最易理解的原型和原型链

2018-09-10  本文已影响0人  饥人谷_朱笑笑啊

一、什么是原型和原型链

我们先来看一个简单的例子,首先我们定义一个Number()函数
var n1 = new Number(1)
这个时候我们就可以调用Number()函数的各种方法了,比如 toString()
n1.toString()

我们知道基本类型对象是存在栈内存中的;复杂类型对象存在堆内存中,栈内存中只存其地址(指针)
所以此时 n1 如果要调用 toString() 方法的话,必须有一个指针能指向这个对象。那么 toString() 这个方法存在哪里比较好呢,最基本的想法当然是存在 Number() 函数中好了

这样调用当然不会有什么问题,但是如果此时我们再来一个
var n2 = new Number(2)
同是也调用 n2 的toString()方法
n2.toString

那此时我们就发现有一个问题,n1 和 n2 都有一个toString() 方法,如果在栈内存中各自存储一个toString() 的方法的话,很明显比较浪费,当数据量变大时就会明显影响性能。

所以,我们是不是能将toString() 这类大家都有可能会用到的方法打包放在一个对象内,然后在Number() 函数放一个指针不就好了,那就给这个指针取个名字吧,就叫__proto__


从图中我们可以看到,Number(1) 中的有一个预设属性__proto__,里面包含了 toString() 在内的好几个有关数值的方法。
那无关数值的方法,有关对象的方法呢hasOwnProperty(),眼尖同学已经发现了,在Number() 的__proto__中还有一个__proto__: Object,就像你所看到的一样,这里指向的就是对象的通用方法。 又到了需要取名字的时候了,这些通用的方法得存在栈内寸中,Number() 的那就叫Number.prototype 吧

这里我们就你能看到n2.__proto__Number.prototype是一样的,证明n2.__proto__指向的就是Number.prototype


同理:n2.__proto__.__proto__ === Object.prototype也是true

这里我们就能推广得到一个比较通用的法则 对象.__proto__ = 函数.prototype
例如:

String.__proto__ === Function.prototype \\true
Number.__proto__ === Function.prototype \\true
Function.__proto__.__proto__ === Object.prototype  \\true

这个时候需要给这整个做法取个名字了,由于这些个公用属性一个指向一个,要是画出箭头指针,就像链子一样,那就要原型链吧。这些指向的最后就是null。

Object.prototype.__proto__ === null //true

二、原型链解决了什么问题

我们要说到一个新词继承,依旧是 var n2 = new Number(2),我们没有定义n2任何的属性和方法,但是它却能够通过原型链调用Number.prototype、甚至是Object.prototype 中的属性和方法,这就是n2 继承了符合它本身数据类型的公用属性。
所以当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

上一篇 下一篇

猜你喜欢

热点阅读