Making 'this' refer to an object

I

Ivo

How do I make the magic 'this' variable refer to an object of my choice, in
a string of code which is to be eval'ed?
Say, I have an object, an array with four elements:

var myobject = [1,2,3,4];

and a string of Javascript:

var mystring = 'alert(this.length)';

When I interpret mystring, I want 'this' to refer to myobject, and get
alerted "4". I have tried:

with( myobject ) { eval( mystring ); }
and
eval( 'with( myobject ) { ' + mystring + ' }' );

but it gives me the length of the window, "0", as if 'this' is not set where
I want it. Variations on the theme have all the same result.
A clumsy solution is to replace the actual occurances in the string:

eval( mystring.replace( /this/g, 'myobject' ) );

That works for simple strings, but I am not sure about more demanding
statements with complex references.
Even more clumsy is using the prototype to add a method:

myobject.constructor.prototype.eva = function( s ) { eval(s); };
myobject.eva( mystring );

Do all kinds of objects and elements have a constructor property which
allows such addition?

Hope I made the issue clear, all ideas appreciated,
Ivo
 
L

Lasse Reichstein Nielsen

Ivo said:
How do I make the magic 'this' variable refer to an object of my choice,

Generally, you call a function through its "call" method, i.e.,

myFunc.call(myThis, args)

It works as if the "myFunc" function was called as a method on
the "myThis" object. If "call" is not implemented, you can make
the function an actual method of the object:

myThis.__secretMethod__ = myFunc;
myThis.__secretMethod__(args);

but that's obviously ugly :)
in a string of code which is to be eval'ed?

User provided at runtime? Then you don't have a function, so you must
create one yourself.
var myobject = [1,2,3,4]; ....
var mystring = 'alert(this.length)';

Try:
(function(){return eval(mystring);}).call(myobject)

or if you don't care about the return value:

Function(mystring).call(myobject)


You can't just use the immediate idea:
eval.call(myobject, mystring)
because the eval function is not required to work as a method
of anything but the global object, and indeed, in some implementations
it doesn't (it doesn't work in Firefox, and probably not in some
other browsers too).

with( myobject ) { eval( mystring ); }

"with" does not change the "this" reference, it just adds a layer
to the scope resolution chain.

myobject.constructor.prototype.eva = function( s ) { eval(s); };

or just
myobject.eva = function(s) { eval(s); }

No need to pollute the prototype
myobject.eva( mystring );
Do all kinds of objects and elements have a constructor property which
allows such addition?

Probably. Host objects doesn't need to follow rules, but many do.
Language objects like arrays will work, but you don't want to pollute
their prototype. Adding to Array.prototype will make code like
for (var i in myArray) { ... myArray ... }
also count the additions.

/L
 
M

michael elias

Hi,

Try avoiding eval(), it's a bad habit using it. If you want to execute
code that is created dynamically during run-time, create a new Function
object.

var fFunction = new Function([arg1, [arg2, [arg3...
[sFunctionBody]]]]);

to call your new function in the scope of a certain object use apply()
or call().

var oObj = new MyObject();
fFunction.call(oObj[arg1 [, arg2 [, arg3...]]]);
or
fFunction.apply(oObj [, aArgArray]);
 
R

rh

Lasse said:
Ivo said:
How do I make the magic 'this' variable refer to an object of my choice,

Generally, you call a function through its "call" method, i.e.,

myFunc.call(myThis, args)

[..]


User provided at runtime? Then you don't have a function, so you must
create one yourself.
var myobject = [1,2,3,4]; ...
var mystring = 'alert(this.length)';

Try:
(function(){return eval(mystring);}).call(myobject)

or if you don't care about the return value:

Function(mystring).call(myobject)


You can't just use the immediate idea:
eval.call(myobject, mystring)
because the eval function is not required to work as a method
of anything but the global object, and indeed, in some implementations
it doesn't (it doesn't work in Firefox, and probably not in some
other browsers too).

Right, but that simply lends even more weight to the general
anathematic (enematic ;-)) reaction to almost every conceived usage of
eval.

Were it me in this circumstance, I'd be inclined to use something in
the nature of:

String.prototype.exe = function () { return new Function(this); };

var myobject = [1,2,3,4];
var mystring = 'alert(this.length)';
mystring.exe().call(myobject);

[...]

../rh
 
V

VK

Ivo said:
How do I make the magic 'this' variable refer to an object of my choice, in
a string of code which is to be eval'ed?


'this' is not magic but indeed may be confusing. 'this' is always set
to the current execution context. This definition puts right away your
question under the right andgle: "How to switch / freese a given
execution context?" (because you cannot *set* 'this' to something, it's
not some var a = 0;)

1) In the "free floating form" 'this' always points to the window where
the current code is executing.

2) In the intrinsic handlers 'this' points to the control captured the
event:
<imput type=... onclick="alert(this.tagName)...

3) You can *freese* the above state by using closures in anonymous
functions:
someFormControl.onclick = function(){alert(this.tagName);}
Suppose to be a bad practice though because of potential memory
leaking.

4) In class constructors 'this' refers to the object instance the
constructor is in the process of creating:

var Joe = new Employee('Joe','Doe',5000);

function Employee(FirstName,LastName,Salary) {
// all accross this conctructor
// 'this' refers to that Joe
// you're creating
this.FirstName = FirstName;
this.LastName = LastName;
this.Salary = Salary;
}


Sometimes you need to extend an existing constructor for new data
types. That would be a hell to copy constructors under different names
over and over again just for few changes. This is why OOP has such
great thing as inheritance. If you say have to add class Manager, and
it differes from Employee only bu the dapartment name, you simply do:

var Mary = new Manager('Mary','Smith',10000,'Public Relations');

function Manager(FirstName,LastName,Salary,Department) {
this.Department = Department;
Employee.call(this);
}

now

alert(John.Department); // undefined
alert(Mary.Department); // 'Public Relations'
alert(John instanceof Manager); // false, just a simple worker
alert(Mary instanceof Manager); // true

All above would be much easier to explain by using standard words
"class", "super class", "extends" etc. But as we have some taboo in
this group for such lexical freedom, I said it as I could.

Any way, your task should be rather clear now: instead of "hacking"
'this', you have to place it into the right OOP context and it will fly
by itself.
 
V

VK

A RUDE MUSTAKE IN MY CODE!

Method call() requires to spell all arguments your forward to the super
class. In the sample from the prev. posting Mary's name etc will be
lost!

To forward all available arguments to the cuper class w/o spelling each
one of them you use apply method.

So the proper Manager constructor is:

function Manager(FirstName,LastName,Sal­ary,Department) {
this.Department = Department;
Employee.apply(this, arguments);
}
 
L

Lasse Reichstein Nielsen

michael elias said:
Try avoiding eval(), it's a bad habit using it. If you want to execute
code that is created dynamically during run-time, create a new Function
object.

I see no advantage of using "Function" over "eval". If one is evil (as it
is) so is the other.

/L
 
R

rh

Lasse said:
I see no advantage of using "Function" over "eval". If one is evil (as it
is) so is the other.

But then, evil is as evil does.

I've yet to see a "Function" used as a substitute for a lack of
knowledge of property accessor square bracket notation, and that is the
source for much of the "eval" revilement.

It's simply too easy for a novice programmer to pick up "eval" and use
it in the language, usually to their own (and other's) futility and
detriment. In that regard, and not exclusively so, the two are far from
equivalent on the scale of evils.

I think the recommendation to avoid "eval", and to use a "Function"
where necessary/appropriate, is a good one!

../rh
 

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

Forum statistics

Threads
473,780
Messages
2,569,610
Members
45,254
Latest member
Top Crypto TwitterChannel

Latest Threads

Top