Мотивация за синтаксической ошибкой строгого режима при удалении неквалифицированного идентификатора?

У меня возникли проблемы с пониманием того, что в строгом режиме синтаксическая ошибка возникает, когда delete используется для неквалифицированного идентификатора.

В большинстве случаев это имеет смысл... если вы объявляете переменные обычным способом с ключевым словом var, а затем пытаетесь использовать delete на них, в нестрочном режиме он будет терпеть неудачу, поэтому имеет смысл, если строгий режим терпит неудачу с ошибкой в ​​этих случаях.

Однако есть случаи, когда вы не можете удалить идентификаторы, которые являются квалифицированными:

(function() {

  // "use strict";

  var obj = Object.create({}, { bloop: { configurable: false } });

  delete obj.bloop; // throws TypeError in strict mode, silently fails in non-strict.

  console.log('bloop' in obj); // true

}());

Строгий режим должен выполнять проверку времени выполнения, поскольку при столкновении возникает TypeError. Существуют также случаи, когда вы можете успешно удалить неквалифицированные идентификаторы в нестрогом режиме...

// "use strict";

window.bar = 6;

console.log(typeof bar); // number

delete bar; // works in non-strict, syntax error in strict!

console.log(typeof bar); // undefined

На самом деле, насколько я понимаю, можно ли удалять вещи (в нестрогом режиме), зависит от внутреннего свойства [[Configurable]] и не имеет ничего общего с квалифицированными идентификаторами. Насколько я могу судить, в строгом режиме нет способа удалить неглобальные переменные, которые (как свойства локального VO) настраиваются:

(function() {

  // "use strict";

  eval('var foo = 5;');

  console.log(typeof foo); // number

  delete foo; // works in non-strict, SyntaxError in strict.

  console.log(typeof foo); // undefined

}());

Итак, мой вопрос заключается в том, какой смысл бросать SyntaxError при использовании delete на неквалифицированный идентификатор, когда TypeError будет бросать в любом случае, если свойство не настраивается? Это кажется ненужным ограничением, и в некоторых случаях, похоже, не существует какого-либо обходного пути, кроме использования строгого режима (третий пример). Может ли кто-нибудь объяснить мотивацию этого решения?


Обновление: я просто понял, что я упускаю из виду тот факт, что прямые вызовы eval имеют свою собственную область действия в строгом режиме, а не в области вызывающей функции, поэтому в третьем примере foo не будет определяться в строгом режиме, Во всяком случае, проверка времени выполнения все равно поймает это, но вызывает побочный вопрос: нет ли способа иметь настраиваемые локальные переменные в строгом режиме, как это происходит с объявлениями eval 'd variable в нестрочном? AFAIK, который был одним из немногих законных видов использования eval.

Ответы

Ответ 1

Вы говорите Раздел 11.4.1, параграф 5.a. спецификаций:

  1. Else, ref - ссылка на привязку записи среды, так что    а. Если IsStrictReference (ref) истинно, выведите исключение SyntaxError.
       б. Пусть привязки будут GetBase (ref).
       с. Верните результат вызова метода DeleteBinding для привязки, предоставляя GetReferencedName (ref) в качестве аргумента.

То, что вы назвали "неквалифицированные идентификаторы", официально называется "привязка записи среды".

Теперь, на ваш вопрос. Зачем бросать SyntaxError при 5.c. все равно потерпит неудачу? Я думаю, вы сами ответили на него.

Строгий режим должен выполнять проверку выполнения здесь, потому что TypeError вызывается , когда это встречается.

Это правильно. Но всегда лучше быстро терпеть неудачу. Таким образом, когда есть вероятность обнаружить SyntaxError (в время синтаксического анализа), эту возможность следует принять.

Почему? Это избавит вас от необходимости исправлять ваше приложение, если возникла ошибка. Подумайте о IDE, которые могут сразу показать вам ошибку, в отличие от часов отладки.
Кроме того, такие ограничения могут быть выгодными для оптимизированных компиляторов JIT.

Ответ 2

Если вы хотите удалить объект в строгом режиме. Вы должны явно указать о доступе к свойствам. Также обратите внимание, что важно, как вы называете эту функцию. Если оператор new не используется this есть undefined в разделе use strict, и вы не можете использовать метод ниже. Пример:

'use strict'
function func(){
  var self = this;
  self.obj = {};
  self.obj.x = 'y'

  console.log(self.obj);
  delete self.obj // works
  // delete obj // doesn't work
  console.log(self.obj);
}

var f = new func();

Чтобы удалить объект за пределами функции (закрытие), вам нужно позвонить как

// same code as above
delete f.obj