function Parent() { this.name = 'zhangsan'; this.children = ['A', 'B', 'C']; } Parent.prototype.getName = function() { console.log(this.name); } function Child() { } Child.prototype = new Parent(); var child = new Child(); console.log(child.getName());
[!NOTE]
主要問題:javascript
function Parent(age) { this.names = ['zhangsan', 'lisi']; this.age = age; this.getName = function() { return this.names; } this.getAge = function() { return this.age; } } function Child(age) { Parent.call(this, age); } var child = new Child(18); child.names.push('haha'); console.log(child.names); var child2 = new Child(20); child2.names.push('yaya'); console.log(child2.names);
[!NOTE]
優勢:java
[!DANGER]
缺點:函數
/** * 父類構造函數 * @param name * @constructor */ function Parent(name) { this.name = name; this.colors = ['red', 'green', 'blue']; } Parent.prototype.getName = function() { console.log(this.name); } // child function Child(name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); // 校訂child的構造函數 Child.prototype.constructor = Child; // 建立實例 var child1 = new Child('zhangsan', 18); child1.colors.push('orange'); console.log(child1.name, child1.age, child1.colors); // zhangsan 18 (4) ["red", "green", "blue", "orange"] var child2 = new Child('lisi', 28); console.log(child2.name, child2.age, child2.colors); // lisi 28 (3) ["red", "green", "blue"]
[!NOTE]
優勢: 融合了原型鏈繼承和構造函數的優勢,是Javascript中最經常使用的繼承模式優化
function createObj(o) { function F(){}; // 關鍵:將傳入的對象做爲建立對象的原型 F.prototype = o; return new F(); } // test var person = { name: 'zhangsan', friends: ['lisi', 'wangwu'] } var person1 = createObj(person); var person2 = createObj(person); person1.name = 'wangdachui'; console.log(person1.name, person2.name); // wangdachui, zhangsan person1.friends.push('songxiaobao'); console.log(person2.friends); // lisi wangwu songxiaobao
[!DANGER]
缺點:ui
// 建立一個用於封裝繼承過程的函數,這個函數在內部以某種形式來加強對象 function createObj(o) { var clone = Object.create(o); clone.sayName = function() { console.log('say HelloWorld'); } return clone; }
[!DANGER]
缺點:與借用構造函數模式同樣,每次建立對象都會建立一遍方法this
function Parent(name) { this.name = name; this.colors = ['red', 'green', 'blue']; } Parent.prototype.getName = function() { console.log(this, name); } function Child(name, age) { Parent.call(this, name); this.age = age; } // test1: // 1. 設置子類實例的時候會調用父類的構造函數 Child.prototype = new Parent(); // 2. 建立子類實例的時候也會調用父類的構造函數 var child1 = new Child('zhangsan', 18); // Parent.call(this, name); // 思考:如何減小父類構造函數的調用次數呢? var F = function(){}; F.prototype = Parent.prototype; Child.prototype = new F(); // 思考:下面的這一句話能夠嗎? /* 分析:由於此時Child.prototype和Parent.prototype此時指向的是同一個對象, 所以部分數據至關於此時是共享的(引用)。 好比此時增長 Child.prototype.testProp = 1; 同時會影響 Parent.prototype 的屬性的。 若是不模擬,直接上 es5 的話應該是下面這樣吧 Child.prototype = Object.create(Parent.prototype);*/ Child.prototype = Parent.prototype; // 上面的三句話能夠簡化爲下面的一句話 Child.prototype = Object.create(Parent.prototype); // test2: var child2 = new Child('lisi', 24);
// 自封裝一個繼承的方法 function object(o) { // 下面的三句話實際上就是相似於:var o = Object.create(o.prototype) function F(){}; F.prototype = o.prototype; return new F(); } function prototype(child, parent) { var prototype = object(parent.prototype); // 維護原型對象prototype裏面的constructor屬性 prototype.constructor = child; child.prototype = prototype; } // 調用的時候 prototype(Child, Parent)
var o1 = {name: 'value'}; var o2 = new Object({name: 'value'}); var M = function() {this.name = 'o3'}; var o3 = new M(); var P = {name: 'o4'}; var o4 = Object.create(P)
__proto__
內部屬性,這個屬性所對應的就是該對象的原型__proto__
以外,還預置了 prototype 屬性__proto__
。任何一個實例對象經過原型鏈能夠找到它對應的原型對象,原型對象上面的實例和方法都是實例所共享的。es5
一個對象在查找以一個方法或屬性時,他會先在本身的對象上去找,找不到時,他會沿着原型鏈依次向上查找。prototype
[!NOTE]
注意: 函數纔有prototype,實例對象只有有__proto__, 而函數有的__proto__是由於函數是Function的實例對象指針
[!NOTE]
判斷實例對象的__proto__屬性與構造函數的prototype是否是用一個引用。若是不是,他會沿着對象的__proto__向上查找的,直到頂端Object。code
[!NOTE]
使用對象.construcor
直接可判斷
var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);
// 普通寫法 function Animal() { this.name = 'name' } // ES6 class Animal2 { constructor () { this.name = 'name'; } }