原型链在js中是比较重要的一个知识点,js本身就是基于原型的,非常有必要理解js的原型链与继承相关知识。

基于原型链的继承

js对象都会有一个指向一个原型对象的链,在试图访问对象的属性时,不仅仅会在对象本身上寻找,还会在该对象的原型链上继续往上寻找,一直找到匹配的属性或者到达原型链的末端。

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
const a = function () {
this.fi = 1
this.se = 2
}

a.prototype.se = 2.1
a.prototype.th = 3

const b = new a()
// b通过a构造生成,b的原型链便指向了构造函数a的原型对象
// 即 b.__proto__ === a.prototype

console.log(b.se) // 2
// 在实例对象b中寻找属性th,先在b自身中寻找

console.log(b.th) // 3
// 在实例对象b中寻找属性th,先在b自身中寻找
// 在b中找寻不到便到b的原型链中寻找,即a.prototype

console.log(b.un) // undefined
// 在实例对象b中寻找属性th,先在b自身中寻找
// 在b中找寻不到便到b的原型链中寻找,即a.prototype
// 在a.prototype中寻找不到便继续往原型链上找
// 而a.prototype.__proto__ === Object.prototype
// 在Object.prototype中还找不到,继续
// 而Object.prototype.__proto__ === null
// 到这便是原型链的末尾,于是整个原型链如下:
// { fi:1, se: 2 } --> { se: 2.1, th: 3 } --> Object.prototype --> null

js便是这样通过原型链来实现继承的,如果在实例对象obj中找不到属性,便在obj.proto__中寻找,找不到继续在obj.__proto.__proto__里寻找,一直到原型链末端null便没有下一个__proto__了,没找到就返回undefined

__proto__不是js标准里的,不用这个属性的好。在ECMAScript标准中是obj.[[Prototype]],从ES6开始使用Object.getPrototypeOf()和Object.setPrototypeOf()来访问修改[[Prototype]]。

在遍历对象属性的时候如果不想遍历原型链,可以使用Object实例对象的hasOwnProperty方法,或者Object.keys()