4

我目前正在研究John Resig的 JavaScript Ninja的秘密,我希望有人可以帮助我进一步理解其中一个示例。

它是一个允许对对象进行方法重载的函数,每个重载都有自己的定义和行为。他在这里写了博客。

代码如下所示:

function addMethod(object, name, fn) {
   var old = object[name];

   object[name] = function(){
      if (fn.length == arguments.length)
         return fn.apply(this, arguments)
      else if (typeof old == 'function')
         return old.apply(this, arguments);
};

并像这样使用:

addMethod(obj,'funcName',function(){});
addMethod(obj,'funcName',function(a){});
addMethod(obj,'funcName',function(a,b){});

我想我了解它的大部分工作原理,但你可以得到比我从上面的博客文章中给出的更好的解释)。

但是,它访问oldfn使用闭包的值,我仍在研究。

编辑 - 在jsFiddle下面添加。

当试图理解它时,我意识到线路返回fn.apply(this, arguments)可能只是return fn()看起来相同的结果。请参阅此jsFiddle中的示例。

apply那么,如果不需要,为什么要使用语法呢?

我尝试在没有应用的情况下使用jsFiddle中的示例,但它似乎总是

此外,当我们返回这些函数时究竟发生了什么,尤其是在以下情况下:

return old.apply(this, arguments);

我真的很想深入了解如何使用这种方法,以及它为什么有效,因此任何见解都将不胜感激。

谢谢

4

6 回答 6

3

apply那么,如果不需要,为什么要使用语法呢?

它实际上是使用所必需的。

this并且arguments对于每个都不同,function并且在调用它们时设置。通过使用fn(),fn将使用空集合arguments或不为 传递值来调用this

.apply(this, arguments)调用fnorold并传递当前function.

var obj = {};

addMethod(obj, 'funcName', function (a, b) {
    console.log(this === obj);
    console.log(a, b);
    console.log(arguments[0], arguments[1]);
});

obj.funcName(2, 3);
// true
// 2, 3
// 2, 3

此外,当我们返回这些函数时究竟发生了什么,尤其是在以下情况下:

return old.apply(this, arguments);

好吧,目的addMethod是创建一个函数链,每个函数都知道并可以调用old在它之前创建的函数。

对于书中的示例,链构建为:

// after: addMethod(obj, 'funcName', function(){});
obj.funcName = function(){...} ──> function(){}
// after: addMethod(obj, 'funcName', function(a){});
obj.funcName = function(){...} ──────> function(a){}
               └── function(){...} ──> function(){}
// after: addMethod(obj, 'funcName', function(a,b){});
obj.funcName = function(){...} ──────────> function(a,b){}
               └── function(){...} ──────> function(a){}
                   └── function(){...} ──> function(){}
Legend:
  `└──` represents an `old` reference
  `──>` represents a `fn` reference

每个function(){...}都是通过在不同的范围/闭包中重新评估相同的表达式而创建的唯一实例:

function(){
  if (fn.length == arguments.length)
     return fn.apply(this, arguments)
  else if (typeof old == 'function')
     return old.apply(this, arguments);
}

然后每个都.apply()跟随一个“手臂”或“箭头”到一个oldorfnreturns 允许结果通过 / 反向传递。

于 2013-08-08T09:26:26.697 回答
2

这是代码的细分。

function addMethod(object, name, fn) {

   //get the old function from the object
   var old = object[name];

   //assign a new function to the property
   object[name] = function(){

      //See if the method signatures match, if they do execute the new method
      if (fn.length == arguments.length)

        /*
         Call the function provided using apply, the first argument "this" is the object
         it sets the context for this in the function we provide, second argument is
         the arguments provided to the function.  We must return the result of the 
         function.    

        */

         return fn.apply(this, arguments)

      //If the old property on the object is a function and the new functions signature
      //did not match call the old function assigned to the property.

      else if (typeof old == 'function')

         // Same as before calling with apply, setting context and returning result

         return old.apply(this, arguments);
};

了解其apply工作原理很重要。它设置this函数内的上下文。例如:

var myFunction = function(){
   alert(this.msg);  //this will be set by what apply passes in as the first arg
};

var obj1 = {msg: "Hello"};
var obj2 = {msg: "World"};

myFunction.apply(obj1);
myFunction.apply(obj2);

示例 http://jsfiddle.net/NCaKX/

于 2013-08-08T09:26:33.417 回答
1

我认为你错过了.apply

我不会尝试解释它:P 你可以找到很多很好的解释,例如:

tl;博士

.apply允许您设置this上下文。.apply允许您将参数作为数组传递,允许可变数量的参数。

于 2013-08-08T09:16:59.870 回答
1

在 Javascript 中,this变量不是在函数声明时设置的,而是在执行时设置的,具体取决于使用哪个对象访问函数引用。

您需要使用apply不仅是因为前面提到的动态绑定this,还因为您不知道事先有多少个参数;所以apply接收参数列表并将列表中的每个元素作为单独的参数传递给函数。

于 2013-08-08T09:25:07.083 回答
1

.apply可以指定使用上下文

window.name = "window";

var object = {
    name:"object"
};

function showName(){
    alert(this.name);
}

showName(); // shows window
showName.apply(object); // shows object

更多:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

于 2013-08-08T09:26:30.957 回答
0
fn.apply(this, arguments)

调用fnwiththis作为当前参数thisarguments参数。

fn()

调用等于或fn(取决于您是处于“非严格模式”还是“严格模式”)但没有参数。thiswindowundefined

在这个Mozilla.org页面中,有一个很好的讨论this(总是有用的)

于 2013-08-08T09:19:02.023 回答