开发者

javascript eval how to

var obj = {x : 2}; eval.call(obj, 'x'); // ReferenceError: x is not defined How to change last line to get value by variable name?

Clarification

'x' - any expression in some obj context, possibly not a obj parameter

Original problem

/**
 * Guar开发者_运维问答ds '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' - delegates function call, how to 'delegate a reference' with possibility to 'dereference' in different context?

Updates

here is 2 possibilities to use eval:

1. eval.call(null, 'evaluate expression in global context');

2. eval('evaluate expression in context where eval function was called')

3. how to eval in some predefined 'context' ?

I want to mimic C++ reference when you can put it in any context and 'dereference' to value (but when in moment you dereference it value could be changed and you should get new value). Like in javascript you put object as function argument and anytime you get obj.someproperty you'll get newest someproperty value (if it was changed). But this will not work when you will try to pass a primitive or what if whole object will be changed by some other. How to 'pass a reference' to 'whole object' to some other context?

Got clear understanding what I want :)

javascript how to create reference

What I was looking for:

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());

Tanks Brianpeiris!


This should do it, no need for eval:

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


Update: I may understand now, or at least I have two guesses. See Update 1 and Update 2 below.


Original answer:

You almost never need eval. But just so you know, you're not alone, there are a lot of people who think you have to use eval for this. It's actually a lot easier than that.

If you want to access a property in an object, you can use either dotted notation (obj.x) or bracketed notation (obj['x']). Note the quotes in the latter: All property names are strings, and the bracket notation lets us use actual strings when looking up properties. So given this object:

var obj = {foo: 42};

all of these put 42 in 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")

As you can see, you can use any expression to come up with the name of the property (as a string), and then use that property name string in the brackets.


Update 1: In your reference function, if you literally want to accept a string containing an expression you know nothing about, evaluate the string, and use the result to look up a property on the object, here's how you do that — I want to be clear that I would strongly recommend solving this problem a different way, but without knowing more about the actual problem, I couldn't say how. So here it is:

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

So for example:

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

Live example

Apologies if I've guessed wrong.


Update 2:

From the fact that you're giving delegate and reference together, and the comment "... how to 'delegate a reference' with possibility to 'dereference' in different context?..." it sounds like you're trying to find a way to find out what the original function was, if you only have the delegate. E.g.:

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

If that's what you're trying to do, you can't do it without setting something up in delegate that you later look for in reference. Fortunately, that's easy:

// 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;
};

Note that you don't need the context parameter on reference.

And again, apologies if I'm guessing wrong.


Off-topic: Re your delegate function, you'll be glad to know that you don't have to copy the arguments before you pass them into apply. (You do probably want to return the return value of the target function, though.) This works fine cross-implementation:

delegate = function(context, func) {
    return function() {
        return func.apply(context, arguments);
    };
};

...because apply is carefully defined in the specification to allow any array-like object, it doesn't require an actual Array instance. See Section 15.3.4.3 of the spec for details.


To extend @brianpeiris's answer, you can decide what parameter you want to read from the object dynamically, at runtime. For example:

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
} 


Or, if you absolutely have to use eval:

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

Overkill, I know.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜