[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.javascript

Scope of "this" variable

Teemu Likonen

12/29/2015 7:35:00 PM

Code

var Item = function() {
this.variable = "variable";
this.fn1 = function() { return this.variable; };
this.foo = {
fn2: function() { return this.variable; }
};
};

var item1 = new Item();
console.log(item1.fn1());
console.log(item1.foo.fn2());

prints this:

"variable"
undefined

So function item1.fn1 returns the string "variable" but function
item1.foo.fn2 returns undefined. The variable "this" somehow disappears
(or doesn't last long enough) when a function object is created inside
another object {...}. Why?

I know a work-around:

var Item = function() {
this.variable = "variable";
this.fn1 = function() { return this.variable; };
var this_object = this;
this.foo = {
fn2: function() { return this_object.variable; }
};
};

But I'd like to understand why the first example works the way it does.
What's the difference between these to examples?

--
/// Teemu Likonen - .-.. <https://github.com/tl... //
// PGP: 4E10 55DC 84E9 DFF6 13D7 8557 719D 69D3 2453 9450 ///
9 Answers

ram

12/29/2015 8:29:00 PM

0

Teemu Likonen <tlikonen@iki.fi> did write:
>Subject: Scope of "this" variable

I look at the following example:

function Thing()
{ this.property = "property";
this.method = function() { return /*1*/ this.property; };
this.inner ={ method: function() { return /*2*/ this.property; }}; }

var thing = new Thing();

console.log( thing.method() );
console.log( thing.inner.method() );

»thing.method()« means »thing.method.call( thing )«.

Therefore, in the body of »method« (marked »/*1*/«), »this«
has the same value as »thing« has in the global scope.

And »thing« in the global scope has a property »property«.

»thing.inner.method()« means
»thing.inner.method.call( thing.inner )«.

Therefore, in the body of »method« (marked »/*2*/«), »this«
has the same value as »thing.inner« has in the global scope.

And »thing.inner« in the global scope has no property »property«.

However, you could evaluate

thing.inner.method.call( thing )

, which will yield »property«.

>Subject: Scope of "this" variable

It has more todo with the /value/ of »this« than with the
/scope/ of »this«.

Ben Bacarisse

12/29/2015 8:47:00 PM

0

Teemu Likonen <tlikonen@iki.fi> writes:

For comment I've duplicated:
Subject: Re: Scope of "this" variable

this is a keyword and not the name of a variable and does not have
scope. But the object to which the keywords refers does changes as
execution contexts are created, entered and exited. As such it feels a
bit like something with scope, but trying to fit it into the model of a
scoped name will just cause confusion.

> Code
>
> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> this.foo = {
> fn2: function() { return this.variable; }
> };
> };
>
> var item1 = new Item();
> console.log(item1.fn1());
> console.log(item1.foo.fn2());
>
> prints this:
>
> "variable"
> undefined
>
> So function item1.fn1 returns the string "variable" but function
> item1.foo.fn2 returns undefined. The variable "this" somehow disappears
> (or doesn't last long enough) when a function object is created inside
> another object {...}. Why?

When you call a method like item1.foo.fn2, part of the process
establishes a value for 'this'. Calling x.f(...) executes f in a
context in which this refers to x. Here, 'this' will refer to
item1.foo. I think you'll agree that you want that behaviour more often
than not.

> I know a work-around:
>
> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> var this_object = this;
> this.foo = {
> fn2: function() { return this_object.variable; }
> };
> };

Or you could write

this.foo = {
fn2: (function (outer) {
return function() { return outer.variable; };
})(this)
};

which is slightly neater using ES6's arrow functions:

fn2: (outer => { return () => { return outer.variable; }; })(this)

> But I'd like to understand why the first example works the way it does.
> What's the difference between these to examples?

For the details, you need to read through the language standard. In
particular, section 11.2.3 "Function Calls".

--
Ben.

Thomas 'PointedEars' Lahn

12/29/2015 9:09:00 PM

0

Teemu Likonen wrote:

> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> this.foo = {
> fn2: function() { return this.variable; }
> };
> };
>
> var item1 = new Item();
> console.log(item1.fn1());
> console.log(item1.foo.fn2());
>
> prints this:
>
> "variable"
> undefined
>
> So function item1.fn1 returns the string "variable" but function
> item1.foo.fn2 returns undefined. The variable "this" somehow disappears
> (or doesn't last long enough) when a function object is created inside
> another object {...}.

â??thisâ? is not a variable; it is a value. And it does not appear or
disappear at all.

> Why?

You have stored in â??this.fooâ? a reference to an object (here: an Object
instance, created with the Object initialiser, â??{}â?). â??thisâ? is only
resolved when a function or method is called, and the object referred to by
â??this.fooâ? (on which you are calling the â??fn2â? method) neither has nor
inherits a property named â??variableâ?. Accessing a non-existing property
usually (without Proxy) yields the â??undefinedâ? value of the Undefined type.

> I know a work-around:
>
> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> var this_object = this;
> this.foo = {
> fn2: function() { return this_object.variable; }
> };
> };

Yes, that is a proper workaround. People also use â??thatâ? or â??selfâ? instead
of the longer â??this_objectâ?.

However, unless you are actually referring to a variable declared in the
local context of the constructor (which can be understood as a private
property since only the public methods of the instance or its prototype, if
defined within the constructor, can access it â?? they are then called
â??privilegedâ?), or the method changes significantly depending on the
constructor call in some other way, you should avoid defining public methods
in the constructor and define them as prototype methods instead, saving
memory (at the expense of runtime efficiency due to the prototype chain
lookup).

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

JR

12/29/2015 9:39:00 PM

0

On 29/12/2015 17:34, Teemu Likonen wrote:
> Code
>
> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> this.foo = {
> fn2: function() { return this.variable; }
^^^^^^
Here, 'this.variable' means 'foo.variable', but there isn't such
identifier in foo, so 'this.variable' will return undefined, according
to the ECMAScript 5.1, $ 8.7 - The Reference Specification Type. Also
see $ 10.3.1, 11.1.1 and 11.1.2:
<http://ecma-international.org/ecma-26...


> };
> };
>
> var item1 = new Item();
> console.log(item1.fn1());
> console.log(item1.foo.fn2());
>
> prints this:
>
> "variable"
> undefined

But if you add a line with "this.foo.variable = 'variable2'", then the
property reference will work fine:

this.foo = {
fn2: function() { return this.variable; }
};
// The next line will resolve the Property reference.
this.foo.variable = "variable2";

console.log(item1.foo.fn2()); // variable2.

>
> So function item1.fn1 returns the string "variable" but function
> item1.foo.fn2 returns undefined. The variable "this" somehow disappears
> (or doesn't last long enough) when a function object is created inside
> another object {...}. Why?
>
> I know a work-around:
>
> var Item = function() {
> this.variable = "variable";
> this.fn1 = function() { return this.variable; };
> var this_object = this;
> this.foo = {
> fn2: function() { return this_object.variable; }
^^^^^^^^^^^^

Oops, this is something else, not a workaround, as this_object
references Item.variable, not foo.variable as in the previous case.

> };
> };
>
> But I'd like to understand why the first example works the way it does.

IMO, "Kangax" wrote a masterpiece about the 'this' keyword in
ECMAScript. You may want to take a look:
<http://perfectionkills.com/know-thy-refe...


> What's the difference between these to examples?

See above.


--
Joao Rodrigues

JR

12/29/2015 9:46:00 PM

0

On 29/12/2015 19:38, Joao Rodrigues wrote:
> On 29/12/2015 17:34, Teemu Likonen wrote:

>>
>> I know a work-around:
>>
>> var Item = function() {
>> this.variable = "variable";
>> this.fn1 = function() { return this.variable; };
>> var this_object = this;
>> this.foo = {
>> fn2: function() { return this_object.variable; }
> ^^^^^^^^^^^^
>
> Oops, this is something else, not a workaround, as this_object
> references Item.variable, not foo.variable as in the previous case.

Oops again :-) I meant "as this_object.variable" references
Item.variable..."



--
Joao Rodrigues

Thomas 'PointedEars' Lahn

12/29/2015 11:35:00 PM

0

Joao Rodrigues wrote:

> On 29/12/2015 17:34, Teemu Likonen wrote:
>> var Item = function() {
>> this.variable = "variable";
>> this.fn1 = function() { return this.variable; };
>> this.foo = {
>> fn2: function() { return this.variable; }
> ^^^^^^
> Here, 'this.variable' means 'foo.variable',

No, it does not.

> but there isn't such identifier in foo,

Your wording is imprecise at best. There is no â??fooâ?, and this has nothing
to do with identifiers. â??this.fooâ? in the direct execution context of Item
is a reference to an object. That object does not have a property with the
name â??variableâ?.

> so 'this.variable' will return undefined, according
> to the ECMAScript 5.1, $ 8.7 - The Reference Specification Type.

_§_, and irrelevant.

> Also see $ 10.3.1, 11.1.1 and 11.1.2:

_§§_, and irrelevant.

> <http://ecma-international.org/ecma-26...

The relevant section there is <http://ecma-international.org/ecma-262/5.1/#sec-...

> But if you add a line with "this.foo.variable = 'variable2'", then the
> property reference will work fine:

It is not a property reference, but a property _access_.

>> var Item = function() {
>> this.variable = "variable";
>> this.fn1 = function() { return this.variable; };
>> var this_object = this;
>> this.foo = {
>> fn2: function() { return this_object.variable; }
> ^^^^^^^^^^^^
>
> Oops, this is something else, not a workaround, as this_object
> references Item.variable, not foo.variable as in the previous case.

Nonsense.

> IMO, "Kangax" wrote a masterpiece about the 'this' keyword in
> ECMAScript. You may want to take a look:
> <http://perfectionkills.com/know-thy-refe...

Unless you have your misconceptions from there, go read it.

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

Thomas 'PointedEars' Lahn

12/29/2015 11:43:00 PM

0

Joao Rodrigues wrote:

> On 29/12/2015 19:38, Joao Rodrigues wrote:
>> On 29/12/2015 17:34, Teemu Likonen wrote:
>>> I know a work-around:
>>>
>>> var Item = function() {
>>> this.variable = "variable";
>>> this.fn1 = function() { return this.variable; };
>>> var this_object = this;
>>> this.foo = {
>>> fn2: function() { return this_object.variable; }
>> ^^^^^^^^^^^^
>>
>> Oops, this is something else, not a workaround, as this_object
>> references Item.variable, not foo.variable as in the previous case.
>
> Oops again :-) I meant "as this_object.variable" references
> Item.variable..."

Nonsense. â??thisâ? in the context of â??Itemâ?, therefore â??this_objectâ? too,
refers to

- the global object if the object referred to by â??Itemâ? (â??Itemâ?)
is called as a global function in non-strict mode (in strict mode,
â??thisâ? would be â??undefinedâ?)

- the constructed Item instance if â??Itemâ? is called as a constructor

- the object that â??Itemâ? was called as a function of through method
transfer (â??target.method = source.method; target.method(â?¦)â?), or use
of Function.prototype.call(), Function.prototype.apply() (both since
ES 3), or Function.prototype.bind() (since ES 5.x).

--
PointedEars
FAQ: <http://PointedEars.... | SVN: <http://PointedEars.de...
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-...
Please do not cc me. / Bitte keine Kopien per E-Mail.

JR

12/30/2015 4:18:00 AM

0

On 12/29/2015 07:38 PM, Joao Rodrigues wrote:
> On 29/12/2015 17:34, Teemu Likonen wrote:
>> Code
>>
>> var Item = function() {
>> this.variable = "variable";
>> this.fn1 = function() { return this.variable; };
>> this.foo = {
>> fn2: function() { return this.variable; }
> ^^^^^^
> Here, 'this.variable' means 'foo.variable', but there isn't such
> identifier in foo, so 'this.variable' will return undefined, according
> to the ECMAScript 5.1, $ 8.7 - The Reference Specification Type. Also
> see $ 10.3.1, 11.1.1 and 11.1.2

Ben Bacarisse got the right reference to the ECMAScript Language
Specification (section 11.2.3 "Function Calls") for this part of the
OP's code.




--
Joao Rodrigues

Teemu Likonen

12/30/2015 8:57:00 AM

0

Ben Bacarisse [2015-12-29 20:47:15Z] wrote:

> ["this"] is a keyword and not the name of a variable and does not have
> scope. But the object to which the keywords refers does changes as
> execution contexts are created, entered and exited. As such it feels a
> bit like something with scope, but trying to fit it into the model of
> a scoped name will just cause confusion.

> When you call a method like item1.foo.fn2, part of the process
> establishes a value for 'this'. Calling x.f(...) executes f in a
> context in which this refers to x. Here, 'this' will refer to
> item1.foo. I think you'll agree that you want that behaviour more often
> than not.

Thank you, and everybody. Many good details were given. I come mostly
From Common Lisp (I'm still "there") and even the semantics of this
dot.notation.thing is quite new to me, even though its very common. But
I got a fair step forward with this discussion and by reading the
standard. Thanks.

--
/// Teemu Likonen - .-.. <https://github.com/tl... //
// PGP: 4E10 55DC 84E9 DFF6 13D7 8557 719D 69D3 2453 9450 ///