先了解一下对象

js中一切皆为对象,但是在这里(原型链中),对象分为两类:

函数对象,包含两种:

  • 由function创造出来的函数:
    1
    2
    3
    4
    function fn(){};//具名函数
    var fn = function(){};//匿名函数
    var fn = new Function();//new Function()对象得到的函数
    //以上这三种都是函数对象
  • 系统内置的函数对象:Function、Object、Array、String、Number,还有正则对象RegExp、Date对象等。

普通对象,除了函数对象之外的,都是普通对象,new Foo()得到的也是普通对象,普通对象是没有prototype(原型对象)属性的,也就没有继承和原型链一说;

再了解一下对象的属性

  • 所有对象都有__proto__属性,用来储存继承得到的属性和方法;
  • 每个函数对象都有prototype(原型对象)属性,用于继承,将其中的属性和方法传递给后代(比如说实例)。

我们来看一下函数对象的原型链:

1
2
3
4
5
6
7
String.__proto__ === Function.prototype;
//true
Object.__proto__ === Function.prototype;
//true
Function.__proto__ === Function.prototype;
//true
//Array、String、Number,还有正则对象RegExp、Date对象等都直接继承自Funtion对象······

可以看出, 一切函数对象(Function、Object、Array、String、Number,还有正则对象RegExp、Date对象等)都直接继承自Funtion对象,Function不仅用于构造函数,还充当了函数对象的构造器,同时也是自己的构造器。

Talk is cheap, show me the code.

我们来验证一下,验证代码很简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function Foo(){
//...
}
var foo = new Foo();
var obj = new Object();

//foo的原型链
console.log(foo.__proto__ === Foo.prototype);//true
console.log(Foo.prototype.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ === null);//true

//Foo的原型链
console.log(Foo.__proto__ === Function.prototype);//true
console.log(Function.prototype.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ === null);//true

//obj的原型链
console.log(obj.__proto__ === Object.prototype);//true
console.log(Object.prototype.__proto__ === null);//true

这三条原型链最后一句都是:Object.prototype.__proto__ === null,最直观的结论就是:一切对象都最终继承自Object对象,Object对象直接继承自根源对象null。

我们接下来分析一下这三条原型链到底是怎么回事。

foo的原型链

  • foo为普通对象,它的构造器是Foo,以Foo为原型,得到原型链第一链:foo.__proto__ === Foo.prototype
  • Foo.prototype这个原型对象为普通对象,它的构造器是Object,以Object为原型,得到原型链第二链:Foo.prototype.__proto__ === Object.prototype
  • Object.prototype这个原型对象以null为原型,得到原型链第三链:Object.prototype.__proto__ === null

Foo的原型链

  • Foo为函数对象,它的构造器是Function,以Function为原型,得到原型链第一条:Foo.__proto__ === Function.prototype
  • Function.prototype这个原型对象是普通对象,它的构造器是Object,以Object为原型,得到原型链第二链:Function.prototype.__proto__ === Object.prototype
  • Object.prototype这个原型对象以null为原型,得到原型链第三链:Object.prototype.__proto__ === null

obj的原型链

  • 这个就很简单了,obj是普通对象,以Object为原型,得到原型链第一链:obj.__proto__ === Object.prototype
  • Object.prototype这个原型对象以null为原型,得到原型链第二链:Object.prototype.__proto__ === null

列出原型链的作用

  • 当js引擎执行对象的属性和方法时,先查找对象上是否存在该属性或方法,不存在则会在对象的原型链上查找;
  • 故foo有Foo、Object的原型方法,而Foo有Function、Object的原型方法;
  • 而foo的原型链没有延伸到Function上,所以foo没有Function的原型方法;
    1
    2
    3
    4
    如:bind是Function上的原型方法,Foo有bind,而foo没有
    Function.bind() => ƒ bind() { [native code] }
    Foo.bind => ƒ bind() { [native code] }
    foo.bind => undefined

总结

找出一个对象的原型链只需两步:

  • 判断这个对象是普通对象还是函数对象,从而得到函数的构造器;
  • 对象.proto === 构造器.prototype。

预埋一个知识点,构造器的原型对象上的constructor属性指回构造器本身。