1、面向對象的三大特征:封裝、繼承、多態。
? 封裝:就是將方法封裝在對象中,只給出接口就可以調用,利于維護,避免全局對象污染,
? 繼承:混入式繼承(mix-in),for(var i in),將一個對象繼承給例外一個對象。
原型繼承:利用原型對象中的成員可以被和其相關的對象共享這一特性。
? 多態:父類引用指向子類的對象(javascript中用不到)
2、創建對象的四種方式
? 1)、使用字面量創建對象: var obj = {value:1,name:'hyl'},缺點:用一個創建一個,造成資源浪費
? 2)、使用內置的構造函數創建對象:var obj = new Object();創建了一個空的對象,然后添加成員,obj.name = '1',
? ? ? 缺點:創建的是一個空的對象,還要將對象添加屬性,造成代碼重復。
? 3)、封裝簡單的工廠函數(不推薦使用)
? ? ? function createObj(name,age){
? ? ? ? let obj = {} 或者 obj = new Object();
? ? ? ? obj.name = name;
? ? ? ? obj.age = age;
? ? ? ? return obj;
? ? ? }
? 4)、自定義構造函數
? function 構造函數名{
this.name = name;
....
? }
? 0.構造函數名首字母需要大寫
? 1.構造函數一般和new關鍵字一起使用
? 2.構造函數的返回值默認為新創建的對象,如果手動返回基本數據類型,則不影響返回值,如果返回的是對象(除了null),則新建出來的對象不會返回
取而代之的是return 后面的對象。
? 構造函數(constructor)的執行步驟:
? 1.使用new關鍵字來創建一個對象。
? 2.調用構造函數,將new創建出來的對象賦值給構造函數內的this.
? 3.使用this給新創建出來的對象賦值
? 4.默認返回新創建出來的對象
3、原型
? 構造函數存在的問題:
? 構造函數中的方法,每創建一個對象的時候,該對象都會重新的創建一次這個方法,每個獨享獨占一個方法,
? 但是該方法的內容完全相同,所以造成資源浪費。
? 1.解決方法1
將構造函數的方法,進行提取,放在構造函數的外面,在構造函數內部進行引用賦值。
那么創建出來的對象,都會指向構造函數外面的這個函數,達到共享的效果。
問題:全局變量越來越多,造成全局變量污染,代碼結構混亂,不容易維護。
? 2.解決辦法2
? ? 使用原型
4、原型是什么?
在構造函數創建出來的時候,系統默認會創建一個關聯的對象,這個對象就是原型,原型對象默認為空對象
默認的原型對象中會有一個屬性 constructor指向該構造函數。
5、原型的作用
原型對象中的成員,可以被使用和它關聯的構造函數創建出來的所有對象共享
6、原型對象的使用:
1.使用動態屬性特性,為原型添加成員變量。
2.直接替換原型對象。
注意事項:直接替換原型對象,會導致替換之前創建的對象的原型和替換之后創建的對象的原型不一致。
7、原型的使用注意事項
1.使用對象訪問屬性的時候,會去現在的對象中查找,如果找到了就直接使用,如果未找到,就去原型中找
2.使用對象設置屬性的時候,只會在對象的本身進行查找,不會去原型中查找,如果對象本身中沒有這個屬性,則給該對象新增一個屬性
如果對象中有這個屬性,修改這個屬性。
3.如果在原型對象中有引用類型的屬性,那么使用對象進行修改該屬性內容,則其他所有跟這個原型對象相關的對象都會受到影響,
Person.prototype.car = {}
var p = new Person();
p.car = {}; //這是修改屬性。
p.car.brand = '' //這是修改屬性的內容
let a = p.car //查找,如果自身對象沒有則在原型對象中查找,然后a.brand
4.一般情況下不會將屬性添加到原型對象中
只會講需要共享的方法添加到原型對象中
8、__proto__
1、這個屬性不是標準屬性,所以存在通用性問題。
2.一般不推薦使用
3.調試的時候可以使用
4.這個屬性是原型中的屬性。
9、替換原型的時候注意事項
在新替換的原型中,沒有constructor屬性,會影響三角結構關系的合理性。
so,在新替換的原型中,手動添加constructor屬性,以保證合理性,賦值為關聯的構造函數。
Person.prototype = {
constructor: Person
}