我目前正在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){});
我想我理解大部分内容是如何运作的,但你可以从上面的博客文章中得到更好的解释。
但是,它使用闭包来访问old
和fn
的值,我正在研究它。
编辑 - 在下面添加jsFiddle
。
在尝试理解它时,我意识到行返回fn.apply(this, arguments)
可能只是return fn()
,结果似乎相同。请参阅此jsFiddle中的示例。
那么,如果不需要,为什么它使用apply
语法?
我尝试过使用jsFiddle中没有应用的示例,但似乎总是如此
此外,当我们返回这些函数时会发生什么,特别是在以下情况下:
return old.apply(this, arguments);
我真的想要深入了解不仅仅是如何使用这种方法,而是为什么它可以工作,所以任何见解都会受到高度赞赏。
由于
答案 0 :(得分:3)
那么,如果不需要,为什么它使用
apply
语法?
实际上需要使用它。
this
和arguments
对于每个function
都有所不同,并在调用时设置。使用fn()
时,fn
将使用空arguments
集合调用,或者this
没有传递任何值。
.apply(this, arguments)
调用fn
或old
,并从当前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()
跟随“手臂”或“箭头”到old
或fn
,return
允许结果通过/ {相反。
答案 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);
答案 5 :(得分:0)
fn.apply(this, arguments)
使用fn
作为当前this
和this
作为参数调用arguments
。
fn()
调用fn
this
等于window
或undefined
(取决于您是否处于“非严格模式”或“严格模式”)但是没有参数。
在这个Mozilla.org页面中,对this
进行了很好的讨论(总是很有用)