对于In与闭包和函数创建问题 [英] For In with closure and function creation issues
问题描述
我一直在尝试创建一个包装器函数,它接受一个对象(obj)的所有函数属性,并用另一个函数(p())包装它们。
I've been trying to create a wrapper function that takes all the function properties of an object (obj) and wraps them with another function ( p() ).
这段代码说明了我的意思。
This code illustrates what I mean.
//Setup code
function p(input){
//do stuff
return new_output;
}
obj = {
prop1: function(){...},
prop2: function(){...},
prop3: function(){...}
}
//Here's the wrapper function
r = new R(obj);
//Expected behaviour
r.prop1(a1,a2); //Just like saying p(obj.prop1(a1,a2))
这是我的尝试实现
function R (obj) {
for (var member in obj) {
//Mirrors obj's members
this[member] = function (args) {
var fn,inner_member = member;
//Convert to array for 'apply'
args = Array.prototype.slice.call(args,0);
fn = obj[member];
//Returns unexpected values, poo...
console.log(inner_member);
return p( fn.apply(fn,args) );
}
};
}
不幸的是,每当我运行r.prop1()时, console,通过console.log,返回错误的成员,prop3和obj [member]返回obj.prop3。一切都是错的。
Unfortunately, whenever I run r.prop1(), the console, via console.log, returns the wrong member, "prop3" and obj[member] returns "obj.prop3". Everything is wrong.
我认为这与闭包以及新创建的成员函数在其范围之外的看法有关。
I think this has to do with the closure and how the newly created member member functions are looking outside their scope.
如何解决这个问题?
编辑: David Flanagan的Javascript:The Definitive Guide非常直接地回答了这个问题在第8章第3节中。该部分是关于闭包的,最后一个例子反映了我上面写的内容。理解我的问题的关键是函数在定义的同一范围链中调用。函数是对象和相关的范围链。 AKA,一个闭包。
David Flanagan's Javascript: The Definitive Guide answers this question pretty much directly in Chapter 8, section 3. That section is on closures and the last example mirrors what I wrote above. The key to understanding my problem is that functions are invoked in the same scope chain as they're defined. A function is an object AND related scope chain. AKA, a closure.
推荐答案
函数引用的成员
变量你在中为
生成循环是相同的成员
变量。
The member
variable referenced by the functions you're generating in the for
loop is the same member
variable.
这是因为JavaScript 没有块范围,只有函数范围。这是一个常见问题。
This is because JavaScript does not have block scope, just function scope. It's a common issue.
一种解决方案是在循环中调用一个函数,传入成员
,使其成为新变量范围的一部分。
One solution is to invoke a function in the loop, passing in member
so that it becomes part of a new variable scope.
function R (obj) {
// --------v---- use var to declare variables in order to avoid implicit globals
for (var member in obj) { // ...thanks to @CMS for the reminder.
createMember( member );
}
function createMember( mem ) {
//Mirrors obj's members
this[ mem ] = function (args) {
var fn,inner_member = mem;
//Conver to array for 'apply'
// Don't forget to use .call-----------v
args = Array.prototype.slice.call(args,0);
fn = obj[ mem ];
console.log(inner_member);
return p( fn.apply(fn,args) );
};
}
}
现在成员的价值循环中每次迭代中的
作为参数传递给单独的函数调用,每次都会创建一个新的变量作用域。
Now the value of member
in each iteration in the loop is pass as an argument into a separate function invocation, which creates a new variable scope each time.
因为每个新函数都是每个唯一变量范围的一部分,所以每个函数都引用一个不同的 mem
变量(或者参数)。
Because each new function is part of each unique variable scope, each one is referencing a different mem
variable (or parameter).
同一概念还有其他变体:
There are other variations on the same concept:
function R (obj) {
for (var member in obj) {
this[ member ] = createMember( member );
}
function createMember( mem ) {
//Mirrors obj's members
return function (args) {
var fn,inner_member = mem;
//Conver to array for 'apply'
// Don't forget to use .call-----------v
args = Array.prototype.slice.call(args,0);
fn = obj[ mem ];
console.log(inner_member);
return p( fn.apply(fn,args) );
};
}
}
这是相同的,除了从调用返回一个函数,分配给这个[member]
。同样的原则。
This is the same, except that it returns a function from the invocation to be assigned to this[ member ]
. Same principle though.
其他人更喜欢使用IIFE (立即调用函数表达式)而不是命名函数。
Other people prefer to use an IIFE (immediately invoked function expression) instead of a named function.
function R (obj) {
for (var member in obj) {
(function( mem ) {
//Mirrors obj's members
this[ mem ] = function (args) {
var fn,inner_member = mem;
//Conver to array for 'apply'
// Don't forget to use .call----------------v
args = Array.prototype.slice.call(args,0);
fn = obj[ mem ];
console.log(inner_member);
return p( fn.apply(fn,args) );
};
})( member );
}
}
...虽然我认为不太清楚,效率稍差。
...though I think it's less clear, and a little less efficient.
编辑:已添加 var
到成员
变量以避免隐式全局。感谢 @CMS 。
Added var
to member
variable to avoid implicit global. Thanks to @CMS.
编辑:已将 Array.prototype.slice(args,0)
更改为 Array.prototype.slice.call(args,0)
编辑:
这与任何问题都没有关系,但如果你所做的就是在包装器调用原始函数时传递参数
,你就可以摆脱它...
This isn't related to any issue, but if all you're doing is passing on the arguments
when the wrapper invokes the original function, you can get rid of...
args = Array.prototype.slice.call(args,0);
并传递原始参数
对象:
return p( fn.apply( fn,arguments ) );
无需将其转换为数组。
这篇关于对于In与闭包和函数创建问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!