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


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

What is this inside a function?

Started bySteven D'Aprano <steve@pearwood.info>
First post2015-06-08 00:21 +1000
Last post2015-06-07 23:48 +0200
Articles 7 — 4 participants

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


Contents

  What is this inside a function? Steven D'Aprano <steve@pearwood.info> - 2015-06-08 00:21 +1000
    Re: What is this inside a function? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-06-07 19:58 +0100
      Re: What is this inside a function? "Christoph M. Becker" <cmbecker69@arcor.de> - 2015-06-07 21:19 +0200
        Re: What is this inside a function? Ben Bacarisse <ben.usenet@bsb.me.uk> - 2015-06-07 20:43 +0100
        Re: What is this inside a function? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-06-08 01:08 +0200
          Re: What is this inside a function? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-06-12 19:19 +0200
      Re: What is this inside a function? Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2015-06-07 23:48 +0200

#28023 — What is this inside a function?

FromSteven D'Aprano <steve@pearwood.info>
Date2015-06-08 00:21 +1000
SubjectWhat is this inside a function?
Message-ID<55745377$0$12997$c3e8da3$5496439d@news.astraweb.com>
I thought I understood what "this" means inside a function. I thought that
when you called a function, "this" was the local scope, which is an object.
That's why you can use a function as an object constructor:

js> function Person1(name, age){
  > this.name = name;
  > this.age = age;
  > }
js> fred = new Person1("Freddy", 23);
[object Object]
js> print(fred.name, fred.age);
Freddy 23


Constructors are just functions, except they implicitly return "this",
right? So at this point I thought I'd be clever:

js> function Person2(name, age){
  > this.name = name;
  > this.age = age;
  > return this;
  > }
js> george = new Person2("George", 42);
[object Object]
js> george.name;
George


And that seems to work. But if I do this:


js> henry = Person2("Henry", 87);
[object global]
js> name;
Henry
js> age;
87
js> henry === this;
true

the function seems to be operating on the global scope.

Obviously my reasoning is invalid. Can somebody explain what is happening
here? What is the role of this inside a function, and how does it sometimes
refer to the object being constructed and sometimes to the global scope?



The above examples are using Rhino.

-- 
Steven

[toc] | [next] | [standalone]


#28030

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-06-07 19:58 +0100
Message-ID<878ubvjqgp.fsf@bsb.me.uk>
In reply to#28023
Steven D'Aprano <steve@pearwood.info> writes:

> I thought I understood what "this" means inside a function. I thought that
> when you called a function, "this" was the local scope, which is an
> object.
> That's why you can use a function as an object constructor:
>
> js> function Person1(name, age){
>   > this.name = name;
>   > this.age = age;
>   > }
> js> fred = new Person1("Freddy", 23);
> [object Object]
> js> print(fred.name, fred.age);
> Freddy 23

No, it's the 'new' part that makes this work.  Without it, what "this"
means depends on strict mode.

The expression new F(...args...) calls the [[Contruct]] internal method
on F and that method is defined to bind this to an empty object.  The
[[Construct]] method goes on to call the [[Call]] internal method so the
main difference between new F(...args...) and F(...args...) is this
special binding for that.

(This is not the correct terminology because 'this' is not a name has no
bindings, but it simpler to put it this way.)

> Constructors are just functions, except they implicitly return "this",
> right?

Not really.  Constructors are just functions and they can return
whatever they like, and when called without new, they return that value.
It's the new expression that returns the new object, probably modified
by the function that was called.  The value the function returns is
ignored in a new expression.

> So at this point I thought I'd be clever:
>
> js> function Person2(name, age){
>   > this.name = name;
>   > this.age = age;
>   > return this;
>   > }
> js> george = new Person2("George", 42);
> [object Object]
> js> george.name;
> George

The 'return this' is harmless in this case because the function's return
value is ignored.

> And that seems to work. But if I do this:
>
> js> henry = Person2("Henry", 87);
> [object global]
> js> name;
> Henry
> js> age;
> 87
> js> henry === this;
> true
>
> the function seems to be operating on the global scope.

Without the 'new' you get whatever the function returns.  In old JS, and
in non-strict mode, that will be the global object (not scope).

> Obviously my reasoning is invalid. Can somebody explain what is happening
> here? What is the role of this inside a function, and how does it sometimes
> refer to the object being constructed and sometimes to the global
> scope?

It's all down to using new F(...) rather than F(...).

> The above examples are using Rhino.

Rhino is a little old.  In strict mode with a newer implementation
(e.g. nodejs) your last example gives an error because 'this' will refer
to the undefined value (rather than the global object) during the call
to Person2.

-- 
Ben.

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


#28032

From"Christoph M. Becker" <cmbecker69@arcor.de>
Date2015-06-07 21:19 +0200
Message-ID<55749955.4050107@arcor.de>
In reply to#28030
Ben Bacarisse wrote:

> Steven D'Aprano <steve@pearwood.info> writes:
> 
>> Constructors are just functions, except they implicitly return "this",
>> right?
> 
> Not really.  Constructors are just functions and they can return
> whatever they like, and when called without new, they return that value.
> It's the new expression that returns the new object, probably modified
> by the function that was called.  The value the function returns is
> ignored in a new expression.

The latter is only true if a primitive value would be returned.  If,
however, the return statement's expression evaluates to an object, this
very object is returned. E.g.

  function foo() {return {bar: "baz"}}
  new foo // => {bar: "baz"}

Cf. <http://ecma-international.org/ecma-262/5.1/#sec-13.2.2>.

-- 
Christoph M. Becker

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


#28033

FromBen Bacarisse <ben.usenet@bsb.me.uk>
Date2015-06-07 20:43 +0100
Message-ID<87wpzfi9t8.fsf@bsb.me.uk>
In reply to#28032
"Christoph M. Becker" <cmbecker69@arcor.de> writes:

> Ben Bacarisse wrote:
>
>> Steven D'Aprano <steve@pearwood.info> writes:
>> 
>>> Constructors are just functions, except they implicitly return "this",
>>> right?
>> 
>> Not really.  Constructors are just functions and they can return
>> whatever they like, and when called without new, they return that value.
>> It's the new expression that returns the new object, probably modified
>> by the function that was called.  The value the function returns is
>> ignored in a new expression.
>
> The latter is only true if a primitive value would be returned.  If,
> however, the return statement's expression evaluates to an object, this
> very object is returned. E.g.
>
>   function foo() {return {bar: "baz"}}
>   new foo // => {bar: "baz"}
>
> Cf. <http://ecma-international.org/ecma-262/5.1/#sec-13.2.2>.

Ah, yes, I forgot that.  Thanks.

-- 
Ben.

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


#28037

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-06-08 01:08 +0200
Message-ID<1622672.QCbqgxkKEs@PointedEars.de>
In reply to#28032
Christoph M. Becker wrote:

> […] If […] the return statement's expression evaluates to an object, this
> very object is returned. E.g.
> 
>   function foo() {return {bar: "baz"}}
>   new foo // => {bar: "baz"}

Should be “function Foo” and “new Foo”, respectively.  JSHint is able to 
point that out with {newcap: true}, but the check will be moved to the 
JavaScript Code Style checker (JSCS) with the next major JSHint release:

<http://jshint.com/docs/options/#newcap> p.

> Cf. <http://ecma-international.org/ecma-262/5.1/#sec-13.2.2>.

Correct, and this has practical implications:

  function Person2(name, age)
  {
    if (!(this instanceof Person2)) return new Person2(name, age);
    
    this.name = name;
    this.age = age;
  }

and with JSX:

  function Person2(name, age)
  {
    if (!(this instanceof Person2)) return Person2.construct(arguments);
    
    this.name = name;
    this.age = age;
  }

See also Function.prototype.construct() and Function.prototype.construct2() 
in <http://PointedEars.de/wsvn/JSX/trunk/object.js>.

-- 
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]


#28091

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-06-12 19:19 +0200
Message-ID<1908572.Dhjy60Y1dk@PointedEars.de>
In reply to#28037
Thomas 'PointedEars' Lahn wrote:

> Christoph M. Becker wrote:
>> Cf. <http://ecma-international.org/ecma-262/5.1/#sec-13.2.2>.
> 
> Correct, and this has practical implications:
> 
>   function Person2(name, age)
>   {
>     if (!(this instanceof Person2)) return new Person2(name, age);
>     
>     this.name = name;
>     this.age = age;
>   }
> 
> and with JSX:
> 
>   function Person2(name, age)
>   {
>     if (!(this instanceof Person2)) return Person2.construct(arguments);
>     
>     this.name = name;
>     this.age = age;
>   }
> 
> See also Function.prototype.construct() and
> Function.prototype.construct2() in
> <http://PointedEars.de/wsvn/JSX/trunk/object.js>.

Du not bother looking for .construct2(); it went the way of the dinosaur 
with r510 last year already :)  The new .construct() does not use eval() 
anymore, and as it was also superior to the .construct2() that Asen Bozhilov 
suggested, I have removed the latter method.

<http://pointedears.de/wsvn/JSX/trunk/object.js?op=diff&rev=510>

-- 
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]


#28036

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2015-06-07 23:48 +0200
Message-ID<4280548.92UKxee3U8@PointedEars.de>
In reply to#28030
Ben Bacarisse wrote:

> The expression new F(...args...) calls the [[Contruct]] internal method
> on F and that method is defined to bind this to an empty object.  The
> [[Construct]] method goes on to call the [[Call]] internal method so the
> main difference between new F(...args...) and F(...args...) is this
> special binding for that.
> 
> (This is not the correct terminology because 'this' is not a name has no
> bindings,

Parse error.

> but it simpler to put it this way.)

<http://ecma-international.org/ecma-262/5.1/#sec-11.1.1>
| The “this” keyword evaluates to the value of the <ThisBinding> of the 
| current execution context.

-- 
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] | [standalone]


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


csiph-web