Created
July 18, 2013 01:38
-
-
Save zhoufenfens/6026065 to your computer and use it in GitHub Desktop.
prototype
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
参考资料: | |
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/ | |
http://www.quora.com/JavaScript/What-is-the-difference-between-__proto__-and-prototype?q=javascript+__proto__+prototype | |
笔记: | |
(1) | |
Object.prototype还有__proto__属性,不过已经是原型链的最后一个环节,并设置为null。 | |
其实ie9以下不支持__proto__形式的访问,则可以用isPrototypeOf( )来替换: | |
function A( ){ } | |
var a=new A( ); | |
alert(A.prototype.isPrototypeOf(a)); // true | |
alert(a.__proto__==A.prototype); // true | |
isPrototypeOf和hasOwnProperty都是从Object.prototype继承而来,后者用来判断属性或方法到底存在于原型还是实例之中。 | |
(2) | |
function A( ){ } | |
var a=new A( ) | |
alert(A.prototype.__proto__==Object.prototype); // true | |
首先a.__proto__指向A.prototype, | |
然后A.prototype是个原型,而原型本身就是对象,所以可以看成Object实例化的对象,于是上面为true | |
最后A.__proto__指向Function.prototype。A是函数,可以看成Function实例化的对象。 | |
所以其实实例对象a通过原型链到达原型顶端,只经历过以下过程: | |
a.___proto__到A.prototype再到Object.prototype,而并没有经过Function.prototype,因为只有A.__proto__才经过它,而非A.prototype。 | |
所以 | |
Function.prototype.m=10设置后,实例对象a并不会拥有该属性,而如果 | |
Object.prototype.m=10设置后,实例对象a则会拥有,这说明原型链根本没经过Function.prototype。 | |
(3) | |
Function与Object发生关系的几种情况: | |
★ Object也是一种函数,所以Function.prototype === Object.__proto__ | |
★ Function.prototype是原型对象,所以是种对象,于是Function.prototype.__proto=Object.prototype | |
注意原型对象本身就是一种对象,所以它的__proto__会指向Object.prototype。 | |
(4) | |
console.log(Function.prototype === Function.__proto__); // true | |
因为Function自己就是函数,所以可以看成是new Function出来的实例 | |
console.log(Object.prototype === Object.__proto__); // false | |
前面应改成Function | |
console.log(Function.prototype === Object.prototype); // false | |
改成:Function.prototype.__proto__=== Object.prototype | |
console.log(Function.prototype === Object.__proto__); // true | |
Object是函数,所以可以看成是new Function出来的实例 | |
console.log(Function.__proto__ === Object.prototype); // false | |
改成:Function.prototype.__proto__=== Object.prototype | |
console.log(Function.__proto__ === Object.__proto__); // true | |
都指向Function.prototype,于是它们之间便间接的指向在一起。。 | |
(4)原型图,比较直观 | |
(5) | |
function A( ){ } | |
var a=new A( ); | |
alert(a instanceof A); | |
alert(a instanceof Object); | |
两个都是true。。。 | |
因为a.__proto__指向A.prototype,而A.prototype.__proto__又指向Object.prototye | |
所以共享了A.prototype.constructor(即A)和Object.prototype.constructor(即Object) | |
于是: | |
function A( ){ } | |
function B( ){ | |
this.fun=function( ){ | |
alert(this instanceof A); | |
alert(this instanceof B); | |
alert(this instanceof Object); | |
} | |
} | |
B.prototype=A.prototype; | |
var bb=new B( ); | |
bb.fun( ); | |
会连续打出三个true。因为bb.__proto__指向B.prototype,也指向B.prototype,还通过更深层次的原型链指向Object.prototype。。都共享了它们的prototype.constructor属性。。也可以: | |
Object.prototype.isPrototypeOf(bb) | |
B.prototype.isPrototypeOf(bb) | |
A.prototype.isPrototypeOf(bb) | |
也即只要原型链上出现过的原型,都是该整条原型链所派生出来实例的原型。 | |
(6) | |
实例化后,再重置原型的值,会切断原来实例出来的对象与新原型之间的联系。。如: | |
function A( ){ } | |
var aa=new A( ); | |
A.prototype={ | |
m:10, | |
n:20 | |
} | |
alert(aa.m); // 值为undefined。 | |
因为aa.__proto__指向A.prototype,所以你A.prototype被重置后,aa.__proto__还是指向以前的老地址。 | |
就好象: | |
var a=[1,2,3]; | |
b=a; | |
a=[3,4,5]; | |
b.push(6) // 这个时候对a已经没了反应,地址都不一样啦。 | |
改成: | |
function A( ){ } | |
A.prototype={ | |
constructor:A, | |
m:10, | |
n:20 | |
} | |
var aa=new A( ); | |
alert(aa.m); // 值为10 | |
是在重置后实例化的,不过这个时候要重新设置下constructor的值,否则指向Object(原型继承的原因)。因为A.prototye.constructor默认有值,被重写后消失,于是要手动设置回来。 | |
(7) | |
function A( ){ | |
this.n=function( ){ } | |
} | |
A.prototype={ | |
m:function( ){ } | |
} | |
var a1=new A( ); | |
var a2=new A( ); | |
alert(a1.m==a2.m) // 结果为true,说明函数是共用的 | |
alert(a1.n==a2.n) // 结果为false,说明各自将函数实例化了一遍,虽然函数内容完全一致,但仍然不同,隶属于不同对象。 | |
(8) | |
function A( ){ } | |
function B( ){ } | |
B.prototype=new A( ); | |
var bb=new B( ); | |
这个时候bb.__proto__就会指向A.prototype,而A.prototype.__proto__又指到Object.prototype,于是完成了整条原型链。。 | |
由于B.prototype=new A( ),也即B.prototype被重写,所以constructor被丢失,于是会去向原型链找该属性,于是A.prototype.constructor就发挥了作用。。 | |
所以bb.constructor既不等于B,也不等于Object,而是等于A。 | |
但是: | |
alert(bb.constructor==B); // false | |
alert(bb.constructor==A); // true | |
alert(bb instanceof(B)); // true | |
这个说明了instanceof有时候没什么意义,反正只要是原型链上出现过的构造函数,它都为true,而constructor属性才会真正反应出原型被重置过这个事实。。如果在A里面还找不到constructor,那就会去Object里找。。 | |
所以: | |
function A( ){ } | |
A.prototype={ | |
m:10, | |
n:20 | |
} | |
var aa=new A( ); | |
alert(aa.constructor); | |
这里实例化以后,又把原型链重置,所以aa的constructor已经不再是A,而是Object。因为aa会通过原来型链最后指到Object.prototype,而这个原型对象刚好有个constructor,便是Object自己。 | |
结论是: | |
alert(aa.constructor=A); // false | |
alert(aa.constructor=Object); // true | |
alert(aa instanceOf Object); // true | |
alert(aa instanceOf A); // true | |
最后这个比较容易迷糊,因为constructor属性被重置掉了(没了,不代表不是,比如某人的爹不在了,不代表那个人不是他爹),但你不能忽视aa是构造函数A实例化出来的对象。而alert(aa instanceOf Object);,说明aa自始至终本质是个对象,所以instanceOf Object是true。 | |
(9) | |
function B( ){ } | |
function A( ){ } | |
A.prototype=new B( ); | |
var a=new A( ); | |
alert(a instanceof A); // true | |
alert(a instanceof B); // true | |
alert(a instanceof Object); // true | |
a.__proto__指到A.prototype,然后A.prototype.__proto__又指到Object.prototype,可以看到只要是原型链上的构造函数,instanceof的话都为true。。 | |
对比: | |
function A( ){ } | |
var a=new A( ); | |
A.prototype={ | |
m:10, | |
n:20 | |
} | |
alert(a instanceof A) // false | |
因为a.__proto__不再指向现在的A.prototype。因为A.prototype指向了新的地方,所以切断了和已经实例化对象的联系。 | |
毕竟a.__proto__指向原型,而A.prototype本来也指向原型,但后来它指到新的地址,于是实例化的对象就跟A.prototye毫无瓜葛。所以A也不再被认为是a的构造函数。 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment