Насколько опасно в JavaScript предполагать, что undefined не перезаписывается?

86

Каждый раз , когда кто -то упоминает тестируется undefined, это отметил, что undefinedэто не является ключевым словом , так что может быть установлен"hello" , так что вы должны использовать typeof x == "undefined" вместо этого. Мне это кажется смешным. Никто бы никогда этого не сделал, и если бы они это сделали, это было бы достаточной причиной, чтобы никогда не использовать какой-либо код, который они написали ... верно?

Я нашел один пример того, как кто-то случайно установил undefinedэто null, и это было причиной, чтобы не предполагать, что undefinedон не перезаписан. Но если бы они сделали это, ошибка осталась бы незамеченной, и я не вижу, как это лучше.

В C ++ все прекрасно понимают, что это законно говорить #define true false, но никто никогда не советует избегать trueи использовать 0 == 0вместо этого. Вы просто предполагаете, что никто никогда не будет достаточно большим придурком, чтобы сделать это, и если они это сделают, никогда больше не будут доверять своему коду.

Укусило ли это когда-нибудь кого-то, кого назначили undefined(специально), и это нарушило ваш код, или это скорее гипотетическая угроза? Я готов рискнуть и сделать свой код более читабельным. Это действительно плохая идея?

Повторюсь, я не спрашиваю, как защититься от переназначенного undefined. Я уже сто раз видел эти трюки. Я спрашиваю, насколько опасно не использовать эти уловки.

Космологический символ
источник
7
Я был бы счастлив, но мне кажется, что ни один из трех приведенных ответов не дает хорошего ответа на вопрос. Я попытался дать понять, что не прошу перефразировать ответы, на которые я ссылался, но это все равно то, что я получил. Если не принять ответ, даже если это не то, о чем я просил, считается глупым, дайте мне знать, и я приму его!
Cosmologicon
1
Я думаю, что здесь изложены все факты. Итак, вы говорите, что вместо этого хотите получить субъективный ответ или мнение, что приводит только к разногласиям. Это причина того, что фраза «передовой опыт» не допускается в заголовках вопросов. Вы единственный человек, который может знать, насколько это опасно в вашем сценарии. И если вы пишете популярную библиотеку, в которой вы не контролируете все «переменные», обертка function (undefined) {} ​​кажется отличным ответом. Почему бы не использовать его и не принять этот ответ?
шеннон
4
Если кто-то беспокоится о том, что кто-то изменит определение undefined, вам следует больше беспокоиться о том, что кто-то переопределит XMLHttpRequest, или alert. Все функции, которые мы используем, windowможно было бы переопределить. И если вы просто беспокоитесь о том, что коллега сделает это случайно, почему бы ему не доверять window.addEventListener = "coolbeans"? Ответ - не беспокоиться ни о чем из этого. Если кто-то злонамеренно внедряет JS на вашу страницу, вы все равно попадаете под удар. Работайте над предотвращением этого в первую очередь.
Крис Миддлтон,

Ответы:

56

Нет, никогда. В основном это связано с тем, что я разрабатываю современные браузеры, которые в основном совместимы с ECMAScript 5. Стандарт ES5 требует, чтобы undefinedтеперь это было только чтение. Если вы используете строгий режим (вы должны), вы получите ошибку, если вы случайно попытаетесь его изменить.

undefined = 5;
alert(undefined); // still undefined
'use strict';
undefined = 5; // throws TypeError

Чего вам не следует делать, так это создавать собственную изменяемую область видимости undefined:

(function (undefined) {
    // don't do this, because now `undefined` can be changed
    undefined = 5;
})();

Постоянный - это нормально. Все еще ненужно, но нормально.

(function () {
    const undefined = void 0;
})();
Ry-
источник
Ваш первый оператор только гарантирует, что вы случайно не перезапишете undefined во время разработки, он по-прежнему представляет ту же угрозу при работе с другим кодом на клиентских компьютерах.
bennedich
1
@bennedich: Я знаю, я говорил, что никогда не сталкивался с этой проблемой, но вот что тебе следует сделать .
Ry-
1
@bennedich Разве у вас нет шансов случайно перезаписать любую другую переменную?
Атес Горал,
40

Никакой правильный код не сделает этого. Но вы никогда не узнаете, что сделал какой-нибудь подражатель-умный разработчик или плагин / библиотека / скрипт, который вы используете. С другой стороны, это крайне маловероятно, и современные браузеры вообще не допускают перезаписи undefined, поэтому, если вы используете такой браузер для разработки, вы быстро заметите, пытается ли какой-либо код перезаписать его.


И даже если вы не просили об этом - многие люди, вероятно, найдут этот вопрос, когда будут искать более распространенную undefinedпроблему «как защититься от переопределения », поэтому я все равно на это отвечу:

Есть очень хороший способ получить действительно undefined undefined независимо от возраста браузера:

(function(undefined) {
    // your code where undefined is undefined
})();

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

(function($, window, undefined) {
    // your code where undefined is undefined
})(jQuery, this);

Тогда вы можете быть уверены, что внутри этой анонимной функции верны следующие вещи:

  • $ === jQuery
  • window === [the global object]
  • undefined === [undefined].

Однако, обратите внимание , что иногда typeof x === 'undefined'на самом деле необходимо: Если переменная xникогда не была установлена на значение (вопреки быть набор к undefined), чтение xпо-другому , например , как if(x === undefined)будет сгенерировано сообщение об ошибке. Это не относится к свойствам объекта, поэтому, если вы знаете, что yэто всегда объект, if(y.x === undefined)это совершенно безопасно.

ThiefMaster
источник
2
Ваше утверждение о xтом, что значение не установлено, не совсем верно (см. Jsfiddle.net/MgADz ); скорее, если он действительно не определен (см. jsfiddle.net/MgADz/1 ).
Ry-
7
Опять же, если кто-то случайно скажет, undefined = someVariableчто это ошибка, и вы хотите, чтобы что-то сломалось. По крайней мере, я знаю.
Cosmologicon
2
Я работал с кодовой базой, в которой был минимизированный устаревший скрипт, который перезаписывал undefined, у нас не было времени или бюджета, чтобы переписать скрипт, это пример, когда требуется typeof x == "undefined", это не так странно и, вероятно, хорошая привычка.
Damen TheSifter
2
Меня интересует, почему во всех примерах используется «undefined» в качестве дополнительного аргумента функции? Но может возникнуть ситуация, если кто-то передаст один дополнительный параметр (определенный) по ошибке, и вся логика не удастся. Почему бы не использовать что-то вроде function () {var _undef; if (someVal == _undef) {сделать что-нибудь}};
Oleksandr_DJ
4
@Oleksandr_DJ Именно так. Составляет значение , которое вы знаете , есть undefinedи назначьте к undefinedв области. Не оставляйте undefinedоткрытым для перезаписи, если вы передаете "слишком много" аргументов. Это приводит к ошибкам и по своей сути не является защитным паттерном, особенно когда, как указывает Лусеро , есть очень простые альтернативы для получения твердых undefinedзначений в масштабе.
ruffin
19

Для этого есть простое решение: сравнить, против void 0которого всегда не определено.

Обратите внимание, что вам следует избегать, ==поскольку это может привести к изменению значений. Вместо этого используйте ===!==).

Тем не менее, неопределенная переменная может быть установлена ​​по ошибке, если кто-то пишет =вместо того, чтобы ==сравнивать что-то с undefined.

Lucero
источник
ИМО, это лучший ответ.
abhisekp
1
Учтите, что это foo === void 0может читаться не так гладко, foo === undefinedи что неизменяемый undefinedполностью поддерживается современными браузерами (IE 9+), как вы можете видеть в этой таблице совместимости.
Daniel AR Werner
3

Только вы знаете, какой код используете и насколько он опасен. На этот вопрос нельзя ответить так, как вы пояснили, что хотите.

1) Создайте командную политику, запретив переопределение undefined, зарезервировав ее для более популярного использования. Отсканируйте существующий код на предмет неопределенного левого назначения.

2) Если вы не контролируете все сценарии, если ваш код используется вне ситуаций, контролируемых вами или вашими политиками, то, очевидно, ваш ответ будет другим. Отсканируйте код, который использует ваши скрипты. Черт возьми, просканируйте Интернет для статистики неопределенного левого назначения, если хотите, но я сомневаюсь, что это было сделано для вас, потому что вместо этого проще просто получить ответ №1 или №3.

3) И если этого ответа недостаточно, это, вероятно, потому, что вам снова нужен другой ответ. Возможно, вы пишете популярную библиотеку, которая будет использоваться внутри корпоративных брандмауэров, и у вас нет доступа к вызывающему коду. Тогда используйте здесь один из других хороших ответов. Обратите внимание, что популярная библиотека jQuery практикует инкапсуляцию звука и начинается так:

(function( window, undefined ) {

Только вы можете ответить на ваш вопрос так, как вы ищете. Что еще сказать?

edit: ps, если вам действительно нужно мое мнение, я скажу вам, что это совсем не опасно. Все, что может вызвать дефекты (например, присвоение undefined, что, очевидно, является хорошо задокументированным рискованным поведением), само по себе является дефектом. Риск - это дефект. Но это только в моих сценариях, где я могу позволить себе придерживаться такой точки зрения. Как я рекомендую вам, я ответил на вопрос для своих вариантов использования.

Шеннон
источник
3

Тестировать с undefined безопасно. Как вы уже упомянули. Если вы дойдете до какого-то кода, который его переопределяет (что в значительной степени поправимо), просто не используйте его больше.

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

Барт Каликсто
источник
2

Вы можете использовать undefinedв своем коде при кодировании для браузеров, поддерживающих ECMAScript 5.1, поскольку он неизменяем в соответствии со спецификацией языка .

Также см. Эту таблицу совместимости или этот caniuse ECMAScript 5, чтобы увидеть, что все современные браузеры (IE 9+) реализовали неизменяемыйundefined .

Даниэль Ар Вернер
источник
1

Это совсем не опасно. Его можно перезаписать только при работе на движке ES3, и вряд ли он больше будет использоваться.

Кирк Бурлесон
источник
0

Прежде всего, если ваш код ломается, это, вероятно, не потому, что какой-то другой разработчик «пытается быть придурком», как вы выразились.

Верно, что undefinedэто не ключевое слово. Но это глобальный уровень примитивно. Он был предназначен для использования следующим образом (см. «Undefined» на developer.mozilla.org ):

var x;
if (x === undefined) {
    // these statements execute
}
else {
    // these statements do not execute
}

Общая альтернатива этому (также от MDN ) и, на мой взгляд, лучший способ:

// x has not been declared before
if (typeof x === 'undefined') { // evaluates to true without errors
    // these statements execute
}

if(x === undefined){ // throws a ReferenceError

}

У которого есть несколько преимуществ, очевидное (из комментариев) заключается в том, что он не вызывает исключение, когда x не объявлен. Также стоит отметить, что MDN также указывает на важность использования ===over ==в первом случае, потому что:

var x=null;
if (x === undefined) {
    // this is probably what you meant to do
    // these lines will not execute in this case
}
else if (x == undefined) {
    // these statements will execute even though x *is* defined (as null)
}
else {
    // these statements do not execute
}

Это еще одна часто упускаемая из виду причина, по которой, вероятно, во всех случаях лучше просто использовать вторую альтернативу.

Вывод: кодировать первым способом нет ничего плохого и уж точно не опасно. Аргумент, который вы видели, который вы используете в качестве примера против него (что его можно перезаписать), не является самым сильным аргументом в пользу кодирования альтернативы typeof. Но использование typeofлучше по одной причине: оно не вызывает исключения, если ваш var не объявлен. Можно также возразить, что использование ==вместо ===- распространенная ошибка, и в этом случае он не выполняет то, что вы ожидали. Так почему бы не использовать typeof?

Осьминог
источник
1
«У этого есть несколько преимуществ, очевидное из которых состоит в том, что он не вызывает исключения, если x не объявлен». Позвольте мне уточнить это. Считаете ли вы преимуществом молчаливое игнорирование исключения, возникающего при использовании необъявленной переменной? Это кажется очень подверженным ошибкам. Вы можете объяснить, почему вы думаете, что это не ужасный недостаток?
Cosmologicon