原型對象的constructor
修改原型對象時摔桦,一般要同時修改constructor屬性的指向蟋字。
// 壞的寫法 C.prototype={method1:function(...){...},// ...};
// 好的寫法C.prototype={constructor:C,method1:function(...){...},// ...};
// 更好的寫法C.prototype.method1=function(...){...};
上面代碼中,要么將constructor屬性重新指向原來的構(gòu)造函數(shù),要么只在原型對象上添加方法,這樣可以保證instanceof運算符不會失真。
function P() {} P.prototype.constructor === P // true
prototype對象有一個constructor屬性挠阁,默認指向prototype對象所在的構(gòu)造函數(shù)。
function P() {}
var p = new P();
p.constructor === P // true
p.constructor === P.prototype.constructor // true
p.hasOwnProperty('constructor') // false
p是構(gòu)造函數(shù)P的實例對象溯饵,但是p自身沒有constructor屬性侵俗,該屬性其實是讀取原型鏈上面的P.prototype.constructor屬性。
原型鏈
Object.getPrototypeOf(Object.prototype) // null
原型鏈的盡頭就是null
var MyArray = function () {};
MyArray.prototype = new Array();
MyArray.prototype.constructor = MyArray;
var mine = new MyArray();
mine.push(1, 2, 3);
mine.length // 3
mine instanceof Array // true
原型指向數(shù)組實例
Rectangle構(gòu)造函數(shù)繼承Shape
function Shape() {
? this.x = 0;
? this.y = 0;
}
Shape.prototype.move = function (x, y) {
? this.x += x;
? this.y += y;
? console.info('Shape moved.');
};
// 第一步瓣喊,子類繼承父類的實例
function Rectangle() {
? Shape.call(this); // 調(diào)用父類構(gòu)造函數(shù)
}
// 另一種寫法
function Rectangle() {
? this.base = Shape;
? this.base();
}
// 第二步坡慌,子類繼承父類的原型
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
一個對象同時繼承多個對象
function M1() {
? this.hello = 'hello';
}
function M2() {
? this.world = 'world';
}
function S() {
? M1.call(this);
? M2.call(this);
}
// 繼承 M1
S.prototype = Object.create(M1.prototype);
// 繼承鏈上加入 M2
Object.assign(S.prototype, M2.prototype);
// 指定構(gòu)造函數(shù)
S.prototype.constructor = S;
var s = new S();
console.log(s.hello) // 'hello:'
console.log(s.world) // 'world'