一、内部属性 [[prototype]]
JavaScript 没有类的概念,它的“继承”基于对象的内部属性 [[prototype]]
,它是一个内部引用,它的值是引用类型值。
ES6 中 class
语法是一种误导,它只是封装在 [[prototype]]
上的一个语法糖,它的行为像类,但又不同。
JavaScript 中的原型链就是靠内部属性 [[prototype]]
关联起来的。关联的逻辑如下:
- 当访问一个对象的属性时,如果当前对象中不存在,就会在当前对象的内部属性
[[prototype]]
所指向的对象上进行查找,假设是obj.__proto__
。 - 查找到,但立即返回该属性值。
- 没有查找到,就在当前对象的内部属性
[[prototype]]
所指向的对象上进行查找,就是obj.__proto__.__proto__
,以此类推。查找的终点对象就是Object.prototype
。
我们把这个查找过程,叫“在原型链上逐级向上查找”。
取得对象的内部属性 [[prototype]]
,可以使用对象的非标准属性 __proto__
,ES5 提供了一个标准方法 Object.getPrototypeOf()
,可以达到同样目的。
二、以构造的形式调用函数
JavaScript 中没有构造函数的概念,只有“以构造的形式调用的函数”。调用函数时,前面加 new
就说这个函数,是以构造的形式调用的函数。
function Foo() { }
new Foo(); // 以构造的形式调用的函数
当一个函数以构造的形式调用的时候,与普通的函数调用方式有以下的区别:
- 创建、返回一个新对象。
- 函数中的
this
引用指向这个新对象。 - 新对象的内部
[[prototype]]
链指向函数的原型对象((new Foo()).__proto__ === Foo.prototype
值为true
)。
function Foo(info) {
this.info = info;
}
var f1 = new Foo('info1');
var f2 = new Foo('info2');
f1 === f2 // false;
f1.info // info1
f2.info // info2
f1.__proto__ === f2.__proto__ // true
f1.__proto__ === Foo.prototype // true
f1.__proto__.constructor === Foo // true
{注意} 函数的原型对象有一个属性
constructor
,指向函数本身,就是说(new Foo()).__proto__.constructor === Foo
值为true
。
三、寄生组合式继承
这是最常选择的继承方式。
function inheritPrototype(subType, superType) {
subType.prototype = Object.create(superType.prototype);
subType.prototype.constructor = subType;
}
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info('Shape moved.');
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
inheritPrototype(Rectangle, Shape);
var rect = new Rectangle();
console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 1); // 打印 'Shape moved.'
rect
对象有两个实例属性 x
和 y
。rect.__proto__
指向 Rectangle.prototype
,rect.__proto__.constructor
指向 Rectangle
(手动赋予的);Rectangle.prototype.__proto__
指向 Shape.prototype
,Shape.prototype.constructor
指向 Shape
。
四、参考链接
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
(完)