我目前正在使用一个相当深的设置变量的插件(某些地方有3-4个级别)。按照普遍接受的jQuery插件模式,我已经实现了一种简单的方法,用户可以使用以下符号动态修改设置:
$('#element').plugin('option', 'option_name', 'new_value');
以下代码类似于我现在使用的选项方法。
option: function (option, value) {
if (typeof (option) === 'string') {
if (value === undefined) return settings[option];
if(typeof(value) === 'object')
$.extend(true, settings[option], value);
else
settings[option] = value;
}
return this;
}
现在考虑我有一个像这样的设置变量:
var settings = {
opt: false,
another: {
deep: true
}
};
如果我想更改deep
设置,我必须使用以下表示法:
$('#element').plugin('option', 'another', { deep: false });
然而,因为在实践中我的设置可以是3-4级深度我觉得以下符号会更有用:
$('#element').plugin('option', 'another.deep', false);
然而,我不确定这是多么可行,也不确定如何去做。作为第一次尝试,我试图“遍历”有问题的选项并设置它,但是如果我设置了我的遍历变量,它不会设置它在原始设置变量中引用的内容。
option: function (option, value) {
if (typeof (option) === 'string') {
if (value === undefined) return settings[option];
var levels = option.split('.'),
opt = settings[levels[0]];
for(var i = 1; i < levels.length; ++i)
opt = opt[levels[i]];
if(typeof(value) === 'object')
$.extend(true, opt, value);
else
opt = value;
}
return this;
}
换句话说:通过在遍历后设置opt
,在settings
变量中实际引用的设置在此代码运行后保持不变。
我为长期问题道歉,任何帮助表示赞赏。谢谢!
修改
作为第二次尝试,我可以使用eval()
这样做:
option: function (option, value) {
if (typeof (option) === 'string') {
var levels = option.split('.'),
last = levels[levels.length - 1];
levels.length -= 1;
if (value === undefined) return eval('settings.' + levels.join('.'))[last];
if(typeof(value) === 'object')
$.extend(true, eval('settings.' + levels.join('.'))[last], value);
else
eval('settings.' + levels.join('.'))[last] = value;
}
return this;
}
但我真的很想看看是否有人能告诉我不使用eval的方法。由于它是用户输入字符串,我宁愿不在其上运行eval()
,因为它可能是任何东西。或者让我知道,如果我是偏执狂,它应该不会引起任何问题。
答案 0 :(得分:2)
您遇到的问题归结为指向对象的变量与其他类型(如字符串)的变量之间的差异。 2个变量可以指向相同的Object
,但不能指向相同的String
:
var a = { foo: 'bar' };
var b = 'bar';
var a2 = a;
var b2 = b;
a2.foo = 'hello world';
b2 = 'hello world';
console.log(a.foo); // 'hello world'
console.log(b); // 'bar'
您的遍历代码在循环的最后一次迭代之前工作正常,此时opt
是一个变量,在对象{{1}内包含与deep
相同的值 }}。相反,缩短你的循环并使用settings.opt.another
的最后一个元素作为levels
,如
key
在此阶段, var settings = {
another: {
deep: true
}
};
var levels = 'another.deep'.split('.')
, opt = settings;
// leave the last element
var i = levels.length-1;
while(i--){
opt = opt[levels.shift()];
}
// save the last element in the array and use it as a key
var k = levels.shift();
opt[k] = 'foobar'; // settings.another.deep is also 'foobar'
是指向与opt
相同的Object
的指针,而settings.another
是k
,其值为String
< / p>
答案 1 :(得分:0)
如何使用eval而不是遍历?
var settings = {
opt: false,
another: {
deep: true,
}
};
var x = "settings.another";
eval(x).deep = false;
alert(settings.another.deep);
答案 2 :(得分:0)