对于JavaScript原型链的理解
问题的提出:
在初学原型的时候,几句代码的执行结果让我很不解:
typeof Object; // function
typeof Function; // function
typeof Object.__proto__; // function
typeof Object.prototype; // Object
typeof Function.__proto__; // function
typeof Function.prototype; // function
基础知识:
在搞清楚上述代码之前,需要明白几点JavaScript的基础知识:
- JavaScript中,一切皆是对象;
- 对象是由函数创建的;
- 一切函数都是Function的实例
- Object对象是一个函数,所有的对象都是Object对象的实例,即所有的对象都继承自Object的原型对象;
对于三个属性的理解:
清楚了上述的基础知识之后,我们现在来理解一下原型链中关键的三个属性:prototype
、__proto__
、constructor
。
首先给出函数创建对象时,三个属性的指向图:(红箭头标识指针的指向):
遵循ECMAScript标准,someObject.[[Prototype]]
符号是用于指向 someObject
的原型。从 ECMAScript 6 开始,[[Prototype]]
可以通过 Object.getPrototypeOf()
和 Object.setPrototypeOf()
访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__
。
-
prototype
:每个函数都有一个prototype属性,这个属性是个指针,指向一个对象。该对象(原型对象)的用途是包含可以由特定类型的所有实例共享的属性和方法。其中,“特定类型的所有实例”就是由该函数作为构造函数创建的所有实例对象。
-
__proto__
:即上图中的[[Prototype]],是每个对象都有的属性,用于指向该对象的原型,由
__proto__
可以构成一条原型链。 -
constructor
:在我的理解中,
construtor
对于不同的对象有不同的含义:-
对于一般对象,即我们使用构造函数创造的对象,
constructor
表示该对象的构造函数,如:function Foo() {} let foo = new Foo(); console.log(foo.constructor); // Foo() {} let a = {}; // 相当于 let a = new Object(); console.log(a.constructor); // Object() { [native code] } let b = []; // 相当于 let b = new Array(); console.log(b.constructor); // Array() { [native code] } function c() {} // 相当于 let c = new Function(); console.log(c.constructor); // Function() { [native code] }
-
对于函数所对应的原型对象(
f.prototype
),constructor
表示该原型对象对应的函数,如:function Foo() {} console.log(Foo.prototype.constructor); // Foo() {} // 用`instanceof`检测某对象是否是某函数的实例 console.log(Foo.prototype instanceof Foo); // false console.log(Foo.prototype instanceof Object); // true
为什么构造函数的实例化对象和原型对象的constructor都指向该构造函数?
因为constructor是原型对象的固有属性,在被创建之初就指向它的函数,调用实例化对象的constructor时,会在原型链上一直寻找constructor属性,直到在原型对象上找到。
-
总结:
- 在JavaScript中,只有
Object.prototype
没有原型(null
); - 对于对象中的属性,js会沿着原型链向上查找,直到找到该属性或到达
Object.prototype
才停止;处在原型链下层的属性被找到后,js就停止寻找,使得处在原型链上层的同名属性无法被访问,这种情况被称为"属性遮蔽 (property shadowing)"; Object
、String
、Number
、Boolean
、Array
、Function
这些构造函数的constructor
都是Function
;
一切皆是对象
对象都是由函数创造的