原型链
□ JS 中,每个对象(包括内部对象、宿主对象、自定义对象,以及原始类型值自动转成的包装对象)都有一个[[Prototype]]
内部属性,为了表示特性是内部值,用两个方括号加以区分。当访问一个对象的属性时,如果这个属性不存在,则会去对象的[[Prototype]]
中找这个属性,而这个[[Prototype]]
的取值也可以是个对象并也拥有[[Prototype]]
属性,可以继续在其中查找属性,此机制称为原型链(prototype chain)。
□ Firefox、Safari、Chrome 目前都支持通过__proto__属性得到[[Prototype]]
的取值,此非标准方式不被推荐于生产环境,标准方式是通过调用函数 Object.getPrototypeOf() 得到。
□ 要讨论[[Prototype]]
属性的取值,需要先提到prototype属性 ↓。
prototype 和 constructor
● JS 中,每个函数不仅有[[Prototype]]
属性,还都有一个 prototype 属性。
● prototype 属性的取值
(1)取值通常是个对象,此对象不仅有[[Prototype]]
属性,还有一个 constructor 属性,constructor 的默认值是这个函数本身。
(2)取值的特殊情况:Function.prototype 的取值实际也是个对象,它也有[[Prototype]]
属性,也有 constructor 属性且默认值依然是 Function 函数本身但它不能作为构造函数使用,但没有 prototype 属性(即 Function.prototype.prototype === undefined)。这个对象还特殊在它也具有函数类型的特征(如下图),这一点官方给的原因是对早期版本的兼容。
Function.prototype的特殊取值
[[Prototype]] 属性的取值
◆[[Prototype]]
属性的取值通常是其所属类型的 prototype 属性值。
(1)本地对象类型(如 Array、Object、Date、Function)的[[Prototype]]
取值都是 Function.prototype 的值。
(2)对于通过 new 构造出来的自定义对象,其所属类型就是对应的自定义类,所以其[[Prototype]]
的值就是自定义类的构造函数的 prototype 属性值。
◆ 取值的特殊情况:
(1)Object.prototype.__proto__ 的值是 null,它是原型链在[[Prototype]]
属性上的终点。
(2)通过 Object.create()创建的对象,其__proto__值由传入参数决定。
1 2 3 4
| var oneObj = Object.create({a:1}); console.log(oneObj.__proto__); // {a:1} oneObj = Object.create(null); console.log(oneObj.__proto__); // 打印undefined 而不是null
|
理解实例
♂ 理解实例 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| var A= 19; console.log(A.__proto__);//打印Number.prototype的值,见下图1 console.log(A.__proto__ === Number.prototype);//打印true
var B= {}; console.log(B.__proto__ === Object.prototype);//打印true
console.log(Array.prototype.__proto__ === Object.prototype);//打印true console.log(Object.prototype.__proto__ === Object.prototype);//打印false console.log(Object.prototype.__proto__);//打印null
console.log(Array.__proto__ === Function.prototype);//打印true console.log(Object.__proto__ === Function.prototype);//打印true console.log(Function.__proto__ === Function.prototype);//打印true
function C() { console.log("I am cc"); } console.log(C.__proto__===Function.prototype);//打印true
|
图1 A的__proto__属性值
♂ 理解实例 2
1 2 3 4 5 6 7
| var Person = function () { };
var Programmer = function () { }; Programmer.prototype = new Person();
var p = new Programmer(); console.log(p.__proto__.__proto__ === Person.prototype); // 打印true
|
♂ 理解实例 3
1 2 3 4 5 6 7 8 9
| function foo(){ return 0; } console.log(foo.prototype); //打印一个对象,对象值包含两个属性:consoturctor与__proto__,如下图2
console.log(foo.prototype.constructor===foo);//打印true console.log(foo.prototype.__proto__===Object.prototype)//打印true console.log(foo.prototype.constructor.__proto__===Function.prototype);//打印true
|
图2 foo的prototype属性的取值
new
○ JS 中 new 的过程分为以下三步(以语句“var obj= new Base()”为例):
(1)var obj={}; //创建空对象。
(2)obj 的[[Prototype]]
属性赋值为 Base.prototype。
(3)Base.call(obj); // 以 obj 作为上下文调用 Base 函数(即 Base 类的构造函数)
instanceof
★ “A instanceof B”用于判断 A 是否是 B 的实例,运算过程:首先确定 A 不是原始类型字面值(原始类型字面值的 instanceof 运算结果都是 false),然后判断 B 的 prototype 属性是否处于 A 的原型链上。
★ 实例理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| Object instanceof Object; //true /*解析:Object.__proto__===Function.prototype, 而Function.prototype.__proto__===Object.prototype, 因此Object.prototype在Object的原型链上*/
Function instanceof Function; //true /*解析:Function.__proto__===Function.prototype, 因此Function.prototype在Function的原型链上*/
Function instanceof Object; //true /*解析:Function.__proto__===Function.prototype, 而Function.prototype.__proto__===Object.prototype, 因此Object.prototype在Function的原型链上*/
String instanceof String; //false /*解析:String.__proto__===Function.protype, 而Function.prototype.__proto__===Object.prototype, 然后Object.prototype.__proto__===null, 因此String.prototype不在String的原型链上*/
var oneNumber= 19; oneNumber instanceof Number; //false oneNumber instanceof Object; //false /*解析:虽然oneNumber.__proto__===Number.prototype, 但是原始类型字面值的instanceof返回都是false */
Number.MAX_VALUE instanceof Number; //false NaN instanceof Number; //false var oneString= "Haha"; oneString instanceof String; //false /*解析:以上都是原始类型字面值*/
[2,3] instanceof Array; //true ({a:2}) instanceof Object; //true /*解析:非原始类型的字面值*/
|