原型对象和原型链

首先明确一点的是,原型和原型链是针对对象的。

原型

__proto__ 是所有原型对象或对象实例自带的隐式属性,该属性指向它的原型对象。最终所有对象的原型对象为 objectobject__proto__指向 null

原型对象和对象实例不同,对象实例可以自己通过原型对象进行创建,而原型对象是JS的对象类型。

prototype是所有函数在定义时自动创建的对象。在通过原型对象创建对象实例时,原型对象的构造函数拥有一个 prototype 对象,这个 prototype 对象则为该原型对象。

举例:

1
var a = new String("abc");

a为 String 的实例,它有一个 a.__proto__属性指向它的原型对象,那么它的原型对象要怎么得知呢?通过a创建时的构造函数 String(),这个构造函数是原型对象的构造函数,它自带一个 String.prototype对象,这个对象就是原型对象 String

在这个语句执行时,完成 a.__proto__ = String.prototype 的赋值,这样就可以得知对象实例a的原型对象为 String了。

对于自定义函数prototype对象,这个对象会拥有一个 __proto__ 属性。这个 __proto__ 属性指向它的构造函数的prototype对象 (此时完成了一个循环有没有…我觉得这就是原型之所以很绕的原因)

1
2
3
function a(){
/*code*/
};

那么自定义函数aprototype对象的构造函数是谁呢?

在这个语句执行时,完成a.prototype.__proto__ = Object.prototype的赋值。

也就是说,函数的原型对象为 Object

JavaScript中所有的对象(函数也是对象)都是Object的实例,并继承Object.prototype的属性和方法。

constructor属性

a.__proto__ = String.prototype = String

String.prototype.constructor = String

原型对象和原型链-constructor属性

JS new一个对象的过程

1
2
3
4
function Mother(args){
/*code*/
}
var son = new Mother(args);

1.创建新对象

var son = new Mother(args);

2.新对象执行[[prototype]]连接

son.__proto__ = Mother.prototype

Mother作为一个自定义函数,有Mother.prototype.__proto__ = Object.prototype

3.新对象和函数调用的this绑定

相当于执行 Mother.call(son, args)

4.执行构造函数中的代码

5.如果函数没有返回值,那么会自动返回这个新对象,son获得返回值,即经过构造函数处理后的新对象。

原型链

在上例new一个对象的过程中,存在原型链:

son.__proto__ = Mother.prototype

Mother.prototype.__proto__ = Object.prototype

即:

son.__proto__.proto__ = Object.prototype

应用

判断一个对象是否为数组:

  1. 使用 instanceof 操作符
1
2
var arr = [];
console.log(arr instanceof Array); //true

通过查找左操作数 arr 的原型链上是否有右操作数 Array 构造函数的原型对象

arr.__proto__ = Array.prototype

  1. Array.isArray()