Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #29062 > unrolled thread

Scope of "this" variable

Started byTeemu Likonen <tlikonen@iki.fi>
First post2015-12-29 21:34 +0200
Last post2015-12-30 02:18 -0200
Articles 9 — 4 participants

Back to article view | Back to comp.lang.javascript


Contents

  Scope of "this" variable Teemu Likonen <tlikonen@iki.fi> - 2015-12-29 21:34 +0200
    Re: Scope of "this" variable Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-12-29 20:47 +0000
      Re: Scope of "this" variable Teemu Likonen <tlikonen@iki.fi> - 2015-12-30 10:57 +0200
    Re: Scope of "this" variable Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-29 22:09 +0100
    Re: Scope of "this" variable Joao Rodrigues <groups_jr-1@yahoo.com.br> - 2015-12-29 19:38 -0200
      Re: Scope of "this" variable Joao Rodrigues <groups_jr-1@yahoo.com.br> - 2015-12-29 19:46 -0200
        Re: Scope of "this" variable Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-30 00:42 +0100
      Re: Scope of "this" variable Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-12-30 00:35 +0100
      Re: Scope of "this" variable Joao Rodrigues <groups_jr-1@yahoo.com.br> - 2015-12-30 02:18 -0200

#29062 — Scope of "this" variable

FromTeemu Likonen <tlikonen@iki.fi>
Date2015-12-29 21:34 +0200
SubjectScope of "this" variable
Message-ID<87ziwtqc9t.fsf@mithlond.arda>

[Multipart message — attachments visible in raw view] — view raw

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/tlikonen> //
// PGP: 4E10 55DC 84E9 DFF6 13D7 8557 719D 69D3 2453 9450 ///

[toc] | [next] | [standalone]


#29064

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-12-29 20:47 +0000
Message-ID<87k2nx7zjg.fsf@bsb.me.uk>
In reply to#29062
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.

[toc] | [prev] | [next] | [standalone]


#29072

FromTeemu Likonen <tlikonen@iki.fi>
Date2015-12-30 10:57 +0200
Message-ID<8737ukgvpr.fsf@mithlond.arda>
In reply to#29064

[Multipart message — attachments visible in raw view] — view raw

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/tlikonen> //
// PGP: 4E10 55DC 84E9 DFF6 13D7 8557 719D 69D3 2453 9450 ///

[toc] | [prev] | [next] | [standalone]


#29065

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-29 22:09 +0100
Message-ID<1477065.DiSW4fkXl8@PointedEars.de>
In reply to#29062
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.de/faq> | SVN: <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-matrix>
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#29067

FromJoao Rodrigues <groups_jr-1@yahoo.com.br>
Date2015-12-29 19:38 -0200
Message-ID<n5uugv$fpe$1@speranza.aioe.org>
In reply to#29062
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-262/5.1/>


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


> What's the difference between these to examples?

See above.


-- 
Joao Rodrigues

[toc] | [prev] | [next] | [standalone]


#29068

FromJoao Rodrigues <groups_jr-1@yahoo.com.br>
Date2015-12-29 19:46 -0200
Message-ID<n5uuvf$gko$1@speranza.aioe.org>
In reply to#29067
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

[toc] | [prev] | [next] | [standalone]


#29070

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-30 00:42 +0100
Message-ID<2541123.lcmPiflTUf@PointedEars.de>
In reply to#29068
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.de/faq> | SVN: <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | ES Matrix: <http://PointedEars.de/es-matrix>
Please do not cc me. / Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#29069

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-12-30 00:35 +0100
Message-ID<4114182.jsOz3Ienk7@PointedEars.de>
In reply to#29067
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-262/5.1/>

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

> 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-reference/>

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

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

[toc] | [prev] | [next] | [standalone]


#29071

FromJoao Rodrigues <groups_jr-1@yahoo.com.br>
Date2015-12-30 02:18 -0200
Message-ID<n5vlue$n6n$1@speranza.aioe.org>
In reply to#29067
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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web