分享人:陈皓宇
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
原型链是一种机制,指的是JavaScript每个对象包括原型对象都有一个内置的[[proto]]属性指向创建它的函数对象的原型对象,即prototype属性。 有点绕,别急,后面就懂了
从远古时代说起,网景公司(Netscape)
prototype将JS中的对象都联系起来,而且节省内存;换句话说,JS中这种模式的设计,它的目的就是为了节省内存
我们知道 JS 有对象,比如
var obj = { name: 'obj' }
我们可以对 obj 进行一些操作,包括:
「读」属性
「新增」属性
「更新」属性
「删除」属性
下面我们主要来看一下「读」和「新增」属性。
切到demo
在我们没有对 obj 进行任何其他操作之前,发现 obj 已经有几个属性(方法)了 那么问题来了:valueOf / toString / constructor 是怎么来?我们并没有给 obj.valueOf 赋值呀?
让我们来对js进项重新分类一下,万物皆对象。我们就是造物主,js的世界,我们简单的分成两类:
一、函数对象;
二、普通对象,也就是除了函数对象的所有。
我们发现 console.dir(obj) 打出来的结果是:
1. obj 本身有一个属性 name(这是我们给它加的)
2. obj 还有一个属性叫做 __proto__(它是一个对象)
3. obj.__proto__ 有很多属性,包括 valueOf、toString、constructor 等
4. obj.__proto__ 其实也有一个叫做 __proto__ 的属性(console.log 没有显示),值为 null
现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor 这几个属性?
答案:
这跟 __proto__ 有关。
当我们「读取」 obj.toString 时,JS 引擎会做下面的事情:
1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
2. 看看 obj.__proto__ 对象有没有 toString 属性,发现 obj.__proto__ 有 toString 属性,于是找到了
所以 obj.toString 实际上就是第 2 步中找到的 obj.__proto__.toString。
可以想象,
3. 如果 obj.__proto__ 没有,那么浏览器会继续查看 obj.__proto__.__proto__
4. 如果 obj.__proto__.__proto__ 也没有,那么浏览器会继续查看 obj.__proto__.__proto__.proto__
5. 直到找到 toString 或者 __proto__ 为 null。
这种直男式的搜缩方式,和查找修饰符一样,呈现所谓的链式查找。于是,就有了原型链这个称呼。
那么什么是函数对象呢?构造函数构造出来的对象?不不不,这样想就错了。
看demo,什么是函数对象。
每一个函数对象都拥有一个prototype属性,这个属性指向一个对象,也就是原型对象。
当使用这个构造函数创建实例的时候,prototype属性指向的原型对象就成为实例的原型对象。
原型对象自身也是一个对象,它也有自己的原型对象,这样层层上溯,就形成了一个类似链表的结构,
这就是原型链(prototype chain) 。
当我们访问一个函数的属性时,JS引擎就会遍历整个函数,如果找到了就会返回改属性值,
如果没有找到就会到函数的原型属性中去找,如果还没有找到就会到原型的原型中去找,直到找到这个属性或者搜索到原型链的末尾。
访问对象原型的方法有哪些?
获取实例对象obj的原型对象,有三种方法:
1. obj.__proto__
2. obj.constructor.prototype
3. Object.getPrototypeOf(obj)
上面三种方法之中,前两种都不是很可靠。最新的ES6标准规定,__proto__属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype在手动改变原型对象时,可能会失效。
原型链是如何产生的呢?
引自知乎【写代码的苏打饼】专栏的JavaScript 世界万物诞生记
prototype和__proto__都指向原型对象,
任意一个函数(包括构造函数)都有一个prototype属性,
指向该函数的原型对象,同样任意一个构造函数实例化的对象 ,
都有一个__proto__属性(__proto__并非标准属性,ECMA-262第5版将该属性或指针称为[[Prototype]],
可通过Object.getPrototypeOf()标准方法访问该属性),指向构造函数的原型对象。
By :陈皓宇