JS: "this" в контексте функции в строгом режиме, спецификация MDN не соответствует реализации chrome 67

От MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this, это говорит:

В строгом режиме, однако, значение этого остается на том, что было установлено при входе в контекст выполнения, поэтому в следующем случае это будет по умолчанию неопределенное:

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

f2() === undefined; // true

Это говорит о том, что если я (1) "использую строгий"; и (2) определить f2 внутри другой функции, которая при вызове f2 свяжет внешнюю функцию this для f2. НО!

Это не работает...

'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");

Дает этот вывод:

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

ПРИМЕЧАНИЕ: я запустил это с узлом v10.5.0 из командной строки Mac OSX.

ПРИМЕЧАНИЕ 2: Если вы работаете в devtools, вы должны следовать этим шагам для строгого использования.

ПРИМЕЧАНИЕ 3: По сути, я хочу найти способ проникнуть внутрь, без IN1 или без IN2, чтобы НЕ быть неопределенным. И я знаю, что вы можете сделать это с явным связыванием, но я хочу конкретно получить поведение, указанное в документе MDN.

Если вы согласны со мной, MDN следует изменить документ "this", чтобы просто сказать, что в контексте функции с "use strict" это значение установлено ВСЕГДА ВСЕГДА. (автору нравится)

Или Chrome должен изменить реализацию. (автор не любит)

1 ответ

Решение

Значение this когда функция вызывается, она не имеет ничего общего с тем, как или где она определена. Это связано только с тем, как вызывается функция. Вызов ваших внутренних функций:

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

лайк testInside() без какой-либо ссылки на объект означает, что нечего связывать this и в строгом режиме это означает this является undefined, Однако, если вы написали вместо

  testInside.call(this);

тогда будет значение контекста. Тот факт, что функция находится "внутри" другой функции, опять же, абсолютно не влияет на то, как this связан. В качестве альтернативы:

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

это также сработало бы, потому что снова есть контекст.

О, а также также, новый (ish) механизм функции стрелки позволяет вам создавать функции, которые эффективно "наследуют" this значение из их лексической среды. Так:

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

будет работать, потому что вызов функции стрелки не требует каких-либо this связывание; this ведет себя по существу как переменная в замыкании.

Другие вопросы по тегам