先了解一下对象
js中一切皆为对象,但是在这里(原型链中),对象分为两类:
函数对象,包含两种:
由function创造出来的函数:
1
2
3
4function fn(){};//具名函数
var fn = function(){};//匿名函数
var fn = new Function();//new Function()对象得到的函数
//以上这三种都是函数对象系统内置的函数对象:Function、Object、Array、String、Number,还有正则对象RegExp、Date对象等。
普通对象,除了函数对象之外的,都是普通对象,new Foo()
得到的也是普通对象,普通对象是没有prototype
(原型对象)属性的,也就没有继承和原型链一说;
再了解一下对象的属性
- 所有对象都有
__proto__
属性,用来储存继承得到的属性和方法; - 每个函数对象都有
prototype
(原型对象)属性,用于继承,将其中的属性和方法传递给后代(比如说实例)。
我们来看一下函数对象的原型链:
1 | String.__proto__ === Function.prototype; |
可以看出, 一切函数对象(Function、Object、Array、String、Number,还有正则对象RegExp、Date对象等)都直接继承自Funtion对象,Function不仅用于构造函数,还充当了函数对象的构造器,同时也是自己的构造器。
Talk is cheap, show me the code.
我们来验证一下,验证代码很简单。
1 | function Foo(){ |
这三条原型链最后一句都是: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属性指回构造器本身。