JS原型链
About 2 min
前言
思考以下几个问题:
- 原型链是什么概念, JS 中为何要引入原型链?
- 原型链是怎样实现继承的?
- 构造函数 constructor,proto,ES6 中 class、static、super 和原型链的关系?
- 如何利用原型链来解释 this 的指向问题?
- 原型链与区块链?
看下面这段代码的打印结果
function Foo() {
return this;
}
Foo.getName = function() {
console.log("1");
};
Foo.prototype.getName = function() {
console.log("2");
};
new Foo.getName(); // -> 1 等价于new (Foo.getName()) 调用的是构造函数Foo本身的getName方法
new Foo().getName(); // -> 2 等价于(new Foo()).getName() 调用的是实例上(原型上)的getName方法
理解原型链的链
对象的三种创建方式
字面量形式创建
let o1 = { a: "aaa" }; let o2 = new Object({ a: "aaa" }); console.log(o1, o2);
通过构造函数创建
let M = function(a) { this.a = a; }; let o3 = new M("aaa"); console.log(o3);
通过 Ojbect.create 创建
let P = { a: "aaa" }; let o4 = Object.create(P); console.log(o4);
构造函数/原型/实例对象
上例中的let M = function(a) {this.a = a;}
M 就是一个构造函数;构造函数拥有prototype
属性,其指向原型对象,原型对象拥有constructor
属性指向该构造函数;通过o3 = new M('aaa');
即创建了 o3 这个实例对象,实例对象的__proto__
指向构造函数的prototype
也就是原型对象;
对象拥有__proto__
属性,指向原型对象,而构造函数也是对象(准确来说是Function
的实例对象),故上述构造函数 M 拥有__proto__
属性,因此这里就产生了一个类似这样的链条
待补充
原型链如何产生
o3.proto => M.prototype => M.proto => Function.prototype => Object.prototype
instanceof
可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的prototype
。
instanceof
一个instanceof
的具体实现方式
function instanceof(left, right) {
// 获得类型的原型
let prototype = right.prototype
// 获得对象的原型
left = left.__proto__
// 判断对象的类型是否等于类型的原型
while (true) {
if (left === null)
return false
if (prototype === left)
return true
left = left.__proto__
}
}
简单来说: 原型链的链大概就是反映在这里left = left.__proto__
的这种连式结构。
this 的指向问题
function foo() {
console.log(this.a);
}
var a = 2;
foo();
var obj = {
a: 2,
foo: foo
};
obj.foo();
// 以上两者情况 `this` 只依赖于调用函数前的对象,优先级是第二个情况大于第一个情况
// 以下情况是优先级最高的,`this` 只会绑定在 `c` 上,不会被任何方式修改 `this` 指向
var c = new foo();
c.a = 3;
console.log(c.a);
// 还有种就是利用 call,apply,bind 改变 this,这个优先级仅次于 new
待补充
通过原型链来解释 this 的指向问题