理解这个JavaScript函数重载示例

时间:2013-08-08 09:12:18

标签: javascript closures

我目前正在Secrets of the JavaScript Ninja学习John Resig,我希望有人可以帮助我进一步了解其中一个例子。

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

代码如下所示:

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);

我真的想要深入了解不仅仅是如何使用这种方法,而是为什么它可以工作,所以任何见解都会受到高度赞赏。

由于

6 个答案:

答案 0 :(得分:3)

  

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

实际上需要使用它。

thisarguments对于每个function都有所不同,并在调用时设置。使用fn()时,fn将使用空arguments集合调用,或者this没有传递任何值。

.apply(this, arguments)调用fnold,并从当前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()跟随“手臂”或“箭头”到oldfnreturn允许结果通过/ {相反。

答案 1 :(得分:1)

我认为你错过了.apply

的观点

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

TL;博士

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

答案 2 :(得分:1)

在Javascript中,this变量在声明函数时没有设置,但在执行时,取决于用于访问函数引用的对象。

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

答案 3 :(得分: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

答案 4 :(得分:1)

以下是代码的细分。

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/

答案 5 :(得分:0)

fn.apply(this, arguments)

使用fn作为当前thisthis作为参数调用arguments

fn()

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

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