Function.prototype.call 内部实现探讨

 

今天在网上看到了一个有意思的js题目,就拿去和同事讨论。本来以为是一个很简单的问题,但越讨论越深入,逐步认识到了这个问题的深度。

题目是这样的:

 

Java代码
function f1()
{
      alert(1);   
}   
 
function f2()
{
      alert(2);   
}   
 
var f3 = f1.call;   
f3.call(f2);  
 
function f1()
{
  alert(1);
}function f2()
{
  alert(2);
}
 
var f3 = f1.call;
f3.call(f2); 

 

 讨论的过程就不在赘述了,最后的结论是:

1 Function.prototype.call 实现的时候与是依赖与this的,如果直接调用f3(),浏览器将会报错。这个特性跟document.getElementById类似,比如在FF下,$=document.getElementById,调用$时浏览器会报错。

 

2 同样的对函数实例的call调用,如Function.prototype.call()与Function.prototype.call.call(Function.prototype与Function.prototype.call都是Function的实例),Function.prototype.call()可以正常调用,Function.prototype.call.call()则会抛出异常。

 

3 结合结论2以及题目本身,猜测是js引擎对call做了不同的实现,伪码如下:

 

Java代码
var call = function(a,b,c)
{
      this(b,c);//忽略this内部实现与a的绑定;  
}   
 
call.call = function(a,b,c)
{
      a(b,c);//忽略this的绑定  
}  
 
Function.prototype.call = call;  
 
var call = function(a,b,c)
{
  this(b,c);//忽略this内部实现与a的绑定;
}
 
call.call = function(a,b,c)
{
  a(b,c);//忽略this的绑定
}
 
Function.prototype.call = call;
 
 这里猜测的是call本身作为Function的一个实例,在对call.call调用的时候,它的实例属性覆盖了它的原型属性。

 

4 但是通过比对 Function.prototype.call === Function.prototype.call.call 是为true的,所以结论3是错误的。应该是js内部为call的实现做了一个统一的托管,根据调用对象的不同,实现不同的逻辑。伪码如下:

 

Java代码
function call(a,b,c)
{
      if(this === call)
  {
          a(b,c);       
  }
  else
  {
         this(b,c);
      }   
}
 
Function.prototype.call = call;  
posted @ 2012-04-11 10:03  蝌蚪归来  阅读(514)  评论(0编辑  收藏  举报