Skip to content

Instantly share code, notes, and snippets.

@zhoufenfens
Created July 18, 2013 01:38
Show Gist options
  • Save zhoufenfens/6026065 to your computer and use it in GitHub Desktop.
Save zhoufenfens/6026065 to your computer and use it in GitHub Desktop.
prototype
参考资料:
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