方法#1
function transform(ar) {
var alStr = [];
for(var i=0; i<ar.length; i++) {
alStr[i] = (function(v) {
return (function() {
return v;
});
}(ar[i]));
}
return alStr;
}
var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
a[1];
b[1]();
方法#2
function transform(ar) {
var alStr = [];
for(var a in ar) {
var O = function() {
return a;
}
alStr.push(O);
}
return alStr;
}
var a = ["a", 24, { foo: "bar" }];
var b = transform(a);
a[1];
b[1]();
上述方法用于将数组对象转换为单个函数,这些函数在执行时返回特定的数组对象。想知道为什么方法#1工作,方法#2不工作。
答案 0 :(得分:4)
在方法#2中有两个问题:
您将返回键名a
,而不是数组值ar[a]
。也就是说,而不是return a;
你想要的return ar[a];
。
该函数将始终引用循环的最后一个值,因为它引用相同的范围对象。要创建新的范围对象,您需要一个闭包,with
块或绑定函数。
关闭:
for(var a in ar) {
var O = (function(val) {
return function() {
return val;
}
})(ar[a]);
alStr.push(O);
}
使用with
块:
for(var a in ar) {
with({val: ar[a]}) {
alStr.push(function() {
return val;
});
}
}
使用绑定功能:
for(var a in ar) {
var O = function(x) { return x; };
alStr.push(O.bind(null, arr[a]));
}
答案 1 :(得分:3)
function.bind(obj, val)
。最近引入,function.bind
允许您按值和在某些上下文中传递变量。阅读更多here。
所以,你可以这样写:
function transform(ar) {
var alStr = [];
var O = function(x) { return x }
for(var a in ar) {
alStr.push(O.bind(null, ar[a]));
}
return alStr;
}
var a = ["a", 24, 12345];
var b = transform(a);
console.log(a[2]);
b[2]();
这是一个更正确的范例,因为启动闭包具有非常明确的含义。但是,使用bind往往是一种在函数调用时特别使用的函数式方法(特别是在上下文或特定的规定中)。
使用with块也有一些缺点(有很多问题)。
奖励:如果您希望b
也代表对a
数组的后续更改,则此解决方案可以解决该问题:
function transform(ar) {
var alStr = [];
var O = function(x) { return ar[x] }
for(var a in ar) {
alStr.push(O.bind(null, a));
}
return alStr;
}
var a = ["a", 24, 12345];
var b = transform(a);
console.log(a[2]);
console.log(b[2]());
console.log("*********");
a[2] = "new value!";
console.log(a[2]);
console.log(b[2]());