原型对象的constructor
修改原型对象时,一般要同时修改constructor属性的指向。
// 坏的写法 C.prototype={method1:function(...){...},// ...};
// 好的写法C.prototype={constructor:C,method1:function(...){...},// ...};
// 更好的写法C.prototype.method1=function(...){...};
上面代码中,要么将constructor属性重新指向原来的构造函数,要么只在原型对象上添加方法,这样可以保证instanceof运算符不会失真。
function P() {} P.prototype.constructor === P // true
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
function P() {}
var p = new P();
p.constructor === P // true
p.constructor === P.prototype.constructor // true
p.hasOwnProperty('constructor') // false
p是构造函数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
原型指向数组实例
Rectangle构造函数继承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); // 调用父类构造函数
}
// 另一种写法
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);
// 指定构造函数
S.prototype.constructor = S;
var s = new S();
console.log(s.hello) // 'hello:'
console.log(s.world) // 'world'