2

From MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this, it says:

In strict mode, however, the value of this remains at whatever it was set to when entering the execution context, so, in the following case, this will default to undefined:

function f2() {   
  'use strict'; // see strict mode   
  return this; 
}

f2() === undefined; // true

This suggests that if I (1) 'use strict'; and (2) define f2 inside another function that invoking f2 would bind the outside function's this for f2. BUT!

It doesn't work...

'use strict';

function AlarmClock(clockName) {
  this.clockName=clockName;
}

console.log("hello, let's see some weird stuff");

console.log("THIS in global", this);

AlarmClock.prototype.start = function(seconds) {
  console.log('outer', this);
  var testInside = function() {
    console.log('inner', this);
  }
  testInside();
}

var clock = new AlarmClock("Horizons")
clock.start(1);


// WITHOUT CONSTRUCTORS

function withoutOut() {
  console.log("withoutOut", this)
  this.howard="notSoBad";
  console.log("modifiedTheThis, should have Howard", this)
  function withoutIn1() {
   console.log("withoutIn1", this);
   console.log("Strict should set to the defining object's this");
  }
  var withoutIn2 = function() {
    console.log("withoutIn2", this);
    console.log("Strict should set to the defining object's this");
  }
  withoutIn1();
  withoutIn2();
}

withoutOut.bind({Moose: "genius"})();

console.log("DONE");

Gives this output:

hello, let's see some weird stuff
THIS in global {}
outer AlarmClock { clockName: 'Horizons' }
inner undefined
withoutOut { Moose: 'genius' }
modifiedTheThis, should have Howard { Moose: 'genius', howard: 'notSoBad' }
withoutIn1 undefined
Strict should set to the defining object's this
withoutIn2 undefined
Strict should set to the defining object's this
DONE

NOTE: I ran this with node v10.5.0, from a mac osx command line.

NOTE2: If you run in devtools, you have to follow these steps for use strict.

NOTE3: Basically, I want to find someway to get inner, withoutIn1 or withoutIn2 to NOT be undefined. And, I know you can do this with an explicit bind, but I want to specifically get the behavior specified in the MDN doc.

If you agree with me, MDN should change the "this" doc to just say, in function context with "use strict", this is set to undefined ALWAYS. (author likes)

Or, Chrome should change the implementation. (author dislikes)

Pointy
  • 405,095
  • 59
  • 585
  • 614
chongman
  • 2,447
  • 4
  • 21
  • 23
  • 3
    You really are misunderstanding how `this` works. In **any** function call made without an explicit context (no object reference, no use of `.call()`, `.apply()`, or `.bind()`) the value of `this` in strict mode is indeed `undefined`. However, in strict mode `this` works exactly as it does in non-strict mode when there *is* a call context. – Pointy Jul 23 '18 at 21:37
  • To add on to what Ry said, it doesn't suggest that at all. It's saying that if you define it as a method of an object the value of `this` will be the object. It says nothing at all about defining a function inside another function. – Aplet123 Jul 23 '18 at 21:41
  • That second paragraph of the MDN document you linked really spells it out pretty clearly. – Pointy Jul 23 '18 at 21:43
  • 2
    The article has confusing wording, but “the value of this remains at whatever it was set to when entering the execution context” means the `this` value isn’t changed compared to how it was called (e.g. as `f()`/`f.call(null)`/`f.call(undefined)`/`f.call(5)` – these will result in `this` values of `undefined`/`null`/`undefined`/`5` in strict mode, but `(global)`, `(global)`, `(global)`, and `new Number(5)` outside – the values have been changed compared to the call). – Ry- Jul 23 '18 at 21:43
  • Yes reading that quoted paragraph again, I think it's just either awkward word choice or simply wrong; the value of `this` does not have anything to do with its value in the calling environment. (Of course arrow functions are different, but then the bound value involves the *defining* environment.) – Pointy Jul 23 '18 at 21:45
  • Got it. this is defined by the /call/ context. NOT /where/ it is called or /where/ it is defined. So the "left of the dot=context" rule-of-thumb is pretty good. Thanks for clarifying my understanding. The key wording seems to be "whatever it was set to when entering the [new] execution context [of the invocation of the function itself]". Brackets are things I added. --- I misread as the /calling/ execution context. – chongman Jul 24 '18 at 17:41

1 Answers1

7

The value of this when a function is called has nothing at all to do with how or where the function is defined. It has to do only with how the function is called. Calling your inner functions:

AlarmClock.prototype.start = function(seconds) {
  console.log('outer', this);
  var testInside = function() {
    console.log('inner', this);
  }
  testInside();
}

like testInside() without any object reference means that there's nothing to bind to this, and in strict mode that means this is undefined. However, if you had written instead

  testInside.call(this);

then there'd be a context value. The fact that a function is "inside" another function, again, has absolutely no impact on how this is bound. Alternatively:

  this.testInside = testInside;
  this.testInside();

it'd also work, because once again there's a context.

Oh, and also also, the new(ish) arrow function mechanism does let you create functions that effectively "inherit" the this value from their lexical environment. So:

AlarmClock.prototype.start = function(seconds) {
  console.log('outer', this);
  var testInside = () => {
    console.log('inner', this);
  }
  testInside();
}

would work, because calling an arrow function does not involve any this binding; this behaves essentially like a variable in the closure.

Pointy
  • 405,095
  • 59
  • 585
  • 614