本文主要参考了 MDN文档 和 知乎讨论 。
在js中,大部分东西都是对象,数组是对象,函数也是对象,对象更加是对象。 不管我们给数组和函数定义什么内容,它们总是有一些相同的方法和属性 。比如说hasOwnProperty(),toString()等:
这说明一个对象所拥有的属性不仅仅是它本身拥有的属性,它还会从其他对象中继承一些属性。当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类推,这就构成了对象的原型链 。理解js的原型链对使用js的对象非常有帮助。
让我们通过一个例子由浅到深地理解原型链:
这是我们经常使用的创建对象的方式,将共同的方法放到Foo.prototype中,所有实例都共有这个方法了。
这是怎么实现的呢?我们看下面这张图的第一行:
我们定义的show函数在Foo.prototype中,当我们执行f1.show()时,js发现f1本身没有show这个属性,所以它就到f1的原型(也就是__proto__指向的对象)去找,找到了就可以调用。
图片第一行告诉了我们4点:
我们先看看Foo的原型吧!Foo是一个函数,它的构造函数是js内部的function Function(),Function的prototype指向了一个对象Function.prototype,因此Foo的__proto__就指向了Function.prototype,如图。
我们继续深入下去,Function.prototype这个对象,它就是一个普通的对象,它的构造函数是js内置的function Object(),function Object()的prototype指向Object.prototype,因此Function.prototype.__proto__就指向Object.prototype,这个对象中定义了所有对象共有的属性,比如我们之前说的hasOwnProperty()和toString()等。
Object.prototype就是原型链的终点了,它的__proto__是null,js查找属性时,如果到这里还没有找到,那就是undefined了。
到这里就不难理解为什么我们说在js中,函数也是对象了,它就是继承自对象的!
如果如有疑问,欢迎指出!
讲原型和原型链,如果是讲定义,那很是晦涩难懂,今天我们就通俗易懂的说说原型与原型链。还需要借助阮老师的“Javascript继承机制的设计思想”。
1,比如我们还要针对学生统计每个人的总分是多少,我们改造构造函数Person,构造函数上有个 prototype属性,这个属性就是这个构造函数的原型(显式原型),这个原型是函数特有,prototype对象默认有两个属性,constructor属性和__proto__属性。
2,constructor,这个属性包含了一个指针,指回原构造函数。通过控制台输出,我们可以看到我们实例化的对象,有个__proto__属性,这个属性就是隐式原型,这个__proto__是所有对象都有的属性。
3,由于JavaScript的一切都是对象(除undefined),又由于所有对象都有__proto__属性,__proto__又指向构造函数的prototype,当我们访问一个对象的属性时。
4,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样 一直找下去,也就是我们平时所说的原型链的概念。原型链,说明是链式,而不是环,说明有终点,它的终点是null。
对
js中的函数也是对象 (即 (function(){}) instanceof Object == true)
所有的对象都有自己的构筑函数
所有的函数都能当作构筑函数, 每个函数都有一个prototype属性
每个对象都有一个隐藏的o.__proto__属性指向它的构筑函数的prototype
于是所有的函数的原型都是Function.prototype (即 (function(){}).__proto__ === Function.prototype)
访问一个对象的属性时, 如果从这个对象里找不到, 就从obj.__proto__里找, 再找不到就继续从obj.__proto__.__proto__里找, 最终会到达Object.prototype