Javascript: г = г || [] выдает ошибку, если VAR не используется - почему?

Из интеллектуального любопытства, почему javascript принимает

var z = z || [];

для инициализации z (как z может быть определено изначально)

но без var выдает ошибку (в глобальном пространстве)

z = z || [];

(если z ранее не определено)

В глобальном пространстве вы не обязаны использовать VAR, хотя я понимаю, что это может быть плохой практикой.

Прежде чем вы скажете, что это дубликат таких вопросов, как

Какова цель ключевого слова var и когда его использовать это (или опустить)?

Обратите внимание на заявление о том, что "Если вы находитесь в глобальной области, то нет никакой разницы".

Очевидно, что это не на 100% верно, учитывая мой рабочий пример.

Это причуда или законная логика?


добавив краткое изложение ответа, как я его узнал:

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

вар г; абсолютно ничего не делает, если z уже существует

Вот как это выражение, кажется, имеет оба варианта, если вы неверно предполагаете, что «var z» всегда инициализируется.

Начиная слева, «var z» просто гарантирует, что z определено, но на самом деле не влияет на какое-либо существующее значение, если оно уже существует. Затем справа, если z уже существует, она используется, если нет, переменная была только что объявлена ​​(но пуста), поэтому она не будет использоваться, но не вызовет ошибки.

Это отличная статья о такого рода проблемах с областью действия и подъемом в Javascript: http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting

Большое спасибо minitech и всем, кто внес свой вклад!


person ck_    schedule 30.01.2012    source источник
comment
Как правило, копирование фактического сообщения об ошибке обычно более полезно, чем просто запись ошибки.   -  person Álvaro González    schedule 30.01.2012


Ответы (3)


z = z || [] выдаст любую область (глобальную или нет), где нет z в цепочке областей видимости. Причина этого в том, что выражение сначала пытается получить значение существующей переменной с именем z в правой части, что является ошибкой, если ее не существует.

Причина, по которой var z = z || [] не выдает ошибку, заключается в том, что переменная z создается (если она еще не существует) до выполнения выражения, эффект, широко известный как подъем.

С другой стороны, присвоение значения неразрешенному идентификатору (например, z = 2) будет работать без ошибок в любой области (кроме строгого режима ECMAScript 5, который запрещает это и выбрасывает). Если идентификатор не может быть разрешен, он будет добавлен как свойство последнего объекта в цепочке областей видимости, который является глобальным объектом, что создает видимость создания глобальной переменной.

person Tim Down    schedule 30.01.2012
comment
Ах, я думаю, я понял. Таким образом, var z сначала выполняется с левой стороны, как указание создать новый z, но затем он ищет старый z с правой стороны. В этом порядке z только что был инициализирован слева, поэтому z справа не является неопределенным, хотя и пустым. Без переменной z справа не просто пуст, он не определен. Хм, ладно - если var z определяет его как новое слева, как тогда этот код сохраняет существующие значения? Кажется, что он работает в обоих направлениях, инициализирует слева направо, но также может сохранять значение справа. - person ck_; 30.01.2012
comment
@ck_: Да, я думаю, вы поняли, хотя терминология требует некоторой осторожности, потому что undefined является фактическим значением в JavaScript и фактически является значением по умолчанию, присвоенным переменной (например, var x; создает переменную с именем x с начальное значение undefined, которое отличается от несуществующего x, которое никогда не объявлялось). Я бы выбрал незадекларированные или несуществующие. - person Tim Down; 30.01.2012
comment
@ck_: Что касается сохранения существующих значений, var z; абсолютно ничего не делает, если z уже существует, каким бы ни было его значение. - person Tim Down; 30.01.2012
comment
вар г; абсолютно ничего не делает, если z уже существует - это объясняет мое непонимание этой проблемы в двух словах и почему я был сбит с толку. Я всегда предполагал, что var z; уничтожит существующую переменную и инициализирует ее пустой или нулевой или чем-то подобным. Теперь я понял это на 100% и, оглядываясь назад, кажется глупым вопросом! - person ck_; 30.01.2012

Эффект правильный. var всегда сразу объявляет свои «операнды», тогда как, если вы не объявляете его, ваш сценарий пытается использовать неопределенную переменную и выдает ошибку.

Если вы находитесь в глобальной области видимости, вы можете назначить несуществующую переменную, и это будет иметь тот же эффект, что и ее объявление, что может быть плохой практикой. Конечно, в вашем случае это не определено. При этом, хотя это может быть из интеллектуального любопытства, вы бы никогда не писали

var z = z || [];

потому что нет смысла так делать. Скорее, вы можете сделать:

if(!window.z) {
    window.z = [];
}

. На самом деле, когда я объявляю вещи в глобальной области видимости (которая никогда не бывает ;)), вместо этого я использую window.something, потому что это делает мои намерения более ясными.

person Ry-♦    schedule 30.01.2012
comment
когда вы не объявляете его, ваш сценарий пытается использовать неопределенную переменную — подождите, вы говорите, что z=z имеет доступ к z, а var z=z — нет? Второй z все еще находится в глобальной области видимости, как и первый, если он находится вне функции. (озадаченный) - person ck_; 30.01.2012
comment
@ck_: разница в том, что использование var приводит к созданию переменной z до выполнения каких-либо операторов. - person Tim Down; 30.01.2012

Вы можете присвоить необъявленной переменной z = 123; однако вы не можете пытаться читать то, что делает z = z || [].

person Alex K.    schedule 30.01.2012