Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Javascript > Getting the 'this' scope of the caller

Reply
Thread Tools

Getting the 'this' scope of the caller

 
 
Phrogz
Guest
Posts: n/a
 
      10-11-2006
I'm trying to write an 'each' function for a JavaScript array that
behaves like Ruby's Array#each. (It doesn't matter if you know Ruby to
help with this question.)

My problem is the scope of 'this' inside the iterator callback. I would
like it to be the same as the object that called the each() on the
array. Right now I have to do that with a closure or an
explicitly-passed 'this' scope. For example:

function Person( inName, inCats ) {
this.name = inName;
this.cats = inCats;
}

// Using a closure
Person.prototype.showInfo = function( ) {
var me = this;
this.cats.each( function( catName ){
alert( me.name + " owns " + catName );
} );
}

Array.prototype.each = function( inCallback ){
for ( var i=0,len=this.length; i<len; ++i ){
inCallback( this[ i ], i );
}
}

phrogz = new Person( 'Gavin', [ 'Fuzzles', 'Kitty' ] );
phrogz.showInfo( );
--> Gavin owns Fuzzles
--> Gavin owns Kitty


// Using an explicit scope
Person.prototype.showInfo = function( ) {
this.cats.each( this, function( catName ){
alert( this.name + " owns " + catName );
} );
}

Array.prototype.each = function( inScope, inCallback ){
for ( var i=0,len=this.length; i<len; ++i ){
inCallback.call( inScope, this[ i ], i );
}
}


Inside the each() function, arguments.callee.caller would give me a
reference to the showInfo function object. What I am looking for is a
way to access the scope of the 'this' receiver within that particular
invocation of showInfo(), so that I can use it in place of inScope
without having to pass 'this' each call.


Thanks in advance for any help!

 
Reply With Quote
 
 
 
 
Phrogz
Guest
Posts: n/a
 
      10-11-2006
I forgot to add (in case it matters): this is being executed by (a
slightly modified version of) the SpiderMonkey runtime. And no, I don't
have ability to change the runtime to add this capability.

 
Reply With Quote
 
 
 
 
VK
Guest
Posts: n/a
 
      10-11-2006

Phrogz wrote:
> I'm trying to write an 'each' function for a JavaScript array that
> behaves like Ruby's Array#each. (It doesn't matter if you know Ruby to
> help with this question.)


Actually it does help a lot: because it is difficult to help to write a
method w/o knowing its objectives. I've missed the rails of Ruby
but latest Gecko (including Firefox 1.5 or higher) has forEach method
added for Array. Please take a look at:
<http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEac h>
Is it what you want for all other UA's? If not then what is
missing/superfluous?

 
Reply With Quote
 
Phrogz
Guest
Posts: n/a
 
      10-11-2006
VK wrote:
> Phrogz wrote:
> > I'm trying to write an 'each' function for a JavaScript array that
> > behaves like Ruby's Array#each. (It doesn't matter if you know Ruby to
> > help with this question.)

>
> Actually it does help a lot: because it is difficult to help to write a
> method w/o knowing its objectives. I've missed the rails of Ruby
> but latest Gecko (including Firefox 1.5 or higher) has forEach method
> added for Array. Please take a look at:
> <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEac h>
> Is it what you want for all other UA's? If not then what is
> missing/superfluous?


What is listed there is what I have implemented (except that the order
of the callback/scope parameters are reversed).

What I would like is a forEach type method where the 'this' scope used
inside the callback is the same as the 'this' scope that was used to
invoke the forEach. For example:

G = {}
G.a = this;
myArray.each( function(){ G.b = this } );

I would like G.a===G.b

 
Reply With Quote
 
runsun pan
Guest
Posts: n/a
 
      10-12-2006
Phrogz wrote:
> G = {}
> G.a = this;
> myArray.each( function(){ G.b = this } );
>
> I would like G.a===G.b


I am still confusing (the above example seems to make it more
confusing).

Let met put it this way:

someone = new Person("abc", ['d','e'])
someone.cats.forEach( function() { alert(X)} )

You want X to be "someone", right?

That is, cats' this, but not forEach's this. Is that what you want ?

 
Reply With Quote
 
Phrogz
Guest
Posts: n/a
 
      10-12-2006
I am in turn confused by your example. :/

Let me try one more time:

function Person( inName, inCats ) {
this.name = inName;
this.cats = inCats;
}

Person.prototype.showCats = function( ) {
this.cats.each( function( catName ) {
alert( this.name + ' owns ' + catName );
} );
}

phrogz = new Person( 'Gavin', [ 'Fuzzles', 'Kitty' ] );
phrogz.showCats( );

I am hoping to find a way to write the Array.prototype.each() function
so that the above code outputs:
--> Gavin owns Fuzzles
--> Gavin owns Kitty

 
Reply With Quote
 
Michael Winter
Guest
Posts: n/a
 
      10-12-2006
Phrogz wrote:

[snip]

> function Person( inName, inCats ) {
> this.name = inName;
> this.cats = inCats;
> }
>
> Person.prototype.showCats = function( ) {
> this.cats.each( function( catName ) {
> alert( this.name + ' owns ' + catName );
> } );
> }
>
> phrogz = new Person( 'Gavin', [ 'Fuzzles', 'Kitty' ] );
> phrogz.showCats( );
>
> I am hoping to find a way to write the Array.prototype.each() function
> so that the above code outputs:
> --> Gavin owns Fuzzles
> --> Gavin owns Kitty


That isn't going to happen without modifying the showCats method, and
you've already posted the two most likely approaches.

If the each function is to be a method of the Array prototype object, it
is expected that the this operator will refer to an array (or at least
an object with a length property and numeric properties [0,length-1]).
The only other objects it can know about must either be in its scope
chain, or its argument list. The scope chain is fixed when the method is
created so that isn't an option, and if the argument list is
unacceptable then responsibility must fall to the callback to retain any
necessary information.

Mike
 
Reply With Quote
 
Phrogz
Guest
Posts: n/a
 
      10-12-2006
Michael Winter wrote:
> Phrogz wrote:
> > I am hoping to find a way to write the Array.prototype.each() function
> > so that the above code outputs:
> > --> Gavin owns Fuzzles
> > --> Gavin owns Kitty

>
> That isn't going to happen without modifying the showCats method, and
> you've already posted the two most likely approaches.


Thanks for the confirmation. I was hoping that there might be some
feature (in ECMAScript or SpiderMonkey specifically) that allowed you
to access the receiver that invoked a method as part of the call stack
browsing.

It's not altogether surprising that it doesn't exist, but would
certainly be nice in a situation like this. Oh well.

(It looks[1] like SpiderMonkey might have had this at one time as a
"__caller__" property, but it was yanked. It's not in my (older)
SpiderMonkey release, unfortunately.)

[1]
http://developer.mozilla.org/en/docs...unction:caller

 
Reply With Quote
 
Michael Winter
Guest
Posts: n/a
 
      10-12-2006
Phrogz wrote:

[snip]

> I was hoping that there might be some feature (in ECMAScript or
> SpiderMonkey specifically) that allowed you to access the receiver
> that invoked a method as part of the call stack browsing. It's not
> altogether surprising that it doesn't exist, but would certainly be
> nice in a situation like this. Oh well.


It's not entirely unusual, either: the issue also arises when attempting
to assign a method of some object as an event listener. When the
listener is invoked, the this operator will refer to the element to
which the listener is attached, not the object from which the listener
originated. The general solution is much the same: use a closure and
store a reference to the object in the scope chain of that function.

[snip]

Mike
 
Reply With Quote
 
VK
Guest
Posts: n/a
 
      10-12-2006

Phrogz wrote:
> What I would like is a forEach type method where the 'this' scope used
> inside the callback is the same as the 'this' scope that was used to
> invoke the forEach. For example:
>
> G = {}
> G.a = this;
> myArray.each( function(){ G.b = this } );
>
> I would like G.a===G.b


I'm not using prototype for such tricky things, and sure you are not
doing it to alert cats' names so depending on the real purpose it
can be not suitable. But withing the spelled requirements I would do it
this way (keeping all methods as static):


<html>
<head>
<title>Cats</title>
<meta http-equiv="Content-Type"
content="text/html; charset=iso-8859-1">
<script type="text/javascript">

function Person(inName, inCats) {
this.name = inName;
this.cats = inCats;
this.cats.each = each;
this.cats.context = this;
this.showCats = Person.showCats;
}

Person.showCats = function() {
this.cats.each(alertCat);
}

function each(fnCallBack) {
for (var i=0; i<this.length; i++) {
fnCallBack.call(this.context, this[i]);
}
}

function alertCat(catName) {
window.alert(this.name + ' has ' + catName);
}

phrogz = new Person('Gavin', ['Fuzzles', 'Kitty']);
phrogz.showCats();

</script>
</head>

<body>

</body>
</html>

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Create variables with caller scope Jari Williamsson Ruby 3 01-18-2008 12:37 PM
Scope - do I need two identical classes, each with different scope? ann Java 13 09-13-2005 03:07 AM
How do namespace scope and class scope differ? Steven T. Hatton C++ 9 07-19-2005 06:07 PM
IMPORT STATIC; Why is "import static" file scope? Why not class scope? Paul Opal Java 12 10-10-2004 11:01 PM
Can't get function caller if the caller is from a function within a popup window Mark Javascript 2 04-03-2004 07:57 AM



Advertisments