前置代码
原型 每个函数对象都有一个prototype
属性, 它默认指向一个Object实例对象(这个对象也被称为: 原型对象)。
1 console .log (typeof Foo .prototype );
普通的实例对象没有prototype
属性,只有__proto__
属性。而函数对象既有prototype
属性,又有__proto__
属性。(具体原因见后文 )。 所以通过下面的代码可知原型对象为实例对象。
1 2 console .log (Foo .prototype .prototype ); console .log (Foo .prototype .__proto__ )
在读取对象的属性或方法时,会自动到原型中查找,所以我们常常将方法放入原型对象当中。(属性应当由实例对象自身保存维护 )
1 2 3 4 5 6 7 8 Foo .prototype .a = 123 ;Foo .prototype .f = function ( ) { console .log ("print function f" ); }let foo = new Foo ();console .log (foo.a ); foo.f ();
默认情况下,原型对象中有一个constructor属性,它指向函数对象本身。
1 2 3 console .log (Foo .prototype .constructor );console .log (Foo .prototype .constructor === Foo ); console .log (Foo .prototype .__proto__ .constructor === Object )
prototype
属性所指向的对象常常被称为显式原型,而__proto__
属性所指向的对象常常被称为隐式原型。 实例对象的隐式原型与对应的函数对象的显式原型指向的对象相同。
1 console .log (Foo .prototype === new Foo ().__proto__ )
Object函数对象的显式原型是原型链的尽头(其类型为object ),因为Object函数对象的显式原型的隐式原型属性值为null。
1 2 console .log (typeof Object .prototype ); console .log (Object .prototype .__proto__ );
所有函数对象的隐式原型所指向的对象均相同,因为function fun_name() {}
<=> fun_name = new Function();
<=> fun_name = function() {}
,即所有函数对象的隐式原型等于Function
对象的显式原型。
1 2 3 4 5 6 7 8 9 10 11 12 function FA ( ) { console .log ("FA" ); }let FB = function ( ) { console .log ("FB" ); }console .log (FA .__proto__ === FB .__proto__ ); console .log (FA .__proto__ === Function .prototype ); console .log (FA .__proto__ .constructor === FB .__proto__ .constructor ) console .log (FA .__proto__ .constructor === Function )
由于Function = new Function()
,故Function的显式原型对象与隐式原型对象相同,类型为function(使用typeof求值的结果为function,但实际上是Object实例对象,因为其隐式原型等于Object函数对象的显式原型 )。 另外,该原型对象为实例对象,因为没有显式原型。
1 2 3 4 5 6 7 console .log (Function .__proto__ === Function .prototype ); console .log (typeof Function .prototype ); console .log (Function .prototype .__proto__ === Object .prototype );console .log (Function .prototype .prototype ); console .log (typeof Function .prototype .__proto__ ); console .log (Function .prototype .__proto__ .__proto__ );
函数的显式原型指向的对象默认是仅带有constructor
属性的Object实例对象(但Object
和Function
不满足,Object.prototype
还有很多方法,而Function.prototype
类型为function)。(关于Function是否是一个例外,请根据上文结合自己的理解,因为Function的显式对象本质上确实属于Object实例对象 )
1 2 3 console .log (typeof Foo .prototype ); console .log (typeof Object .prototype ); console .log (typeof Function .prototype === 'function' );
原型链
访问一个对象的属性/方法时:
先在自身属性中查找,找到返回
如果没有,再沿着__proto__这条链向上查找,找到返回
如果最终没找到,返回undefined
别名: 隐式原型链
作用: 查找对象的属性(方法)
读取/设置属性
读取对象的属性值时: 会自动到原型链中查找
设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
总结 相信有了上面的基础,下面的图示应该一目了然了。
instanceof
instanceof是如何判断的?
表达式:A instanceof B
如果B函数的显式原型对象在A对象的原型链上,返回true,否则返回false。
C.prototype instanceof C // false
1 2 3 console .log (Foo .prototype instanceof Object ); console .log (Object .prototype instanceof Object ); console .log (Function .prototype instanceof Object );
检验 如果对于下面的各个结果没有任何疑惑,那么恭喜你!应该就算是基本掌握了上面所述内容。
1 2 3 4 5 6 7 8 9 10 11 function Foo ( ) {}let f1 = new Foo ();console .log (f1 instanceof Foo ); console .log (f1 instanceof Object ); console .log (Object instanceof Function ); console .log (Object instanceof Object ); console .log (Function instanceof Function ); console .log (Function instanceof Object );