继承与原型链

原型链

js中没有类(class),在oop方面只有对象这一种数据结构。每个对象都有个属性指向其原型,而其原型又指向它的原型,一直指向null为止,这便是原型链。

当访问一个对象的属性时,不止会访问这个对象,还会顺着原型链一层一层往上寻找同名的属性,直到找到该属性或者到达原型链的末端为止。

根据 ECMAScript 标准,someObject.[[Prototype]] 符号是用于指派 someObject 的原型。这个等同于 JavaScript 的 __proto__ 属性(现已弃用)。从 ECMAScript 6 开始, [[Prototype]] 可以用Object.getPrototypeOf()Object.setPrototypeOf()访问器来访问。

简而言之, prototype 是用于类型的,而 Object.getPrototypeOf() 是用于实例的(instances),两者功能一致。

总结:

  1. 对象有属性__proto__,指向该对象的构造函数的原型对象

  2. 方法除了有属性__proto__,还有属性prototypeprototype指向该方法的原型对象。原型对象有一个constructor,指向该方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
var A = function() {}
var a = new A() // 喏,a是一个对象,并且是A的实例
console.log(Object.getPrototypeOf(a))
console.log(a.__proto__)
console.log(A.prototype)
/**
* 打印出来的东西都是:
* Object {constructor: function}
* constructor: function A()
* __proto__: Object
* 这是一个对象,它有一个 constructor 属性指向 A()
*/
1
2
3
4
5
6
7
var a = function(){};
var b = new a();
b.__proto__ === a.prototype === a {} // a{}表示a的原型对象
a{}.__proto__ === object // 这个代表 Object() 的原型对象
a{}.__proto__.__proto__ === null // Object() 的原型对象再往上就是 null 了,万物起源
a{}.constructor === a // a 的原型对象的constructor指回 a
a.__proto__ === function // a是一个函数,但它也有__proto__

继承

es6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A {
ma() {}
}
class B extends A {
mb() {}
}
var b = new B()
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
/**
* b.__proto__是 B的原型对象
* 访问b的属性时会先从这里寻找(这里有 ma)
* 当找不到的时候,会继续寻找b.__proto__(这里有mb),直到null
*/