[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.javascript

What is this inside a function?

Steven D'Aprano

6/7/2015 2:22:00 PM

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

8 Answers

ram

6/7/2015 5:08:00 PM

0

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.

The local scope in a function is the »activation object«
(»lexical environment«, »context of the function«,
»declarative environment record«, »function scope«,
»scope variables«). It has no name in JavaScript AFAIK.

When you call a function in strict mode, »this« is just
undefined.

function beta(){ "use strict"; console.log( this ); }
function alpha(){ "use strict"; beta(); }
alpha();

undefined

We must all code towards »"use strict";« and forget what
was before. Therefore, I will not discuss the historic state
of the JavaScript of the grandmothers of our grandmothers!


Ben Bacarisse

6/7/2015 6:58:00 PM

0

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.

ram

6/7/2015 7:16:00 PM

0

Ben Bacarisse <ben.usenet@bsb.me.uk> did not write:
|(This is not the correct terminology because 'this' is not a name [and ]has no
|bindings, but it simpler to put it this way.)
[»[and ]« above was inserted by me - Stefan Ram]

ECMA 5.1 says:

»11.1.1 The this Keyword
The this keyword evaluates to the value of the ThisBinding of the current execution context.«

so your wording is not so far from the correct terminology
either.

Christoph M. Becker

6/7/2015 7:20:00 PM

0

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

--
Christoph M. Becker

Ben Bacarisse

6/7/2015 7:43:00 PM

0

"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-....

Ah, yes, I forgot that. Thanks.

--
Ben.

Thomas 'PointedEars' Lahn

6/7/2015 9:48:00 PM

0

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-...
| The â??thisâ? keyword evaluates to the value of the <ThisBinding> of the
| current execution context.

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

6/7/2015 11:09:00 PM

0

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/#... p.

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

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/obj....

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

6/12/2015 5:19:00 PM

0

Thomas 'PointedEars' Lahn wrote:

> Christoph M. Becker wrote:
>> Cf. <http://ecma-international.org/ecma-262/5.1/#sec-....
>
> 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/obj....

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&r...

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