Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

再谈函数的bind方法

  以前的文章中提到过函数的bind方法,如果只是一般的用途,我们确实可以模拟实现。但是bind也有自己独特的地方,如果需要对一个函数使用new来创建它的实例,那我们就无法模拟了。bind实际上做了很多事情,但是正因如此,它的性能就有点伤不起了。
  首先,我们来看看bind创建的函数再创建的实例。 <script>
var F=function(){},G=F.bind();
var f=new F,g=new G;
console.log(g instanceof F); //true
console.log(f instanceof G); //true
console.log(g instanceof G); //true
console.log(g.__proto__==G.prototype); //false
console.log(G.prototype); //undefined;
</script>
  bind创建的函数自身是没有prototype的,即使设置了也没用。因为它override了[[Construct]],这意味着它把new运算符给override了,我们在new G得到的实际上是new F的结果,下面我们加参数试试。 <script>
var F=function(b){
  console.log(this.a,b);
},G=F.bind({a:1},2);
new G; //undefined 2
G(); //1 2
</script>
  bind方法的第一个参数是设置调用时的this,但是只有在作为函数调用时候生效。作为构造器时这个设置的this就无法生效,不过其它参数依然是有效。对于一个由bind创建的函数再次调用bind会产生什么呢? <script>
var F=function(b,c,d,e,f,g){
  console.log(this.a+","+Array.prototype.join.call(arguments));
},G=F.bind({a:1},2,3),H=G.bind({a:4},5,6,7);
F(); //undefined,
G(); //1,2,3
H(); //1,2,3,5,6,7
console.log(F.length); //6
console.log(G.length); //4
console.log(H.length); //1
</script>
  使用一个bind链时,只有第一次bind时设置的this生效,其它参数则是每次叠加上去。并且,bind消耗掉的参数会使得创建出来的函数的length属性相应的缩短。
  除了这些东西之外,bind还有另类的用途。因为bind创建的函数执行toString后不会输出函数体中的代码,这样是不是会安全一点呢?。 <script>
var F=function(){/*嗯嗯、啊啊、噢噢、呜呜*/};
console.log(F.bind().toString()); //function () { [native code] }
</script>
  但更关键的问题来了,它的性能如何? <input type="button" value="普通函数" id="f" />
<input type="button" value="bind函数" id="g" />
<input type="button" value="包裹函数" id="h" />
<script>
document.onclick=function(e){
  if(!(e=e.target).id)return;
  window.eval('(function(){\
    var f=function(){},g=f.bind(),h=function(){return f();};\
    var t=new Date,i=1E6;\
    while(i--)'+e.id+'();\
    console.log(new Date-t+" <-- '+e.value+'");\
  })()');
};
</script>

  性能很差!!!但由于Firefox调用函数本来就慢,从而衬托出了它比较快。总之,虽然它的功能很强大,但如果代码需要考虑性能就要得三思了。
网名:
54.226.58.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^