JavaScript中__proto__与prototype

JavaScript中__proto__与prototype


by:jianwei

测试环境:Google Chrome 36.0.1985.125

如有不足,欢迎指正。


闲话少说,先上图。 




__proto__:对象的原型,JavaScript中每个对象都有一个__proto__属性,用于基于原型链的继承机制,当访问一个对象的属性时,会现在自身属性中查找,如果未找到,则会通过__proto__到原型链中去查找,如果自身属性中找到,则不会继续在原型链中查找该属性。


prototype:函数的原型,利用new foo()的方式创建对象时,会将函数的prototype赋值给所创建对象的__proto__。

简言之,JavaScript中所有对象都有__proto__属性,prototype是function对象所独有。


如上图所示,对照上图来说明一下。

1、如果不作额外修改,默认情况下,所有被创建者的__proto__都指向创建者的prototype:


(1) 如果不作额外修改,默认情况下,所有function的__proto__(因为function是函数对象,所有它有__proto__属性)都指向Function的prototype,包括Function自身。

(2)如果不作额外修改,默认情况下,所有对象的__proto__都指向用来创建它的function对象的prototype。


2、一个对象上的属性包括自身定义的属性和原型链上的属性,这对于该对象外部使用者来说是透明的,平坦的,都可以直接访问,还可以通过hasOwnProperty来区分自身属性和原型链属性。


当然,JavaScript很灵活,我们可以通过代码随时修改对象的__proto__和函数的prototype,但是有以下几个特殊情况:

(1)Function.prototype不允许做任何修改,对其赋值将不会产生任何作用。

(2)普通function.prototype可以赋任何值,都会赋值成功,但影响却不一样。看如下代码:


Object.prototype.a = 100;
function foo(){};


情况一:不修改foo.prototype

var o = new foo();
o.__proto__ === > {a:100};
//这是因为:
foo.prototype.__proto__ == Object.prototype; ===> foo.prototype : {a:100}  //对于外部使用者原型链属性平坦化

o.__proto__ === foo.prototype;===> o.__proto__: {a:100}


情况二:修改foo.prototype为自定义对象

var p1 =  {b:200}
p1.__proto__ ===> {a:100}    //通过字面量创建的对象,__proto__指向Object.prototype
       foo.prototype = p1;
foo.prototype ===> {b: 200, a: 100}  //p1对于外部使用者原型链属性平坦化

var o1 = new foo();
o1.__proto__ === > {b: 200, a: 100} //因为o1.__proto__ === foo.prototype;



情况三:修改foo.prototype为自定义对象

foo.prototype = 300;
foo.prototype ===> 300  //修改成功

var o2 = new foo();
o2.__proto__ === > { a: 100} 
//按理来说应该是o2.__proto__ === foo.prototype,o2.__proto__应该为300,为什么确实{a:100}呢?这不正是Object.prototype么?
o2.__proto__ === Object.prototype ===> true //测试一下,果然如此。

//这说明,在var o2 = new foo();	时,引擎发现foo.prototype不是一个对象,而强行将Object.prototype赋值给了o2.__proto__。引擎为什么要这么做呢?我想这是因为JavaScript中对象的属性访问机制(如果对象自身找不到该属性,就去原型链中找),所以要保证o2.__proto__必须是个对象。


(3)修改对象的__proto__只能是对象类型,否则修改不成功,__proto__保持原值。

var foo = function(){}
foo.prototype = {a:100}

var x = new foo;
x ===>  {a: 100}

x.__proto__ = true
x.__proto__  ===>  {a: 100}                //failed

x.__proto__ = 1
x.__proto__  ===> {a: 100}                 //failed

x.__proto__ = {b:200}
x.__proto__  ===> Object {b: 200}     //succeed


(4)Function.prototype是唯一一个类型为“function”的prototype,其他函数的prototype类型都是object。

typeof Function.prototype ===> “function”
typeof Object.prototype ===> “object”


补充:

1、为什么要有prototype和__proto__?

主要是为了原型链继承的数据的共有和私有。函数对象将自身属性放到构造函数中,将共有属性放到prototype中,这样由自身创建的对象将具有所有属性,而继承下来的函数对象所创建的对象只具有prototype中的属性。

这个问题至于是否还有其他原因,还有待学习。


var Base(){
  this.a = 100;
}
Base.prototype = {b:200};

var Derive(){
  this.c = 300;
}
Derive.prototype = Base.prototype;

var o1 = new Base();
var o2 = new Derive();

o1.a ===> 100
o1.b ===> 200
o2.a ===> undefined
o2.b ===> 200
o2.c ===> 300

Base.prototype.b = 400;
o1.b ===> 400
o2.b ===> 400

//这里也印证了之前的猜想:要保证o.__proto__必须是个对象。


2、new的背后做了什么?

function Foo(){}
var o=new Foo();

类似于:
function Foo(){}
var o = {};	//{}也是个对象,它的__proto__ === Object.prototype
o.__proto__= Foo.prototype;    //真正的实现,此处还会判断Foo.prototype是否是对象类型
Foo.call(o);


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值