Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #29062 > unrolled thread
| Started by | Teemu Likonen <tlikonen@iki.fi> |
|---|---|
| First post | 2015-12-29 21:34 +0200 |
| Last post | 2015-12-30 02:18 -0200 |
| Articles | 9 — 4 participants |
Back to article view | Back to comp.lang.javascript
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
| From | Teemu Likonen <tlikonen@iki.fi> |
|---|---|
| Date | 2015-12-29 21:34 +0200 |
| Subject | Scope 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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | Teemu Likonen <tlikonen@iki.fi> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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]
| From | Joao Rodrigues <groups_jr-1@yahoo.com.br> |
|---|---|
| Date | 2015-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]
| From | Joao Rodrigues <groups_jr-1@yahoo.com.br> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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]
| From | Joao Rodrigues <groups_jr-1@yahoo.com.br> |
|---|---|
| Date | 2015-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