原型链

□ 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
/*解析:非原始类型的字面值*/