Runtime Instance Name without using eval()

D

Darren Satkunas

I'm looking for a way to create a new instance of a Javascript Object
and assign it to an instance name that is determined at runtime. Is
there a way to do this without using the dreaded eval() function shown
below?

function MyObj(value){
this.value = value;
}
//use a static instance name
var Obj1 = new MyObj('abc');
console.log(Obj1.value);

//using a dynamic instance name
var runtimeInstanceName = 'Obj2'; //assume this string is determined
at runtime
eval(runtimeInstanceName+" = new MyObj('def');");
console.log(Obj2.value);
 
D

Dmitry A. Soshnikov

I'm looking for a way to create a new instance of a Javascript Object
and assign it to an instance name that is determined at runtime. Is
there a way to do this without using the dreaded eval() function shown
below?

function MyObj(value){
        this.value = value;}

//use a static instance name
var Obj1 = new MyObj('abc');
console.log(Obj1.value);

//using a dynamic instance name
var runtimeInstanceName = 'Obj2'; //assume this string is determined
at runtime
eval(runtimeInstanceName+" = new MyObj('def');");
console.log(Obj2.value);

If base object is known, in general case it looks like:

someObject[runtimeInstanceName] = new MyObj('def');

In case of global context, you can use `window` object to manages this
case (or, if exactly in global context - `this` keyword):

window[runtimeInstanceName] = new MyObj('def');
console.log(Obj2.value);

/ds
 
D

Darren Satkunas

I'm looking for a way to create a new instance of a Javascript Object
and assign it to an instance name that is determined at runtime. Is
there a way to do this without using the dreaded eval() function shown
below?
function MyObj(value){
        this.value = value;}
//use a static instance name
var Obj1 = new MyObj('abc');
console.log(Obj1.value);
//using a dynamic instance name
var runtimeInstanceName = 'Obj2'; //assume this string is determined
at runtime
eval(runtimeInstanceName+" = new MyObj('def');");
console.log(Obj2.value);

If base object is known, in general case it looks like:

someObject[runtimeInstanceName] = new MyObj('def');

In case of global context, you can use `window` object to manages this
case (or, if exactly in global context - `this` keyword):

window[runtimeInstanceName] = new MyObj('def');
console.log(Obj2.value);

/ds

Thanks Dmitry, works like a charm.

I didn't realize that `window` could be used as a reference to the
global scope.
 
A

Asen Bozhilov

Darren said:
I'm looking for a way to create a new instance of a Javascript Object
and assign it to an instance name that is determined at runtime. Is
there a way to do this without using the dreaded eval() function shown
below?
//using a dynamic instance name
var runtimeInstanceName = 'Obj2'; //assume this string is determined
at runtime
eval(runtimeInstanceName+" = new MyObj('def');");

When been evaluate eval, will be defined property of Global Object.
See in ECMA 262-3 11.2.1 Property Accessors and from FAQ <URL:
http://www.jibbering.com/faq/#propertyAccessAgain >
 
T

Thomas 'PointedEars' Lahn

Darren said:
Dmitry A. Soshnikov said:
In case of global context, you can use `window` object to manages this
case (or, if exactly in global context - `this` keyword):

window[runtimeInstanceName] = new MyObj('def');
console.log(Obj2.value);
[...]

Thanks Dmitry, works like a charm.

It works by coincidence only; it tests positive only because of superficial
testing. It would not work so well if `runtimeInstanceName' happened to
store the name of a property of this Window instance that was implemented
read-only or had a significant meaning (e.g., `innerWidth' in Gecko-based
browsers; `window["innerWidth"] = new Object();' just managed to reduce the
width of my Iceweasel 3.5.5 browser window to about 20 pixels, while reading
it back yielded 474 [pixels]). DO NOT do this.
I didn't realize that `window` could be used as a reference to the
global scope.

First of all, you would not be referencing the/a scope (it cannot be
referenced), but the Variable Object of the global execution context, the
global object.

However, `window' fails in doing that, it refers to a Window instance (that
may have the ECMAScript Global Object in its prototype chain). As the first
page of the JavaScript 1.5 Reference says:

<https://developer.mozilla.org/en/Core_Javascript_1.5_Reference>
| The global object itself can be accessed by `this' in the global scope.

(whereas `scope' should read `execution context' there; objections?)

Assign it to a variable (I used `_global') or property (I am switching to
jsx.global) when needed in a local execution context.


PointedEars
 
D

Dmitry A. Soshnikov

If base object is known, in general case it looks like:
someObject[runtimeInstanceName] = new MyObj('def');
In case of global context, you can use `window` object to manages this
case (or, if exactly in global context - `this` keyword):
window[runtimeInstanceName] = new MyObj('def');
console.log(Obj2.value);

Thanks Dmitry, works like a charm.

But if you need to declare a local variable of some function context,
you still have to use `eval`, as there's no ability to access the
activation object (which stores declared variable) of the function
context.
I didn't realize that `window` could be used as a reference to the
global scope.

In general, `window` property would be enough (regardless specific
implementation as it's a host object), but actually, as I mentioned
above, in the global context, `this` keyword references to the global
object. So you can do something like this in the global context:

this[runtimeInstanceName] = new MyObj('def');

If you're sure that `window` name isn't hidden by some local variable
(e.g. in some function `var window = 10;`), you can normally use it to
manage your case.
 
A

Asen Bozhilov

Dmitry said:
But if you need to declare a local variable of some function context,
you still have to use `eval`, as there's no ability to access the
activation object (which stores declared variable) of the function
context.

Dmitry that isn't only approach to declare *local* variable. He cans
put in the front of the scope chain `object' which haves property for
instance name using `with' statement:

function testFn()
{
with({'instance_name' : new Foo()})
{
window.alert(instance_name);
}
};

`with' statement put on the front of Scope Chain reference to `object'
which have property `instance_name'. Resolving properties against
Scope Chain here is interesting part.

Global Object <- Global execution context
^
AO/VO <- `testFn'
^
Object -> Object.prototype -> null

So here first property will be resolved from Prototype chain. If in
Prototype chain doesn't exist property with that name, will be
*searching* in the next `object' in Scope Chain.
 
T

Thomas 'PointedEars' Lahn

Asen said:
Dmitry that isn't only approach to declare *local* variable.

In fact, using eval() is probably the most risky approach to declare a
variable, local or otherwise. Have you ever heard of code injection?
Not everything that can be done should be done.
He cans put in the front of the scope chain `object' which haves property
for instance name using `with' statement:

That is _not_ a declaration, let alone a variable declaration.


PointedEars
 
D

Dmitry A. Soshnikov

Dmitry that isn't only approach to declare *local* variable. He cans
put in the front of the scope chain `object' which haves property for
instance name using `with' statement:

function testFn()
{
    with({'instance_name' : new Foo()})
    {
        window.alert(instance_name);
    }

};

`with' statement put on the front of Scope Chain reference to `object'
which have property `instance_name'. Resolving properties against
Scope Chain here is interesting part.

Global Object <- Global execution context
    ^
  AO/VO <- `testFn'
    ^
Object -> Object.prototype -> null

So here first property will be resolved from Prototype chain. If in
Prototype chain doesn't exist property with that name, will be
*searching* in the next `object' in Scope Chain.

Yeah, thanks Asen, I sure know about `with` statement affecting on the
scope chain. But that isn't variable declaration.

Regarding prototype chain analysis, yep this affect also can be seen
in some versions of Spidermonkey for named function expressions (NFE),
when special object is created by specification "as by new Object()",
and also for in some other implementations when activation object
inherits from `Object.prototype`.

/ds
 
A

Asen Bozhilov

That is _not_ a declaration, let alone a variable declaration.

Absolutely right. I make little error when i write previous post. In
previous post I want to write:

Dmitry that isn't only approach to "declare" local variable.

But i catch that after submit.
Apologize.
 
T

Thomas 'PointedEars' Lahn

Asen said:
Absolutely right. I make little error when i write previous post. In
previous post I want to write:

Dmitry that isn't only approach to "declare" local variable.

But your variant of the `with' approach does not solve the problem of using
an identifier defined at runtime without using eval() either (using a
writing bracket property accessor to add the property of the object inserted
in the scope chain would), nor would it be necessary (the reading bracket
property accessor would suffice).


PointedEars
 
D

Dmitry A. Soshnikov

[...]
Dmitry that isn't only approach to "declare" local variable.

What exactly do you mean? The only way to declare variable is to use
`var` keyword. If to summarize points which could be related to
`variable` (regardless syntax rules such as `VariableStatement` -
12.2, ES-3) we can get the following:

(1) affecting on the VO/AO;
(2) created on entering execution context (main sign);
(3) get {DontDelete} attribute unless type of code is `eval`.

The point (1) is used to show that not every named object is affected
on VO/AO, e.g. named function expression (NFE) which by specification
should keep optional identifier in special object added in front of
scope chain but not in VO/AO itself; but as you know there're some non-
conformant impementations as some versions of JScript, including
current version.

The point (2) I suggest to use as a main sign to distinguish them from
the properties added to the special object of `with` statement and
`catch` clause. The two last will be available in the scope chain at
runtime, but not right after entering the execution context.

Moreover, regarding `with`, it doesn't declare that properties of its
special object should have {DontDelete} attributes, it depends on
object itself. So, in simple case we can delete this property:

with ({a: 10}) {
alert(typeof a); // number
delete a;
alert(typeof a); // undefined
}

But we can't if properties already have {DontDelete}

var a = 10;
with (this) {
alert(typeof a); // number
delete z; // error in JScript
alert(typeof a); // number, as `a` has {DontDelete}
}

From the other hand, not every variable declaration should get
{DontDelete} as it depends on type of code - in `eval` code they
shouldn't get {DontDelete}, so this point (3) is not the main.

But about point (2) regarding to execution context of function code
type, formal parameters also should get {DontDelete} depending on
code's type. So from this point of view formal parameters are the same
as variables - they created on entering execution context and should
have {DontDelete} depending on type of the code. But in difference
from variables, formal parameters get values (if corresponding values
are passed) also on entering the execution context, meanwhile variable
always get `undefined` on this step.

Regarding {DontDelete} and function's formal parameters, there's non-
conformant issue in Chrome - it doesn't set {DontDelete} in this case.

function test(a, b) {
alert([typeof a, typeof b]); // number, number

delete a;
delete arguments[1];

// undefined, undefined - in Chrome
// number, number - in other
alert([typeof a, typeof b]);
}

Also, regarding property of special object added by `catch` clause,
current version of Opera doesn't set {DontDelete} to it.

try {
trow 'error';
} catch (e) {

alert(typeof e); // string

delete e;

// undefined - in current Opera
// string - in other
alert(typeof e);
}

So, summarizing this all, variable is: added to the VO/AO on entering
the execution context (that differs it from other properties) and
_always_ has `undefined` value on this step (that differs it from the
formal parameter, which can have value any, but not only `undefined`
on this step).

What other approaches to "declare" local variable did you mean?

/ds
 
A

Asen Bozhilov

Thomas 'PointedEars' Lahn said:
But your variant of the `with' approach does not solve the problem of using
an identifier defined at runtime without using eval() either (using a
writing bracket property accessor to add the property of the object inserted
in the scope chain would), nor would it be necessary (the reading bracket
property accessor would suffice).

That isn't true. That property will be resolve not only from Prototype
Chain. That property will be resolve from Prototype Chain and Scope
Chain, that can be benefit in some cases. Of course that is point of
view and what exactly want to do it. If i write sometime code like
this. Maybe i'll be use just only one object without modified Scope
Chain with `with' statement.
 
A

Asen Bozhilov

Dmitry said:
What exactly do you mean? The only way to declare variable is to use
`var` keyword.

I m not going to assert another thesis.
If to summarize points which could be related to
`variable` (regardless syntax rules such as `VariableStatement` -
12.2, ES-3) we can get the following:

(1) affecting on the VO/AO;
(2) created on entering execution context (main sign);
(3) get {DontDelete} attribute unless type of code is `eval`.

The point (1) is used to show that not every named object is affected
on VO/AO, e.g. named function expression (NFE) which by specification
should keep optional identifier in special object added in front of
scope chain but not in VO/AO itself; but as you know there're some non-
conformant impementations as some versions of JScript, including
current version.

Of course but, using indirect call of `eval' at the moment you can be
sure to defined local variable, because `eval' use VO of calling
execution context.
ECMA 262-3

| 10.2.2 Eval Code
| Variable instantiation is performed using the calling context's
| variable object and using empty property attributes.

But in ECMA 5 in strict mode you cannot be create local variable using
indirect call of `eval'

| 10.4.2.1 Strict Mode Restrictions
| The eval code cannot instantiate variable or
| function bindings in the variable environment of the calling
| context that invoked the eval if either the code
| of the calling context or the eval code is strict code. Instead
| such bindings are instantiated in a new
| VariableEnvironment that is only accessible to the eval code.
The point (2) I suggest to use as a main sign to distinguish them from
the properties added to the special object of `with` statement and
`catch` clause. The two last will be available in the scope chain at
runtime, but not right after entering the execution context.

`eval' defined properties of VO runtime too.
Moreover, regarding `with`, it doesn't declare that properties of its
special object should have {DontDelete} attributes, it depends on
object itself. So, in simple case we can delete this property:

with ({a: 10}) {
  alert(typeof a); // number
  delete a;
  alert(typeof a); // undefined

}

No, here depend from internal attribute {DontDelete} of property which
want to deleted.

So, summarizing this all, variable is: added to the VO/AO on entering
the execution context (that differs it from other properties) and
_always_ has `undefined` value on this step (that differs it from the
formal parameter, which can have value any, but not only `undefined`
on this step).

Yes. I know all of that. I want to give just another example to create
property which:

- Resolve from Scope Chain.
- Doesn't has any reference to that property in normal case after
`with' statement.
What other approaches to "declare" local variable did you mean?
Should be know? :)

Regards.
 
T

Thomas 'PointedEars' Lahn

Asen said:
That isn't true. That property will be resolve not only from Prototype
Chain. That property will be resolve from Prototype Chain and Scope
Chain, that can be benefit in some cases. Of course that is point of
view and what exactly want to do it. If i write sometime code like
this. Maybe i'll be use just only one object without modified Scope
Chain with `with' statement.

Either you misunderstood what the OP was asking or you misunderstood
what I was replying. The OP was (also) looking for an alternative to

function foo(runtimeInstanceName)
{
eval("var " + runtimeInstanceName + " = new Foo();");
}

foo("bar");

to have the equivalent of

function foo()
{
var bar = new Foo();
}

Your suggestion,

with ({'instance_name' : new Foo()})

does not help to solve this problem because if you wrote

function foo(runtimeInstanceName)
{
with ({runtimeInstanceName: new Foo()})
{
bar;
}
}

foo("bar");

that would be the equivalent of

function foo()
{
with ({runtimeInstanceName: new Foo()})
{
/*
* ReferenceError, unless Object.prototype
* provides a 'bar' property
*/
bar;
}
}

You could write

function foo(runtimeInstanceName)
{
var o = {};
o[runtimeInstanceName] = 'bar';

with (o)
{
// ...
}
}

But then you would not need the `with' statement in the first place as
`o[runtimeInstanceName]' is readily available for read access and it is no
longer a matter of declaring anything.


PointedEars
 
D

Dmitry A. Soshnikov

Dmitry A. Soshnikov wrote:

[...]
If to summarize points which could be related to
`variable` (regardless syntax rules such as `VariableStatement` -
12.2, ES-3) we can get the following:
(1) affecting on the VO/AO;
(2) created on entering execution context (main sign);
(3) get {DontDelete} attribute unless type of code is `eval`.
The point (1) is used to show that not every named object is affected
on VO/AO, e.g. named function expression (NFE) which by specification
should keep optional identifier in special object added in front of
scope chain but not in VO/AO itself; but as you know there're some non-
conformant impementations as some versions of JScript, including
current version.

Of course but, using indirect call of `eval' at the moment you can be
sure to defined local variable, because `eval' use VO of calling
execution context.
ECMA 262-3

| 10.2.2 Eval Code
| Variable instantiation is performed using the calling context's
| variable object and using empty property attributes.

But in ECMA 5 in strict mode you cannot be create local variable using
indirect call of `eval'

| 10.4.2.1  Strict Mode Restrictions
| The eval code cannot instantiate variable or
| function bindings in the variable environment of the calling
| context that invoked the eval if either the code
| of the calling context or the eval code is strict code. Instead
| such bindings are instantiated in a new
| VariableEnvironment that is only accessible to the eval code.

Yeah, thanks, I know that.
`eval' defined properties of VO runtime too.

Yes, but formal parameter is also created on entering execution
context. So, the main sign (if do not use combination of "created on
entering context" + "always has `undefined` value") is - _always_ has
`undefined` value on entering the context. Any other entities
affecting on VO/AO do not require this condition (formal parameters,
repeat, have values if values are passed).
No, here depend from internal attribute {DontDelete} of property which
want to deleted.

Didn't I say the same? I said - from difference of `var` (not in
`eval` context) special object of `with` statement doesn't require
that all of it's properties should have {DontDelete}. So, {DontDelete}
was related sure to properties of the object, but not the object
itself ;)

/ds
 
D

Dmitry A. Soshnikov

[...]
[[Prototype]] of AO/VO could also refer to `Object.prototype` here,
since ES3 implicitly permits it (and some implementations, e.g.
Blackberry browser, do implement it that way).

Yep, "implicitly" here is the main word which can serves as
justification. Funny, but yep, ECMA-262-3 doesn't say anything about
Activation object - should it be some special internal object, or
should it be simple object `as by new Object` or anything else? So
Blackberry didn't think much here and used simple object which
inherits from `Object.prototype`. Regarding special object for
optional identifier of NFE, Spidermonkey doesn't break the rules as
they did it conforming to the specification where is written: 'as by
new Object', so this is "error" of specification, thought, other
implementations fix this editorial error, as the guessed to do with
Activation object (in difference from Blackberry) - do not set
prototype to it at all, or at least not inherit from
`Object.prototype` ;)

/ds
 
D

Dmitry A. Soshnikov

Dmitry A. Soshnikov wrote:
[...]
What exactly do you mean? The only way to declare variable is to use
`var` keyword. If to summarize points which could be related to

I guess it would depend on what exactly you mean by "to declare a
variable", but I would say that function declaration "declares a
variable" too ;)

I suggest to take for a basis 10.1.3, ES-3 section. The main
difference of `var` (not of `eval` code) from other (FD and formal
parameters) is that `var` _always_ has `undefined` value on entering
execution context stage. FD have concrete value, formal parameters
also can have values if they passed.

/ds
 
D

Dmitry A. Soshnikov

[...]
`eval' defined properties of VO runtime too.

And, btw, forgot - although `eval` affecting on VO/AO of calling
context at runtime, if to analyze exactly execution _context_ stuff,
`eval` code also creates its own context inheriting from calling
context needed things such as VO/AO, `this` value and scope chain. But
still variable instantiation regarding to the `eval` context itself is
also takes place, which means again - `var`s will be created on
entering the context and _always_ initialize with `undefined` value:

function test() {
alert(a); // ReferenceError, "a" is not defined
eval('alert(a); var a = 10; alert(a);'); // undefined, 10
}

So regardless the calling context from which point of view it's a
runtime, the `eval`'s context has two stages also - entering the
context and runtime from which point of view `var` - is `var`, except
that variable instantiation has empty attributes for the properties of
VO/AO - for both: `FD`s and `var`s.

/ds
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top