本文最后更新于 2024年6月7日 下午
虽然面试可能凉了,但是还是收获了知识,我还觉得OK~
准备前端的面试绕不开的一个问题就是“对JavaScript的原型链的理解”,我自然也详细了解了一下这个问题,随着问题的深入,我发现虽然之前我了解过原型链的思想,但是很多细节扣的都不够深入,我只是了解了原型链的基本思想,最深处还有宝藏(坑)等待发掘(懵逼)。
ES5
先看一个ES5中对象继承的基本实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var a = function () { this.name = "i am a"; } a.prototype.sayHello = function () { console.log(this.name); }
var b = function () { a.call(this); this.age = "22"; }
b.prototype = Object.create(a.prototype); b.prototype.constructor = b;
|
这样就相当于b继承于a对吧?我们验证一下:
1 2 3 4 5
| var obj_a = new a(); var obj_b = new b();
console.log(obj_b instanceof a);
|
这里提一下instanceof的原理:
就是在对象a的原型链上检查是否有B.prototype
OK! 我们再深入一下,看一下原型链上的关系:
1 2 3 4 5 6
| console.log(Object.getPrototypeOf(obj_b) instanceof a);
console.log(Object.getPrototypeOf(Object.getPrototypeOf(obj_b)) instanceof a);
console.log(Object.getPrototypeOf(Object.getPrototypeOf(obj_b)) === a.prototype);
|
也就是下图所示:

但是仅仅这样就算完了吗?那和之前的理解没啥区别啊。我们再继续深入一下:
1 2 3 4 5
| console.log(Object.getPrototypeOf(a.prototype) == Object.prototype)
console.log(Object.getPrototypeOf(Object.prototype) === null);
|
我们知道类a不继承于其他类了,那么a的原型对象作为一个对象,它一定是由Object函数生成的,那么它的原型对象就是Object.prototype。
Object.prototype的原型对象的比较特殊是null。

下面开始逐渐令人迷惑了:
我们知道a()、b()甚至是Object()他们都是一个函数,那么函数也是一个对象,既然这样他们也是有原型的,也会拥有一条原型链,那么它的原型对象是是谁呢?
也许直接思考原型对象不太好得出结论,我们换一个角度,它的构造函数是谁?我们知道有这样一个函数:Fucntion()。可以用它生成任意的函数对象:
1 2 3 4
| console.log(Object.getPrototypeOf(a).constructor===Function)
console.log(Object.getPrototypeOf(a)===Function.prortotype)
|
那既然a()作为一个函数它可以使上文的式子成立,那么Function本身作为一个函数的构造函数,它也是一个函数啊,那么上面的式子按理说也可以成立啊。
1 2
| console.log(Object.getPrototypeOf(Function).constructor === Function)
|
对于这个迷惑的操作,可以理解为Function可以构造任何函数,Function作为一个函数,当然可以自己构造自己。
既然上面的式子成立,自然下面的式子也可以成立:
1 2
| console.log(Object.getPrototypeOf(Function) === Function.prototype)
|

那么Object()作为一个函数,自然也可以使上文中提到的式子成立:
1 2 3 4
| console.log(Object.getPrototypeOf(Object) === Function.prototype)
console.log(Object.getPrototypeOf(Object).constructor === Function)
|
同时Function.prototype作为一个对象,那么它的原型对象也就是Object的原型对象。
1 2
| console.log(Object.getPrototypeOf(Function.prototype) ===Object.prototype)
|

大功告成!
ES6
在ES6中引入了class这一用法,它其实是一个语法糖,与ES5中的对象用法大同小异。唯一有些不同的地方在于:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class a { name = "a"; sayHello() { console.log(this.name); } } class b extends a { age = "22"; }
var obj_a = new a(); var obj_b = new b();
console.log(Object.getPrototypeOf(b)===a);
console.log(Object.getPrototypeOf(b.prototype)===a.prototype)
|
也就是说这时,b()作为一个函数,它的原型对象是a()。
