看不懂这个Javascript函数(函数重载)
Can't understand this Javascript function (function overloading)
我正在阅读 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);
};
}
这是一个函数重载的例子,使用方式:
var ninja = {};
addMethod(ninja,'whatever',function(){ /* do something */ });
addMethod(ninja,'whatever',function(a){ /* do something else */ });
addMethod(ninja,'whatever',function(a,b){ /* yet something else */ });
我对作用域、闭包和 apply() 的使用有深入的了解。我的疑惑是:
- fn.length将returnfn中定义的参数个数。请问arguments.lengthreturn参数的个数是多少?已经存在的功能?
- 但如果是这样,并且它们匹配,为什么它会应用新功能而不是现有功能?
- 如果arguments.length return是给定函数的编号,那么它们什么时候不同?
- 我添加了10个方法,从无参数开始,每次递增,添加第10个方法后,我调用无参数方法,'store'第一个函数在哪里?
- 我不明白old在这里的用法
我可能没有能回答所有问题的关键概念。请随意给我一个解释,而不是单独回答问题。
已添加评论:
//replace object[name] with a wrapper that either calls the passed-in
//function (fn) or the old value of object[name]
function addMethod(object, name, fn) {
//store object[name]
var old = object[name];
object[name] = function(){
//if the wrapper is called with as many arguments as is the arity of the passed in function (fn), call the passed in function (fn)
if (fn.length == arguments.length)
return fn.apply(this, arguments)
//otherwise call the old value of object[name] but only if it is a function
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
dandavis 的评论解决了您的大部分第一个问题。 arguments.length
给出应用于行
中声明的函数的参数数量
object[name] = function(){
该方法是 'stored' 在第一行代码中声明的 ninja
对象中,并传递给后续调用。
创建函数后,它会保留对定义范围内变量的访问权限。在这种情况下,我们创建的每个方法都可以访问一个范围,其中包含变量 old、object、name 和 fn。旧变量可以从我们添加的每个方法访问,并且从主对象对它的引用被覆盖,所以它只能从该范围内的 "old" 访问。您基本上有一堆 "old" 变量通过它们级联以找到处理给定参数数量的变量。
function addMethod(object, name, fn) {
// Get a reference to the existing method name.
var old = object[name];
/*
Write over the method name with a new method
that checks for a specific argument length.
If the method is called with a different
argument length and "old" exists call the
old method.
*/
object[name] = function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments)
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
fn.length
will return the number of parameters defined in fn. Will arguments.length
return the number of which arguments? The already existing function's?
没有。 arguments
是一个类似数组的局部变量,可在函数内部使用。它包含传递给函数的参数数量。
你的其余问题可以通过解决这个问题来回答:
I add 10 methods, starting with no parameters and increasing the number of them each time, after adding the 10th method, I call the method with no parameters, where did it 'store' the first function?
逐步查看 addMethod
方法可能会有帮助:
function addMethod(object, name, fn) {
var old = object[name];
// Get the old function corresponding to this name. Will be "undefined"
// the first time "addMethod" is called.
object[name] = function(){
// Now, assign object[name] to a new function.
// The critical part of this function is that "old" is captured inside of
// this function and will be available any time the function is called.
if (fn.length == arguments.length)
// if the number of parameters belonging to the function we've added
// matches what was passed in, call "fn"
return fn.apply(this, arguments)
else if (typeof old == 'function')
// Otherwise if there's another function with this name
// call it instead.
return old.apply(this, arguments);
};
}
因此,让我们在您的示例中每次调用 addMethod
并检查 fn
和 old
的值。您可以将其组织为相互堆叠的函数的方式,利用 old
.
的范围
addMethod(ninja,'whatever',function(){ /* do something */ });
// old === undefined
addMethod(ninja,'whatever',function(a){ /* do something else */ });
// old === function #1
addMethod(ninja,'whatever',function(a,b){ /* yet something else */ });
// old === function #2
最后调用addMethod
三次ninja.whatever
指的是一个函数如果可以的话调用函数#3,如果可以的话再调用old
函数(函数#2)参数与函数 #3 的参数列表长度不匹配。
所以视觉上,你可以这样想:
function #3 (a,b)
function #2 (a)
function #1 ()
每个函数的 old
引用指向它下面的函数。
现在让我们看看调用 ninja.whatever()
时会发生什么。这个函数在我们栈的 "bottom" 处。
- 当前与
whatever
关联的函数是函数 #3。调用函数 #3 时,fn.length != arguments.length
,因此执行 old
(函数 #2)。
- 所以现在我们正在执行功能 #2。同样,当调用函数 #2 时,
fn.length != arguments.length
和 old
(函数 #1)被执行。
- 最后,函数 #1 被执行。这次
fn.length == arguments.length
函数被调用。
function.length
是函数期望的参数数量,即形式参数。 arguments.length
是传递给函数的实际参数数量,这意味着已经存在的函数,因为没有参数可以传递给新函数;它没有被调用,只是一个值。 arguments
对象是一个类似数组的对象,包含传递的参数。 (知道这个长度 属性 可能更有意义)。给定参数和形式参数的长度之间的区别在于,函数可以传递比指定参数更多或更少的参数。例如,console.log()
接受任意数量的参数。其中一些函数只是围绕 arguments 对象包装一个循环,并对 arguments 对象中的每个元素做一些事情。添加的每个方法都存储为作为 addMethod
函数的第一个参数给出的对象的 属性。变量 old
只是一个变量,名称不是理解概念所必需的。也许作者通过 old
暗示对象及其属性的可变性(可变性是在声明后赋予 属性 新值/修改对象的能力)。
我正在阅读 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);
};
}
这是一个函数重载的例子,使用方式:
var ninja = {};
addMethod(ninja,'whatever',function(){ /* do something */ });
addMethod(ninja,'whatever',function(a){ /* do something else */ });
addMethod(ninja,'whatever',function(a,b){ /* yet something else */ });
我对作用域、闭包和 apply() 的使用有深入的了解。我的疑惑是:
- fn.length将returnfn中定义的参数个数。请问arguments.lengthreturn参数的个数是多少?已经存在的功能?
- 但如果是这样,并且它们匹配,为什么它会应用新功能而不是现有功能?
- 如果arguments.length return是给定函数的编号,那么它们什么时候不同?
- 我添加了10个方法,从无参数开始,每次递增,添加第10个方法后,我调用无参数方法,'store'第一个函数在哪里?
- 我不明白old在这里的用法
我可能没有能回答所有问题的关键概念。请随意给我一个解释,而不是单独回答问题。
已添加评论:
//replace object[name] with a wrapper that either calls the passed-in
//function (fn) or the old value of object[name]
function addMethod(object, name, fn) {
//store object[name]
var old = object[name];
object[name] = function(){
//if the wrapper is called with as many arguments as is the arity of the passed in function (fn), call the passed in function (fn)
if (fn.length == arguments.length)
return fn.apply(this, arguments)
//otherwise call the old value of object[name] but only if it is a function
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
dandavis 的评论解决了您的大部分第一个问题。 arguments.length
给出应用于行
object[name] = function(){
该方法是 'stored' 在第一行代码中声明的 ninja
对象中,并传递给后续调用。
创建函数后,它会保留对定义范围内变量的访问权限。在这种情况下,我们创建的每个方法都可以访问一个范围,其中包含变量 old、object、name 和 fn。旧变量可以从我们添加的每个方法访问,并且从主对象对它的引用被覆盖,所以它只能从该范围内的 "old" 访问。您基本上有一堆 "old" 变量通过它们级联以找到处理给定参数数量的变量。
function addMethod(object, name, fn) {
// Get a reference to the existing method name.
var old = object[name];
/*
Write over the method name with a new method
that checks for a specific argument length.
If the method is called with a different
argument length and "old" exists call the
old method.
*/
object[name] = function(){
if (fn.length == arguments.length)
return fn.apply(this, arguments)
else if (typeof old == 'function')
return old.apply(this, arguments);
};
}
fn.length
will return the number of parameters defined in fn. Willarguments.length
return the number of which arguments? The already existing function's?
没有。 arguments
是一个类似数组的局部变量,可在函数内部使用。它包含传递给函数的参数数量。
你的其余问题可以通过解决这个问题来回答:
I add 10 methods, starting with no parameters and increasing the number of them each time, after adding the 10th method, I call the method with no parameters, where did it 'store' the first function?
逐步查看 addMethod
方法可能会有帮助:
function addMethod(object, name, fn) {
var old = object[name];
// Get the old function corresponding to this name. Will be "undefined"
// the first time "addMethod" is called.
object[name] = function(){
// Now, assign object[name] to a new function.
// The critical part of this function is that "old" is captured inside of
// this function and will be available any time the function is called.
if (fn.length == arguments.length)
// if the number of parameters belonging to the function we've added
// matches what was passed in, call "fn"
return fn.apply(this, arguments)
else if (typeof old == 'function')
// Otherwise if there's another function with this name
// call it instead.
return old.apply(this, arguments);
};
}
因此,让我们在您的示例中每次调用 addMethod
并检查 fn
和 old
的值。您可以将其组织为相互堆叠的函数的方式,利用 old
.
addMethod(ninja,'whatever',function(){ /* do something */ });
// old === undefined
addMethod(ninja,'whatever',function(a){ /* do something else */ });
// old === function #1
addMethod(ninja,'whatever',function(a,b){ /* yet something else */ });
// old === function #2
最后调用addMethod
三次ninja.whatever
指的是一个函数如果可以的话调用函数#3,如果可以的话再调用old
函数(函数#2)参数与函数 #3 的参数列表长度不匹配。
所以视觉上,你可以这样想:
function #3 (a,b)
function #2 (a)
function #1 ()
每个函数的 old
引用指向它下面的函数。
现在让我们看看调用 ninja.whatever()
时会发生什么。这个函数在我们栈的 "bottom" 处。
- 当前与
whatever
关联的函数是函数 #3。调用函数 #3 时,fn.length != arguments.length
,因此执行old
(函数 #2)。 - 所以现在我们正在执行功能 #2。同样,当调用函数 #2 时,
fn.length != arguments.length
和old
(函数 #1)被执行。 - 最后,函数 #1 被执行。这次
fn.length == arguments.length
函数被调用。
function.length
是函数期望的参数数量,即形式参数。 arguments.length
是传递给函数的实际参数数量,这意味着已经存在的函数,因为没有参数可以传递给新函数;它没有被调用,只是一个值。 arguments
对象是一个类似数组的对象,包含传递的参数。 (知道这个长度 属性 可能更有意义)。给定参数和形式参数的长度之间的区别在于,函数可以传递比指定参数更多或更少的参数。例如,console.log()
接受任意数量的参数。其中一些函数只是围绕 arguments 对象包装一个循环,并对 arguments 对象中的每个元素做一些事情。添加的每个方法都存储为作为 addMethod
函数的第一个参数给出的对象的 属性。变量 old
只是一个变量,名称不是理解概念所必需的。也许作者通过 old
暗示对象及其属性的可变性(可变性是在声明后赋予 属性 新值/修改对象的能力)。