「JavaScript」通俗理解原型&原型链

93 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情

涅槃计划JS篇

原型是 JavaScript 中一座难以逾越的大山,难归难,该越还是得越。


定义

JavaScript 中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript 的对象中都包含了一个 [[Prototype]] 内部属性,这个属性所对应的就是该对象的原型。

prototype

每个函数都有一个 prototype 属性(prototype 是函数才会有的属性),当一个函数被用作构造函数来创建实例时,这个函数的 prototype 属性值会被作为原型赋值给所有对象实例。也就是说,所有实例的原型引用的是函数的 prototype 属性。

栗子

// 创建构造函数 
function Family() {}

// 构造函数原型添加属性
Family.prototype.name = 'xiaoyu';

// 调用构造函数创建实例化对象
var member = new Family();

console.log(member.name) // xiaoyu

构造函数 Familyprototype 属性指向的就是栗子中 member 的原型。

知道了构造函数的原型 prototype,继续往下看

__proto__

所有 object 对象都有一个隐式引用,它被称之为这个对象的 prototype 原型。

image.png

obj 只声明了 namesex 两个属性,在控制台却可以发现它有 __proto__ 属性,这意味着 obj 被隐式地挂载了另一个对象的引用,置于 __proto__ 属性中。

了解了这个属性后继续了解它们的关系

每一个对象的 __proto__ 属性都会指向该对象的原型

function Student() 

var stu = new Student();

console.log(stu.__proto__ === Student.prototype); // true

绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Student.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto__ 时,可以理解成返回了 Object.getPrototypeOf(obj)

constructor

实例对象和构造函数都可以指向原型,但是原型不能指向实例,因为一个构造函数可以生成多个实例。但是原型可以指向构造函数,每个原型都有一个 constructor 属性指向关联的构造函数。

// 所以可以得到
console.log(Family === Family.prototype.constructor); // true

我们知道了构造函数、实例原型、和实例之间的关系。对,我知道了,有什么用?别着急 Look down......

prototype chain 原型链

先分析实例和原型之间的关系,当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。

// 构造函数Person
function Person() {}

Person.prototype.name = 'xiaoyu';

var menber = new Person();

// 给实例添加属性
menber.name = 'niuniu';

console.log(menber.name) // niuniu

image.png

我们给实例对象 menber 添加了 name 属性,打印 menber.name 结果大家都知道是 niuniu

// 删除实例自身属性
delete menber.name;

console.log(menber.name) // xiaoyu

image.png

当我们删除了 menbername 属性时,从 menber 对象中找不到 name 属性就会从 menber 的原型也就是 menber.__proto__Person.prototype) 中查找,然后找到了 name 属性为 xiaoyu

继续打印 menber 看看

image.png

可以看到 menber.[[Prototype]].[[Prototype]] 属性中还有很多其他的方法,那 menber 能调用吗?回答:当然可以,查找机制和查找属性一样。

再展开看看

image.png

可以看到最后的 __proto__ === null 了,或者说 Object.prototype.__proto__ === nullnull 表示“没有对象”,即该处不应该有值,所以也可以理解为 Object.prototype 没有原型,所以查找属性的时候查到 Object.prototype 就可以停止查找了。

image.png