prototype&new操作符

构造函数里用this和.prototype.的区别

<span style="font-size:18px;">function Foo() {
  this.a = function() {
    alert('hahaha')
  };
}
</span>
var bar = new Foo();bar.a();

 

<span style="font-size:18px;">function Foo() {
}
Foo.prototype.a = function() {
  alert('hahaha')
};
var bar = new Foo();
bar.a();</span>

function Foo() {}Foo.prototype.a = function() { alert('hahaha')};var bar = new Foo();bar.a();

 
在结果上看是一样的,但是这两个有什么区别呢? 

仔细想想,如果使用this的话,由于是写在Foo构造函数里面的,所以我可以访问到构造函数里面的变量,比如下面的代码:

<span style="font-size:18px;">function Foo() {
  var x = 'hahaha'
  this.a = function() {
    alert(x)
  };
}
var bar = new Foo();
bar.a();</span>
但是
<span style="font-size:18px;">function Foo() {
  var x = 'hahaha';
}
Foo.prototype.a = function() {
  alert(x)
};
var bar = new Foo();
bar.a();</span>
就会报错: x is not defined.

对于我接触到的程序的情况来看,如果需要一个Foo需要的var, 则会把他写在prototype里面,

<span style="font-size:18px;">function Foo() {
}
Foo.prototype.x = 'hahaha'
Foo.prototype.a = function() {
  alert(this.x)
};
var bar = new Foo();
bar.a();</span>


谈到这,又想起new来了,上次写的太不全面,再补一点:

<span style="font-size:18px;">function new (f) {
    var n = { '__proto__': f.prototype };
    return function () {
        f.apply(n, arguments);
        return n;
    };
}</span>
http://www.cnblogs.com/purediy/archive/2012/09/12/2682490.html
这篇文章中一开始给了一张关于constructor, prototype and instance的图,配合上面的代码对理解很有帮助:




有一个问题,在new出一个对象的时候,它的proto是复制不对,这里要做更正,是指针!)了一套prototype出来,并且你可以对其进行改写但不会影响构造函数本身改写后其他基于这个构造函数new出来的对象内容也有可能根据引用类型/基本类型去改写/覆盖。比如如下的代码:

function Foo() {}
Foo.prototype.bar = new Date();

var a = new Foo();
var b = new Foo();

a.bar.setMonth(0);
console.log(b.bar); // 变成了一月份

为了解决这个问题,可以采用原型式继承的方法,如下:

<span style="font-size:14px;">function Foo() {
  this.bar = new Date();
}
function FooMed() {
  Foo.call(this);
}
var a = new FooMed();
var b = new FooMed();
a.bar.setMonth(0);
console.log(b.bar);</span><span style="font-size: 18px;">
</span>
这样 a 就算改写了它的bar也不会 影响b了. 当你写新的__proto__给new出来的对象时,调用这个属性会先在__proto__中寻找是否有这个属性,如果没有才会去在构造函数的prototype中寻找, )。更神奇的是,如果对new出来的对象中的某一个__proto__进行改写,那么输出就就是根据改写后的__proto__来输出,但是一但改写的这部分代码被删除,原来的__proto__就又被恢复了,感觉这几句太绕了,还是看下面的代码比较清楚...: ( 前面的红字已经解释了原因

<span style="font-size:18px;">function Foo() {
}
Foo.prototype.x = 'hahaha'
Foo.prototype.a = function() {
  alert(this.x)
};
var bar = new Foo();
bar.a = 'newhaha';
alert(bar.a);
delete bar.a;
bar.a();</span>
输出依次是: 'newhaha', 'haha' 太奇妙了。。 不知道以后有没有机会了解到这是为什么,这部分是怎么实现的。以后来做UPDATE. (已经找到原因了:‘实例与原型之间的松散连接关系’,当调用到bar.a的时候,首先程序会去搜索实例中自带的'.a', 所以输出就是.a, 但是如果没有.a的话就会搜索到prototype上,因此就输出原型的.a

另外这里引出了 hasOwnProperty()的方法, 比如上一部分代码,重写了bar的a之后,如果去尝试

<span style="font-size:18px;">bar.hasOwnProperty('a')</span>
会发现结果是true(因为a '遮蔽'了prototype中的a,遮蔽的概念是书上给出的), 然后delete的过程完成后再去看,结果会变成false(因为这个instance是不包含对a的定义的)

如果把 hasOwnProperty配合in来使用(in如果返回为true,那么这个属性既可能是直接在对象上访问到的要么就是通过原型访问到的),就可以确定该属性是存在在prototype中还是该属性独有的(改写后的也算独有的)。

另外竟然谈到改写的问题,还有一个比较重要的问题,当我们采用以下方法来改写整个prototype这个object的时候,比如:

<span style="font-size:18px;">function Foo() {}
Foo.prototype = {
  a: 'haha'
}
var foo = new Foo();</span>
这种情况下,new出来的foo它的constructor就不再指向Foo了即

<span style="font-size:18px;">foo.constructor === Foo; // false</span>
但是仍旧可以通过instanceof来看它是否是Foo的实例,即:

<span style="font-size:18px;">foo instanceof Foo; // True</span>
另外有一个比较有趣的事情,就是new出实例的时机问题。

<span style="font-size:18px;">function Foo() {}
var foo = new Foo();
Foo.prototype.bar = function () {
  alert('haha');
}
foo.bar();
</span>
这里看似bar是在new Foo()之后才执行的,但是实际上foo.bar还是可以正确输出haha(在原型中找到的bar)

<span style="font-size:18px;">function Foo() {}
var foo = new Foo();
Foo.prototype = {
  bar: function() {
    alert('haha');
  }
}
foo.bar();</span>

 
会报错!因为prototype已经被整体改写了。而new的时候foo指向的是原prototype.















  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值