JavaScript 原型链
2018-04-05
一个原型链
- 通过 构造函数A 创建的实例A-instance的
[[proto]]
属性会自动指向 构造函数A的原型对象prototype
,这种关系是在实例被创建时便自动创建的。 - 而我们的 构造函数A 的原型对象
prototype
本身就是一个Object
的实例。
JavaScript动态特性的副作用
1 | function car(){ |
当我们创建实例carA时,原型链的状态
当我们在 line 1修改了构造函数car的原型, 再创建实例carB时原型链的样子。
- 当我们对构造函数car原型上的属性和方法进行删改时, car的所有实例都可以访问新的方法或属性。
- 当我们完全更换构造函数car的原型时(如line1), 之前创建的car的实例会保留旧的原型的引用, 而在更换完原型之后通过构造函数创建的实例将会保留新的原型的引用。对新的原型上的属性的删改在旧的实例(保留旧的原型的引用的实例)上无法体现。
通过instanceof
判断实例类型
1 | function Car(){}; |
用法:
object instanceof constructor
- 原理:
instanceof
通过判断构造函数constructor
的prototype
是否在object
的原型链上。即检测右边函数原型是否在左侧对象的原型链上。
- 原理:
line 2 之前
- line2 改变构造函数
Car
的原型之后原型链的样子
- 如图所示, 显然构造函数
Car
的原型是不在CarA
的原型链上的 - 同时我们还发现, 尽管我们在 line 2 重新定义了构造函数
Car
的原型, 但是新定义的原型对象并没有consturctor
属性, 而原来的原型对象的constructor
属性仍然指向构造函数Car
。 这就会产生如下问题:
1
2console.log(carA.constructor === Car);// output:true
console.log(carA instanceof Car); // output:false而通过原型链实现继承时, 也会出现类似的问题:
1
2
3
4
5
6
7
8
9
10function Car(){}
function miniCar(){}
miniCar.prototype = new Car();// line 1
let miniA = new miniCar();
console.log( miniA.constructor === miniCar); // false
console.log( miniA instanceof miniCar); //true
console.log( miniA.constructor); //Car原型继承的图示
- 由于javascript 的垃圾回收机制, 实际情况应是如下图所示
- 为了解决上述问题, 我们应该在上述代码 line1 之后设置新原型的
constructor
属性
1 | function Car(){} |
- 由此我们也通过JavaScript实现了原型继承
1
2
3
4
5
6
7
8
9
10function SuperClass(){};
function SubClass(){};
SubClass.prototype = new SuperClass();
Object.defineProperty(SubClass.prototype, 'constructor', {
enumerable: false,
value: SubClass,
writable: true
})
let instance = new SubClass();
ES6 Class
- 由于ES5实现原型继承的过程繁琐复杂, ES6引入
class
语法糖, 来模拟类继承。 但其底层仍然是基于原型的实现。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41// before ES6
function Car(name){ //构造函数
this.name;
}
Car.showName = function(car){//静态方法
return car.name;
}
Car.prototype.run = function(){ //原型方法
return true;
}
function miniCar(){};
miniCar.prototype = new Car('BMW');
Object.defineProperty(SubClass.prototype, 'constructor', {
eumerable: false,
value:SubClass,
writable: true,
})
// after ES6
class Car {
constructor(name){ // 构造函数
this.name;
}
// 静态方法
static showName(car){
return car.name;
}
// 如下为原型方法
run(){
return true;
}
}
// 通过 extends 关键字来实现继承。
class miniCar extends Car{
//...
}