Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.javascript > #28023 > unrolled thread
| Started by | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| First post | 2015-06-08 00:21 +1000 |
| Last post | 2015-06-07 23:48 +0200 |
| Articles | 7 — 4 participants |
Back to article view | Back to comp.lang.javascript
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
| From | Steven D'Aprano <steve@pearwood.info> |
|---|---|
| Date | 2015-06-08 00:21 +1000 |
| Subject | What 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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | "Christoph M. Becker" <cmbecker69@arcor.de> |
|---|---|
| Date | 2015-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]
| From | Ben Bacarisse <ben.usenet@bsb.me.uk> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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]
| From | Thomas 'PointedEars' Lahn <PointedEars@web.de> |
|---|---|
| Date | 2015-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