简单理解JavaScript原型链

186 阅读3分钟

这是我参与更文挑战的第17天,活动详情查看: 更文挑战

原型链的目的是为了继承。

继承是什么?继承就是一个对象可以访问被继承的对象的属性和方法

img

代码实现

var A = {
	color:"red"
}
A.color
var B = {}
B.__proto__=A
B.color

image-20210617233333483

在语言设计中,继承有两种形式,一个是基于类的设计,一种是基于原型的设计。显然JavaScript是基于原型的。C++,Java,C#这些是基于类继承的设计模式,这种模式的特点是提供了很多的关键字,比如class、friend、protected、private、interface等,通过这些关键字,来实现继承。引入这么多东西会导致代码复杂和臃肿,设计上也更困难,JavaScript本身不提供class的实现,虽然ES5/ES6引入了class关键字,但是那只是语法糖(就是实际上语言本身没啥新东西,主要是使用和理解更方便了),JavaScript的继承和基于类的继承没有任何关系,自然JavaScript也就不是面向对象语言了

JavaScript 仅仅在对象中引入了一个原型的属性,就实现了语言的继承机制,基于原型的继承省去了很多基于类继承时的繁文缛节,简洁而优美。

每个JavaScript对象都包含了一个隐藏属性__proto__,将这个隐藏属性__proto__叫做该对象的原型(prototype),__proto__指向内存中的另一个对象,就把__proto__指向的对象称为该对象的原型对象,该对象可以访问其原型对象的方法和属性。

例子

当C对象的原型指向B对象,也就是C对象的__proto__属性指向了B对象,那么C对象就可以使用B对象的属性和方法了。如下图

image-20210617212029138

当C对象将他的__proto__属性指向了B对象之后,那么当你通过C对象来访问B对象中的name属性的时候,V8引擎会先从C对象中查找,但是查不到,接下来V8就在C对象的原型对象B中查找,因为B对象中包含了name属性,V8就直接返回B对象中的name属性值,虽然C和B是不同的对象,但是使用上来说,B的属性就像是C的属性。

B对象也有自己的__proto__属性,假如它的__proto__属性指向了内存中的另一块对象A,如下图所示

image-20210617221821980

可以看到A有一个属性是color,那么如果通过C.color访问color属性的时候,V8会先在C对象内部查找,如果依然没有找到,就继续在C对象的原型对象B中去找,如果B中依然没找到,那么就去B的原型对象A中去寻找,因为color在对象A中,V8返回该属性值。name和color看起来都是C对象本身的属性,实际上这些属性都位于原型对象上,这个查找属性的路径就是原型链,就像一个链条一样,把几个原型对象连接在了一起。

代码实现

A = {
    color:"red"
}
B = {
    name:"红色"
}
C = {
    type:"颜色"
}
C.__proto__=B
B.__proto__=A
C.name
C.color

image-20210617233602603

再假设D的__proto__属性也指向了B,那么也就是说D和C共同拥有同一个原型对象,当通过D去访问name属性或者color属性时,返回的值和使用对象C访问name属性和color属性是一样的,因为是同一个数据,都是同一个链条上的。

image-20210617225047772

代码实现

D = {
 age:22
}
D.__proto__=B
D.name
D.color

image-20210617233825897

继承就是一个对象可以访问另一个对象中的属性和方法。在JavaScript中,通过原型和原型链的方式实现了继承的特性。这就是对原型链的简单理解。

参考:time.geekbang.org/column/arti…