注意:此问题是对最近提出的问题JavaScript: automatic getters and setters in closures without eval?的跟进。
该问题的要点如下:“如何在闭包中自动为范围变量提供getter和setter - 而不使用eval
语句”。有海报,提供了使用eval
演示如何执行此操作的代码,并且用户提供了以下answer,其中不需要eval
:
function myClosure() {
var instance = {};
var args = Array.prototype.slice.call(arguments);
args.forEach(function(arg) {
instance[arg] = function(d) {
if (!arguments.length) return arg;
arg = d;
return instance;
};
})
return instance;
};
这个问题是关于如何使用上述函数设置/获取的范围变量的默认值。
如果我们只是向变量v3
添加默认值,我们会得到以下结果:
function myClosure() {
var v3 = 2
var instance = {};
var args = Array.prototype.slice.call(arguments);
args.forEach(function(arg) {
instance[arg] = function(d) {
if (!arguments.length) return arg;
arg = d;
return instance;
};
})
return instance;
}
var test = myClosure("v1", "v2", "v3") // make setters/getters for all vars
test.v1(16).v2(2) // give new values to v1, v2
console.log(test.v1() + test.v2() + test.v3()) // try to add with default v3
// 18v3
我没想到。
那么如何为变量提供默认值?
注意:请构建以下实现,在初始化时生成getter / setter(允许代码作者预先定义所有应该具有getter和setter的变量)
function myClosure() {
var instance = function () {};
var publicVariables =['v1', 'v2', 'v3']
function setup() {
var args = Array.prototype.slice.call(arguments);
// if called with a list, use the list, otherwise use the positional arguments
if (typeof args[0] == 'object' && args[0].length) { args = args[0] }
args.forEach(function(arg) {
instance[arg] = function(d) {
if (!arguments.length) return arg;
arg = d;
return instance;
};
})
}
setup(publicVariables)
// setup('v1', 'v2', 'v3') also works
return instance;
}
var test = myClosure()
test.v1(16).v2(2)
console.log(test.v1() + test.v2() + test.v3())
如何使用自动getter和setter在此设置(上面的代码块)中使用默认值?
答案 0 :(得分:2)
该问题的要点如下:“如何在闭包中自动为范围变量提供getter和setter - 而不使用eval语句”。在那里有海报,提供了代码演示如何使用eval进行操作,用户给出了一个不需要eval的答案。
不,你不能没有eval
。这里不使用任何形式的eval
的所有答案都不能访问范围变量,而只是普通的属性 - 或者它们创建自己的局部变量。
提供默认值非常简单:
function myClosure(...args) {
var instance = {v3: 2};
// ^^^^^ not a `var`
for (const arg of args) {
let val = instance[arg];
instance[arg] = function(d) {
if (!arguments.length) return val;
val = d;
return instance;
};
}
return instance;
}
答案 1 :(得分:1)
你的意思是这样的:
function myClosure(...vars) {
const instance = {};
vars.forEach(varArg => {
let name = undefined;
let value = undefined;
if (typeof varArg == 'string')
{
name = varArg;
}
else
{
name = Object.keys(varArg)[0];
value = varArg[name];
}
instance[name] = function(d) {
if (!arguments.length) return value;
value = d;
return instance;
};
})
return instance;
}
const test = myClosure(
{ "v1": 1 },
"v2",
{ "v3": 3 },
);
// Print some defaults.
console.log(test.v1());
console.log(test.v2());
test.v1(16).v2(42) // give new values to v1, v2
console.log(test.v1(), test.v2(), test.v3())
代理,因为它。
function myClosure(...vars) {
const instance = vars.reduce((obj, { name, value }) => {
obj[name] = value;
return obj;
}, {});
let proxy;
const handler = {
get: function(target, prop) {
return (...args) => {
if (args.length == 0)
return instance[prop];
instance[prop] = args[0];
return proxy;
};
}
};
proxy = new Proxy(instance, handler);
return proxy;
}
const test = myClosure(
{ name: "v1", value: 1 },
{ name: "v2" },
{ name: "v3", value: 3 }
);
// Print some defaults.
console.log(test.v1());
console.log(test.v2());
console.log(test.vNew());
test.v1(16).v2(42).vNew(50); // give new values to some variables.
console.log(test.v1(), test.v2(), test.v3(), test.vNew())
答案 2 :(得分:0)
注意:我发布自己的答案仅供参考。我不会将此标记为问题的答案。
基于 @ H.B。提供的答案,我会通过以下方式更新答案:
实例现在是一个函数,而不是一个对象
function myClosure() {
var instance = function () {
console.log(this.v1(), this.v2(), this.v3())
};
var publicVariables =[ 'v1', 'v2', {'v3': 3} ]
function setup() {
var args = Array.prototype.slice.call(arguments);
// if called with a list, use the list,
// otherwise use the positional arguments
if (typeof args[0] == 'object' && args[0].length) { args = args[0] }
args.forEach(function(arg) {
var name, value
if(typeof arg == 'object') {
name = Object.keys(arg)[0]
value = arg[name]
} else {
name = arg
value = undefined
}
instance[name] = function(d) {
if (!arguments.length) return value;
value = d;
return instance;
}; // end instance function
}) // end for each
} // end setup
setup(publicVariables)
return instance;
}
var test = myClosure().v1(10).v2(2)
console.log(test.v1(), test.v2(), test.v3())
test.v1(20).v3(1)
console.log(test.v1(), test.v2(), test.v3())