- Оригинальный адрес:Понимание «неопределенного» JavaScript
- Оригинальный автор:Angus Croll
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:yanyixin
- Корректор:noahziheng, Moonliujk
По сравнению с другими языками концепция undefined в JavaScript несколько сбивает с толку. Особенно пытаясь понять ReferenceError ("X IS Not Defe") и как написать для них элегантный код.
Эта статья — одна из моих попыток разобраться в этом. Если вы еще не знакомы с разницей между переменными и свойствами в JavaScript (включая внутренний VariableObject), лучше всего прочитать мойпредыдущий пост.
Что не определено?
В JavaScript есть Undefined (тип), undefined (значение) и undefined (переменная).
Undefined (type)является встроенным типом в JavaScript.
undefined (value)является единственным значением типа Undefined. Предполагается, что любое неназначенное свойствоundefined
(ECMA 4.3.9 и 4.3.10). Функция без оператора возврата или функция с пустым возвратом вернет неопределенное значение. Значение параметра, не определенного в функции, также считается неопределенным.
var a;
typeof a; //"undefined"
window.b;
typeof window.b; //"undefined"
var c = (function() {})();
typeof c; //"undefined"
var d = (function(e) {return e})();
typeof d; //"undefined"
undefined (variable)Начальное значение не определено (значение) глобальных свойств, поскольку это глобальное свойство, мы также можем использовать его в качестве переменного доступа. Для согласованности я называю его единой переменной в этой статье.
typeof undefined; //"undefined"
var f = 2;
f = undefined; //re-assigning to undefined (variable)
typeof f; //"undefined"
Начиная с ECMA 3, его можно переназначить:
undefined = "washing machine"; //把一个字符串赋值给 undefined (变量)
typeof undefined //"string"
f = undefined;
typeof f; //"string"
f; //"washing machine"
Излишне говорить, что переназначение неопределенных переменных — очень плохая практика. На самом деле, ECMA 5 этого не позволяет (хотя в современных браузерах это применяется только в Safari).
тогда ноль?
Да, в целом понятно, но повторюсь:undefined
а такжеnull
разные,null
выражатьПреднамеренныйИсходное значение отсутствующего значения.undefined
а такжеnull
Единственное сходство в том, что они оба ложны.
Итак, что такое ReferenceError?
ReferenceError Указывает, что было обнаружено недопустимое опорное значение. (ECMA 5 15.11.6.3)
В реальном проекте это означает, что при попытке JavaScript получить неразрешимую ссылку выдается ReferenceError. (Есть несколько других случаев, когда выдается ReferenceError, особенно при работе в строгом режиме ECMA 5. Если вам интересно, см. список для чтения в конце этой статьи.)
Важно отметить, как различается синтаксис сообщений, отправляемых разными браузерами, и, как мы увидим, ничто из этой информации не является особенно поучительным:
alert(foo)
//FF/Chrome: foo is not defined
//IE: foo is undefined
//Safari: can't find variable foo
Все еще не ясно, что такое «неразрешимая ссылка»?
В терминологии ECMA ссылка состоит из базового значения и имени ссылки (ECMA 5 8.7 — опять же я игнорирую строгий режим. Также обратите внимание, что ECMA 3 имеет немного другую терминологию, но фактическое значение такое же).
Если ссылка является свойством, базовое значение и имя ссылки находятся в.
с обеих сторон (или первая скобка или что-то еще):
window.foo; //base value = window, reference name = foo;
a.b; //base value = a, reference name = b;
myObj['create']; // base value = myObj, reference name = 'create';
//Safari, Chrome, IE8+ only
Object.defineProperty(window,"foo", {value: "hello"}); //base value = window, reference name = foo;
Для ссылок на переменные базовым значением является VariableObject текущего контекста выполнения. VariableObject глобального контекста — это сам глобальный объект (в браузереwindow
). Каждый контекст функции имеет абстрактный объект переменной, называемый ActivationObject.
var foo; //base value = window, reference name = foo
function a() {
var b; base value = <code>ActivationObject</code>, reference name = b
}
Если базовое значение не определено, ссылка считается неразрешимой.
Следовательно, если в.
Предыдущее значение переменной было неопределенным, тогда ссылка на свойство была неразрешимой. В следующем примере будет выброшена ошибка ReferenceError, но это не так, потому что сначала выдается TypeError. Это связано с тем, что на базовое значение свойства влияет CheckObjectCoercible (ECMA 5 от 9.10 до 11.2.1), который выдает ошибку TypeError при попытке преобразовать тип Undefined в Object. (Спасибо kangax за предварительное объявление в твиттере)
var foo;
foo.bar; //TypeError(基值,foo 是未定义的)
bar.baz; //ReferenceError(bar 是不能被解析的)
undefined.foo; //TypeError(基值是未定义的)
Ссылки на переменные всегда разрешаются, поскольку ключевое слово var гарантирует, что VariableObject всегда будет присвоено базовое значение.
По определению ссылка, которая не является ни свойством, ни переменной, неразрешима и выдает ReferenceError:
foo; //ReferenceError
В приведенном выше JavaScript не видно явного базового значения, поэтому объект VariableObject просматривается, чтобы сослаться на имя какfoo
характеристики. Конечноfoo
Нет базового значения, выдается ReferenceError.
ноfoo
Разве это не необъявленная переменная?
Технически нет. Хотя мы иногда находим «необъявленная переменная» полезным термином для диагностики ошибок, в действительности переменная не является переменной, пока она не объявлена.
Как насчет неявных глобальных переменных?
Это правда, что идентификаторы, которые никогда не объявлялись с помощью ключевого слова var, будут созданы как глобальные переменные, но только тогда, когда им будет присвоено значение.
function a() {
alert(foo); //ReferenceError
bar = [1,2,3]; //没有错误,foo 是全局的
}
a();
bar; //"1,2,3"
Конечно, это раздражает. Было бы лучше, если бы JavaScript всегда выдавал ReferenceErrors при обнаружении неразрешенных ссылок (на самом деле это то, что он делает в строгом режиме ECMA).
Когда вам нужно закодировать ReferenceError?
Это редко необходимо, если ваш код хорошо написан. Мы видели, что при типичном использовании есть только один способ получить неразрешимую ссылку: использовать синтаксически правильную ссылку, которая не является ни свойством, ни переменной. В большинстве случаев обязательно помните ключевое слово var, чтобы этого избежать. Исключения во время выполнения возникают только при ссылке на переменные, которые существуют только в определенных браузерах или в стороннем коде.
Хороший примерconsole. В браузерах Webkit консоль встроена, и свойства консоли всегда доступны. Однако консоль в Firefox зависит от установки и открытия Firebug (или других надстроек). В IE7 нет консоли, в IE8 есть консоль, но свойство console существует только при запуске средств разработки IE. Судя по всему в Опере есть консоль, но я ей ни разу не пользовался.
Вывод состоит в том, что следующий фрагмент кода, скорее всего, вызовет ReferenceError при запуске в браузере:
console.log(new Date());
Как закодировать переменную, которой может не быть?
Один из способов проверить наличие неразрешимой ссылки без выдачи ReferenceError — использоватьtypeof
ключевые слова.
if (typeof console != "undefined") {
console.log(new Date());
}
Однако мне это всегда кажется утомительным, не говоря уже о подозрительном (дело не в том, что ссылочное имя не определено, а в том, что базовое значение не определено). Но в любом случае, я предпочитаю держатьtypeof
для проверки типа.
К счастью, есть и другой способ: мы уже знаем, что если базовое значение неопределенного свойства определено, оно не вызовет ReferenceError, а так как консоль является глобальным объектом, мы можем сделать это:
window.console && console.log(new Date());
На самом деле вам нужно только проверить, существует ли переменная в глобальном контексте (в функции есть и другие контексты выполнения, и вы можете контролировать, какие переменные существуют в вашей собственной функции). Итак, теоретически вы должны быть в состоянии избежать использованияtypeof
Чтобы проверить ошибки к цитированию.
Где я могу прочитать больше?
Центр разработчиков Mozilla:undefined
Ангус Кролл:Переменные и свойства в JavaScript
Юрий Зайцев («кангакс»):Понять Удалить
Дмитрий А. Сошников:Объяснение ECMA-262-3: Глава 2 Переменные объекты
Стандартный документ ECMA-262 пятого издания
undefined: 4.3.9, 4.3.10, 8.1
Reference Error: 8.7.1, 8.7.2, 10.2.1, 10.2.1.1.4, 10.2.1.2.4 и 11.13.1.
Строгий режим для ECMAScript Annex C
Если вы обнаружите ошибки в переводе или в других областях, требующих доработки, добро пожаловать наПрограмма перевода самородковВы также можете получить соответствующие бонусные баллы за доработку перевода и PR. начало статьиПостоянная ссылка на эту статьюЭто ссылка MarkDown этой статьи на GitHub.
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.