以前说到原型链就只知道通过原型链继承,构造函数和它的实例之间的原型链的关系啊这些东西,最近面试被问得很懵,后来看到一篇文章总结的特别好,当时看明白了,后来面试又忘了一部分,所以今天打算自己总结一下,加深印象。
JS中没有类的概念,万物皆是对象
其他语言中的继承于类,在JS中是 对象继承于对象。所以万物都有__proto__
属性,但是prototype
属性却不是所有对象都有,只有构造函数才有。
例如 使用instanceof
用来测试变量是不是Object类型,除了基本数据类型外,其他的比如函数、数组、键值对对象以及比较特殊的几个构造函数——Number、Array、String、Boolean、Function等,用instanceof Object
结果都是true
。
instanceof
的原理是通过原型链一直查找,找到相同的原型就会返回true
。- 在我们平时使用构造函数实例化对象的过程中,我们知道对象有一个属性叫
__proto__
,这个属性是指向它的构造函数的原型prototype
。
面试中被问到typeof Object
返回什么?
这个回答上来了,是function
,因为Object是对象的构造函数,它是Function的实例,实际上所有的构造函数例如Array、Number都是Function的实例。下面我们通过代码使用上面两条测试来证明:
Object instanceof Function // true
Array instanceof Function //true
Object.__proto__ === Function.prototype // true
Number.__proto__ === Function.prototype // true
所以说Number、Array、String、Boolean
这些构造函数都是Function
的实例,那么Function
也是构造函数,那么Function
是不是 Function 自身的实例呢?
答案是:是的。
Function instanceof Function // true
Function.__proto__ === Function.prototype // true
如上所示,这就是神奇的地方所在了,Function
的对象属性__proto__
指向了它自己的原型prototype
。
到这里我们可以得出几个结论:
- 任何对象都有
__proto__
属性,但是只有函数才有prototype
属性 - 同一个对象的
__proto__
属性和prototype
属性是没有关联的,除了Function
- 对象的
__proto__
属性是用来和其父“类”关联的,构造函数的prototype
是用来和其实例关联的,所以对于同时存在这两个属性的构造函数来说,这两个属性之间是没有什么关系的,也就对应上一条。 - 任何构造函数都是
Function
的实例,任何对象都是Object
的实例 - 任何对象直接调用方法,例如
obj.foo()
,在实例本身没有这个属性的情况下,都是从其__proto__
属性上查找的,也就是从该对象的构造函数的prototype
属性上查找。
这里有一道典型的题目就是考对上面几条的理解,我们都知道Object.prototype.toString
方法可以用来判断数据类型,那么用Object.toString
可以吗。
答案是:不可以。
因为Object.toString
是Object.__proto__.toString
,也就是Function.prototype.toString
,和Object.prototype.toString
根本不是同一个函数。
下面我们通过一张图来描述JS中的原型链。
JS中的原型链
OK,这就是JS中的原型链的样子,都是围绕前面提到的几点进行绘制的。
参考链接
附上之前看的文章的链接:再谈javascriptjs原型与原型链及继承相关问题