JavaScript eval如何使用?

3

var obj = {x : 2}; eval.call(obj, 'x'); // 引用错误:x未定义 如何更改最后一行以通过变量名获取值?

澄清
“x” - 在某个obj上下文中的任何表达式,可能不是obj参数

原始问题

/**
 * Guards 'this' when delegating method as a callback to others. Arguments aren't known beforehand and will be provided by consumer.
 */
delegate = function(context, func) {
    return function() {
        var args = [];
        for ( var i = 0; i < arguments.length; i++)
            args.push(arguments[i]);
        func.apply(context, args);
    };
};

reference = function (context, 'expression to evaluete to get reference value') {
    ... TODO
};

'delegate' - 委托函数调用,如何“委托引用”并在不同的上下文中“取消引用”?

更新
有两种使用eval的可能性:
1. eval.call(null, '在全局上下文中评估表达式');
2. eval('在调用eval函数的上下文中评估表达式')
3. 如何在一些预定义的“上下文”中进行评估?

我想要模仿C++引用,当你可以将它放置在任何上下文中并且“取消引用”以获得值(但是在您取消引用它时,值可能已更改,您应该获得新值)。就像在javascript中,您将对象作为函数参数放置,随时获取obj.someproperty即可获取最新的someproperty值(如果已更改)。但是,当您尝试传递原始类型或整个对象被其他内容更改时,这将无法正常工作。如何将对“整个对象”的“引用”传递给其他上下文?

我清楚地了解了我想要什么 :)
javascript如何创建引用

我所寻找的内容:

createReference = function(context, prop) {
    return function() {
        return context[prop];
    };
};

Provider = function() {
};
Provider.prototype.x = 5;
Provider.prototype.getXRef = function() {
    return createReference(this, 'x');
};
Provider.prototype.incrementX = function() {
    this.x = this.x + 1;
};

var provider = new Provider();
var refX = provider.getXRef();
provider.incrementX();
alert(refX());

感谢Brianpeiris!

4
obj.xobj['x']有什么问题? - Felix Kling
7
我不确定你实际上想要实现什么,但你目前的方式是可怕的。退一步,解释一下你想用这种语法解决的问题(而不是试图弄清楚如何让这个语法起作用)。 - Quentin
1
@Mykhaylo:再次回到David的观点,你能更清楚地解释一下你想要实现什么吗?因为一定会有比eval更好的方法。 - T.J. Crowder
2
这里有一篇阅读材料:*全局 eval。有哪些选项?* - Gumbo
3
@Mykhaylo:您的“Original problem”代码并未解释您想要做什么。 delegate函数似乎完全不相关,因为它从未调用referencereference函数未提供足够的信息来解释为什么下面的几个答案都不是您要寻找的内容。 - T.J. Crowder
显示剩余6条评论
4个回答

5
这应该就可以了,无需使用eval函数:

var obj = {x: 2};
var value = obj['x'];

1
@NeXXeuS 如果你只有一个字符串,那该怎么办呢?换句话说,如果你只有var propertyName = 'x', obj = {x: 2};这两个变量,你就无法使用obj.propertyName(显然不行)。 - brianpeiris

4

更新:我现在可能明白了,至少我有两个猜测。请参见下面的更新1更新2


原始答案

你几乎永远不需要使用eval。但是只是让你知道,你并不孤单,有很多人认为你必须使用eval来实现这个功能。其实比那更简单。

如果你想访问对象中的属性,可以使用点表示法(obj.x)或括号表示法(obj['x'])。注意后者中的引号:所有属性名都是字符串,而括号表示法允许我们在查找属性时使用实际的字符串。所以给定这个对象:

var obj = {foo: 42};

所有这些都将42放入x中:

x = obj.foo;
x = obj['foo'];
x = obj['f' + 'o' + 'o'];
y = 'foo'; x = obj[y];   // Using the "foo" string from variable `y`
x = obj[getTheAnswer()]; // Using the return value of a function (`getTheAnswer` returns "foo")

正如您所见,您可以使用任何表达式来命名属性(作为字符串),然后在括号中使用该属性名称字符串。


更新 1: 在您的reference函数中,如果您确实想要接受一个包含您不知道任何信息的表达式的字符串,评估该字符串,并使用结果查找对象上的属性,那么这就是您应该做的 - 我想明确指出,我强烈建议以不同的方式解决这个问题,但是如果不了解实际问题,我无法说出如何解决。所以这就是:

var reference = function(context, expressionString) {
    return context[eval(expressionString)];
};

例如:

因此,举个例子:

var obj = {p5: 42};
alert(reference(obj, "'p' + (4 + 1)")); // alerts 42

实时示例

如果我猜错了,敬请谅解。


更新2:

从您同时提到 delegatereference,以及注释中的"...如何在不同的上下文中'委托引用'并有可能'取消引用'?..." 可以看出,您正在尝试找到一种方法来查找原始函数,即使您只有委托。例如:

function foo() { ... }
var fooDelegate = delegate(someObject, foo);
var original = reference(someObject, fooDelegate);
alert(original === foo); // alerts true

如果您想要做的就是这样,那么您无法在没有在“delegate”中设置某些内容并在稍后在“reference”中查找它的情况下完成。幸运的是,这很容易:
// Create a function that, when called, will always call the given
// function with the given context, passing along the call arguments.
delegate = function(context, func) {
    var newFunc = function() {
        return func.apply(context, arguments);
    };
    newFunc.__delegate__original = func;
    return newFunc;
};

// If given a function created by `delegate`, returns the original
// underlying function. If the given function is not from `delegate`,
// returns `func` unchanged.
reference = function(func) {
    return func.__delegate__original || func;
};

请注意,在reference上不需要使用context参数。
如果我猜错了,请再次道歉。
离题一下:关于你的delegate函数,你会很高兴知道,在将它们传递到apply之前,你不需要复制arguments。(但你可能想返回目标函数的返回值。)这在跨平台实现中也可以正常工作。
delegate = function(context, func) {
    return function() {
        return func.apply(context, arguments);
    };
};

由于规范中仔细定义了apply以允许任何类似数组的对象,因此它并不需要实际的Array实例。有关详细信息,请参见规范第15.3.4.3节


+1 对于 42,但是 getTheAnswer() 不应该返回 42 吗?(开玩笑 ;)) - Felix Kling
由于参数不是数组而是对象,它在我的IE浏览器中似乎无法工作。 - Mike
@Mykhaylo:一定是其他问题,它在IE上运行良好,甚至可以回溯到IE6:http://jsbin.com/usexo3 - T.J. Crowder
@T.J. Crowder 做得好,我认为你实际上理解了他的意思 :) - brianpeiris
@Mykhaylo: "感谢你的帮助"。很高兴能帮忙,没关系。我得走了,但我已经添加了第二个猜测答案。无论如何,祝你好运。 - T.J. Crowder

1

为了扩展@brianpeiris的答案,您可以在运行时动态地决定要从对象中读取哪个参数。例如:

var obj = {x: 2);
var field = 'x'; // or do some other operation to figure out the field you want
var value = obj[field];
if (value) {
  // the field exists and has a true value
} 

0

或者,如果你非常需要使用 eval:

var obj = {x : 2};
var myVar = eval(obj.x);
alert(myVar);

有点过度了,我知道。


2
我认为这并不有用。如果他可以调用 obj.x,那么就没有必要使用 eval - Felix Kling
是的,那是一个糟糕的答案,我应该感到难过。 - Justin Pearce

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接