1 сентября 2011 в 08:27

Область видимости в JavaScript и «поднятие» переменных и объявлений функций перевод

Вы знаете, какое значение выведет этот код на JavaScript?
var foo = 1; 
function bar() { 
    if (!foo) { 
        var foo = 10; 
    } 
    alert(foo); 
} 
bar();


Если вас удивляет, что выведется «10», то следующий код вас и вовсе запутает:
var a = 1; 
function b() { 
    a = 10; 
    return; 
    function a() {} 
} 
b(); 
alert(a);

В этом случае браузер выведет «1». Так что, собственно, происходит? Хотя такое поведение кажется странным, опасным и сбивающим с толку, на самом деле это очень мощное и выразительное средство JavaScript. Я не знаю, есть ли официальное название для такого поведения, но мне нравится использовать термин «поднятие»(«hoisting»). В этой статье я попытаюсь пролить свет на этот механизм языка, но сначала давайте поговорим об области видимости в JavaScript.

Область видимости в JavaScript


Одна из причин, приводящих в замешательство новичков, — это область видимости. Вообще, не только новичков. Я встречал много опытных JavaScript-разработчиков, которые не понимают механизм области видимости в JavaScript. Причина в том, что внешне JavaScript очень похож на любой другой Си-подобный язык.
Давайте рассмотрим следующий код на Cи:
#include <stdio.h> 
int main() { 
    int x = 1; 
    printf("%d, ", x); // 1 
    if (1) { 
        int x = 2; 
        printf("%d, ", x); // 2 
    } 
    printf("%d\n", x); // 1 
}


Эта программа выведет 1, 2, 1, потому что Си и все остальные Си-подобные языки реализуют области видимости на уровне блоков кода. Когда исполняется новый блок кода, например условие if, новые переменные, объявленные в нём, не повлияют на переменные внешней области видимости.
Но не в случае JavaScript. Попробуйте запустить вот этот код в Firebug:
var x = 1; 
console.log(x); // 1 
if (true) { 
    var x = 2; 
    console.log(x); // 2 
} 
console.log(x); // 2

На этот раз будут выведены числа 1, 2, 2. Это связано с тем, что в JavaScript используется область видимости на уровне функций. Это совсем не то, что мы привыкли видеть в языках программирования, вроде Си. Блоки кода, вроде того, который у нас идёт сразу после if, не создают новую область видимости. Только функции создают новые области видимости.
Для многих программистов, привыкших к Си, C++, C# или Java такое поведение очень неожиданное и неприятное. К счастью, благодаря гибкости функций JavaScript, можно обойти эту проблему. Чтобы создать временную область видимости внутри функции, достаточно сделать следующее:
function foo() { 
    var x = 1; 
    if (x) { 
        (function () { 
            var x = 2; 
            // какой-то код
        }()); 
    } 
    // x всё ещё 1. 
}

Такой подход достаточно гибок и может быть использован везде, где вам нужна временная область видимости, не только внутри блоков кода. Но я настаиваю на том, чтобы вы всё-таки потратили своё время, чтобы понять реализацию области видимости в JavaScript. Это довольно мощная особенность языка, которая мне очень нравится. Если вы понимаете область видимости, вам проще будет разобраться в «поднятии» переменных и объявлений функций.

Объявления, именование и «поднятие» переменных и функций


В JavaScript существует четыре основных способа появления идентификатора в области видимости:
  1. Внутренние механизмы языка: например, во всех областях видимости доступны this и arguments.
  2. Формальные параметры: у функций могут быть именованные формальные параметры, область видимости которых ограничена телом функции.
  3. Объявления функций: объявленные в виде function foo() {}.
  4. Объявления переменных: например, var foo;.

Интерпретатор JavaScript всегда незаметно для нас перемещает («поднимает») объявления функций и переменных в начало области видимости. Формальные параметры функций и встроенные переменные языка, очевидно, изначально уже находятся в начале. Это значит, что этот код:
function foo() { 
    bar(); 
    var x = 1; 
}

на самом деле интерпретируется так:
function foo() { 
    var x; 
    bar(); 
    x = 1; 
}

Оказывается, не важно, будет ли вообще выполнена строка, в которой происходит объявление. Следующие две функции эквивалентны:
function foo() { 
    if (false) { 
        var x = 1; 
    } 
    return; 
    var y = 1; 
} 
function foo() { 
    var x, y; 
    if (false) { 
        x = 1; 
    } 
    return; 
    y = 1; 
}

Обратите внимание, что присваивание значений переменным не поднимается вместе с их объявлением. Поднимаются только объявления переменных. В случае с функциями, поднимается вся функция целиком. Существуют два основных способа объявить функцию, давайте их рассмотрим:
function test() { 
    foo(); // TypeError "foo is not a function" 
    bar(); // "this will run!" 
    var foo = function () { // функциональное выражение, присвоенное локальной переменной 'foo' 
        alert("this won't run!"); 
    } 
    function bar() { // объявление функции с именем 'bar' 
        alert("this will run!"); 
    } 
} 
test();

в этом случае поднимается только функция bar. Идентификатор «foo» также поднимается, но не анонимная функция — она остаётся на месте.

Вот мы и описали основные моменты «поднятия» переменных и функций. Конечно, JavaScript не был бы сам собой, если бы не было особых случаев, в которых всё немного сложнее.

Разрешение имён


Самый важный особый случай, который стоит иметь в виду, — это порядок разрешения имён. Вспомните, есть четыре способа появления идентификаторов в области видимости. Именно в том порядке, в котором я их упомянул, и происходит разрешение имён. В общем случае, если имя уже определено, оно никогда не будет переопределено другой сущностью с таким же именем. То есть объявление функции имеет приоритет над объявлениями переменной с таким же именем. Но это совсем не означает, что присваивание переменной значение не заменит функцию, просто её определение будет проигнорировано.
Есть несколько исключений:
  • Встроенный идентификатор arguments ведёт себя странно. Он как будто объявляется сразу после формальных аргументов функции и перед объявлениями функций. Это означает, что если у функции есть формальный аргумент arguments, у него будет приоритет над встроенным, даже если его не передадут при вызове функции. Это плохая особенность JavaScript. Не используйте формальный аргумент с именем arguments.
  • Если вы попробуете использовать this в качестве идентификатора, произойдёт ошибка SyntaxError. Это хорошая особенность.
  • Если в списке формальных параметров функции несколько из них имеют одинаковое имя, тот параметр, который упоминается последним, имеет приоритет. Даже если его не передали при вызове функции.

Именованные функциональные выражения


Вы можете давать имена функциям, определённым с помощью функциональных выражений, используя синтаксис определения функций. Это не приводит к объявлению функции, а следовательно, имя функции ни добавляется в область видимости, ни поднимается вместе с телом функции в начало области видимости. Вот несколько строк, чтобы проиллюстрировать, что я имею в виду:
foo(); // TypeError "foo is not a function" 
bar(); // работает 
baz(); // TypeError "baz is not a function" 
spam(); // ReferenceError "spam is not defined" 
 
var foo = function () {}; // анонимное функциональное выражени (поднимается 'foo') 
function bar() {}; // объявление функции (поднимаются 'bar' и тело функции) 
var baz = function spam() {}; // именованное функциональное выражение (поднимается только 'baz') 
 
foo(); // работает 
bar(); // работает 
baz(); // работает 
spam(); // ReferenceError "spam is not defined" 

Как писать код, обладая такими знаниями


Итак, теперь вы понимаете область видимости и «поднятие» переменных и объявлений функций. Что это означает применительно к написанию кода на JavaScript? Самое главное — всегда объявлять ваши переменные, используя var. Я настаиваю на том, чтобы у вас был ровно один var на область видимости и чтобы он располагался в её начале. Если вы заставите себя так делать, у вас никогда не будет проблем, связанных с «поднятием». Тем не менее, это может привести к тому, что сложно следить за переменными, которые объявлены в текущей области видимости. Я рекомендую использовать JSLint с включённой опцией onevar, чтобы вынудить вас так делать. Если вы будете так всё делать, ваш код будет выглядеть примерно так:
/*jslint onevar: true [...] */ 
function foo(a, b, c) { 
    var x = 1, 
        bar, 
        baz = "something"; 
} 


Что говорит стандарт


Достаточно полезно обращаться к стандарту ECMAScript напрямую, чтобы понять, как всё работает. Вот что в нём говорится про объявление переменных и область видимости(секция 12.2.2):
Если инструкция переменной встречается внутри ОбъявленияФункции, переменные объявляются внутри локальной области видимости для данной функции согласно описанию в разделе 10.1.3. В противном случае они объявляются в глобальной области видимости (т.е. создаются как поля глобального объекта согласно описанию в разделе 10.1.3) с использованием атрибутов свойств { DontDelete }. Переменные создаются, когда происходит вход в область выполнения. Блок не определяет новой области выполнения. Только Программа и ОбъявлениеФункции создают новую область видимости. Переменные инициализируются при создании значением undefined. Переменной, для которой определён Инициализатор, присваивается значение его ВыраженияПрисваивания в момент выполнения ИнструкцииПеременной, а не в момент создания переменной.

Я надеюсь, эта статья пролила немного света на особенность JavaScript, которая так часто многих приводит в замешательство. Я старался быть как можно более последовательным, чтобы не запутать вас ещё сильнее. Если я в чём-то ошибся или что-то пропустил, пожалуйста, дайте мне знать.
Перевод: Ben Cherry
Алексей @Li0liQ
карма
46,8
рейтинг 0,0
Front-end developer
Самое читаемое Разработка

Комментарии (71)

  • +6
    Область человек видимости?
    • +1
      Роботы на Хабре )
    • 0
      Проверял русский спелчекер… Спасибо, исправил.
  • –1
    >Область человек видимости в JavaScript переменных и объявлений функций
    Промт такой промт.
    • +6
      Переводчик или пошутил или ошибся. Топик, в целом, переведен неплохо.
  • 0
    Я не знаю, есть ли официальное название для такого поведения, но мне нравится использовать термин «поднятие»(«hoisting»).

    Это «замыкание» (closure).
    • +3
      Также добавлю, что в новом JavaScript есть ключевое слово «let», которое используется так же, как и var, но реализует такой же принцип области видимости, как в Си — на уровне блоков.
    • +3
      Там именно hoisting, т.к. Function Declaration определяются на момент входа в контекст функции.
      • –3
        И почему «hoisting», если в JavaScript это называется «closure»?
        • +4
          При чем тут closure? Замыкание--это как бы автоматическая передача в анонимную функцию всех внешних переменных. А в статье имеется в виду поднятие к началу функции объявления переменных из этой же функции.
          • +1
            Хм, я не так смотрел на определение, думал он имеет ввиду именно передачу в функцию внешних переменных.
        • +1
          Ты помоему немного в терминах запутался.
          Замыкание это по сути механизм определения функций, ничего про переменные он не описывает.
          • +1
            Не определения, а… черт, замыкание несколькоих локальных переменных таким образом, чтоб они были доступны в функции, которая может быть «отдана» за пределы видимости замыкаемых переменных.

            Простейший пример замыкания:
            function a() {
               var x = 5;
               return function() { return x; }
            }
            

            тут происходит замыкание переменной «х» внутрь возвращаемой функции.

            Это никак не относится к hoisting-гу, который определяет видимость деклараций переменных и названий функций.

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

            К примеру, «замыкание» на С# реализованно через создание анонимных классов, члены которого содержат «замкнутные» переменные, и который создается тогда, когда мы используем эти переменные и экземпляр которого доступен в «замкнутых» функциях (делегатах).

            В то же время, если бы в С# было бы «поднятие», то оно было бы реализованно строго на уровне синтаксического анализатора, не создавая никаких новых сущностей (как в «замыкании»).

            Мне кажется тут действительно серьезное отличие. И ИМХО лучше бы не было «поднятия» — оно только конфузит чтение кода.
    • 0
      Stoyan Stefanov. JavaScript Шаблоны 2011 — используется термин «подъем».

      • 0
        Вобще более прижившийся перевод термина hoisting — всплытие, но не суть.
  • 0
    Простите, а зачем () в пятом примере в строке после "//какой-то код"?
    • +3
      Чтобы выполнить анонимную функцию, которая используется для создания области видимости.
      • 0
        Спасибо. Впервые просто с таким сталкиваюсь.
  • 0
    Спасибо, интересно и познавательно. Только зачем так было сделано? Одна из раскоряк, из-за которых можно не любить js.
    • 0
      Php, lua и ряд других языков используют туже модель.
      Хотя только в php(имхо) правильно додумались еще добавить возможность указывать нужные импорты из parent scope(как бы это на русском то сказать?)
      • 0
        parent scope (как бы это на русском то сказать?)
        «Из уровня выше». На деле же в PHP из глобальной зоны видимости.
        • 0
          я имел в виду именно локальную зону видимости.
          Бичь js — хавание(всех без разбору) видимых переменных замыканиями с последующими утечками памяти в php обходиться ну очень просто.
          • 0
            я имел в виду именно локальную зону видимости.
            В каком месте? Я уже запутался.
            Бичь js — хавание (всех без разбору) видимых переменных замыканиями с последующими утечками памяти в php обходиться ну очень просто.
            Я не понимаю почему это бич JS. Объясните?
          • 0
            я имел в виду именно локальную зону видимости.
            Я понял о чём вы говорили — о синтаксисе анонимных функций в PHP 5.3, я думал совсем о другом.
          • 0
            ну вы преувеличиваете, указание локальной видимости еще было в Perl: my, our, local.
            • 0
              В нем и не такие перлы есть
      • +1
        Кстати,

        global $var в PHP — синтаксический сахар от $var =& $GLOBALS['vars'].
        • 0
          Эх коммандер, но вот кого не ожидал глобала так от Вас.
          Руки — руки отрывать за глобалы как в php так и в js.
          • 0
            У меня ощущение, что я разговариваю с двумя людьми под одним логином. Вы написали:
            Хотя только в php (имхо) правильно додумались еще добавить возможность указывать нужные импорты из parent scope (как бы это на русском то сказать?)
            Вы же про global $var пишете, нет? Я и уточнил кое-что про global $var.
            • 0
              я говорил про замыкания.
              function a(){
              $somevar= 1;
              $someotherVal = 'a very big string';
              $closure = function (b) use($somevar){
              return b($somevar)
              }
              return $closure;
              }

              a(function($v){echo($v))}


              тут — someotherVal — будет скушано GC, в JS — она получит count++ так как видима из замыкания и не сожрется GC.
              Особо тяжко в JS это проявлятся в IE при общении с DOM.
              • 0
                Я уже понял.
              • 0
                Особо тяжко в JS это проявлятся в IE при общении с DOM.
                Это проблемы IE, а не JS.

                Я не в курсе какой GC в JS и есть ли какой-то, положенный по стандарту, но всем проблемам с освобождением ссылок (в т.ч. циклических) не один год и они все более-менее имеют решение. PHP получил хороший GC только недавно и от дизайна языка это никак не зависит.
                • 0
                  Да вот как-то не совсем это ИЕ проблемы.
                  В ИЕ просто GC на дом ноды( как на НЕ обьекты JS ) не распространяется.
                  В любых других браузерах теже грабли — пока последний адресатор стека не помреть — все переменные стека не умрут.
                  Решения этих проблем есть, и это часто очень простые решения, но 90% современных любителей jquery либо их не знают, либо им не следуют
                  • 0
                    Тем лучше! Давайте пользоваться тем, что у нас с вами есть конкурентное преимущество!
          • 0
            Ага, кажется я догадался. Вы о синтаксисе PHP 5.3 для анонимных функций.
          • НЛО прилетело и опубликовало эту надпись здесь
      • 0
        в Lua с областью видимости все нормально: local x будет виден в пределах блока, в котором объявлен.
        • 0
          Первое что неделями и месяцами мне сносило моск когда я лет 10 назад начинал прикручивать Lua будучи ярыми Сишником — что там нужно было специально просить чтобы переменная не вываливалась наружу.
          Кончилось тем что поправил исходники чтобы lua стал синтаксически больше похож на Си. В то же время тем же самым занимались еще трое знакомых, почти что тенденция была.
          Сейчас все молча жрут кактус :)
          • 0
            > что там нужно было специально просить чтобы переменная не вываливалась наружу.

            вы про то, что любая переменная не объявленная локально считается глобальной? есть такое. это решение мне кажется достаточно логичным.

            кстати можно провести параллель с C — если функцию вызываете без декларации, то только на этапе линковки обнаружится проблема ;-)
    • 0
      Вероятно, чтобы не смешивать локальные переменные и уровень выше.
    • +1
      Когда создавался JavaScript, так было принято. ЕМНИП, тоже лексическое объявление переменных в C появилось только в C99 — до этого область видимости была тоже на уровне функции.

      На самом деле, статья написана в довольно «шаманской» манере (как, впрочем, и многие прикладные мануалы по JavaScript). Для того, что бы не ошибаться, главное не путать объявления с определениями и присваиваниями, формальные параметры с фактическими, имена переменных и ключевые слова, переменные и память, в которой они размещаются, ссылки и значения и т.д. и т.п. В нормальном курсе обучения программисты всё это проходят и никаких проблем у них не возникает. А вот если они учатся методом тыка, то… :)
      • 0
        Да ладно область видимости, мне больше не нравится что оно само, можно сказать, переделывает код, из-за чего можно говорить «вот этот код на самом деле будет выполняться вот в таком, другом, порядке». Очень не интуитивно. Понятно, что можно разобраться, почитать там и там, но принцип наименьшего удивления нарушен :)
      • 0
        уже в ALGOL 60 был нормальный block lexical scoping, С++ (в те времена C with Classes) в середине 80x так же подхватил эту идею.
        • 0
          Может, у меня слишком узкий круг знакомых, но на них нет ни одного программиста на Алголе…

          А в C++ в то время, ЕМНИП, block scoping у многих компиляторов был ущербный — в частности, переменные, объявляемые в условиях циклов, определялись во внешних блоках, а не во внутренних, как сейчас.
          • 0
            Причем здесь ваши знакомые, это ведь не вы JavaScript изобретали. Я думаю в JavaScript забили на block scoping по какой-то другой причине, а не потому что не знаю про такую фичу.

            Формально то что объявляется в C++ в for лежит за пределами блока {}, поэтому объявления и не входили в блок. Там и сейчас не все как во внутреннем блоки, т.к. инициализация делается один раз, а не каждый раз как для остальных переменных внутреннего блока цикла.
            • 0
              Скорее всего, просто было проще сделать интерпретатор. На этапе парсинга поднимаем объявления к соответствующему узлу AST, после чего при входе в контекст (евала этого узла) сразу резервируем контейнер под соответствующие ссылки, который существует до выхода из контекста. Точно также в С++ место под переменную на стеке на самом деле определяется на этапе компиляции и в некоторых компиляторах при определённом хакинге можно присваивать и модифицировать содержимое переменной до её объявления.

              Там и сейчас не все как во внутреннем блоки

              Всё точно также. Просто, опять же, понятие lexical block scoping выходит за рамки block, определённого в C++ (думаю, только в лиспо-подобных языках он может совпадать, т.к. там «ключевые слова» операторов входят в состав некоей формы, которая своими скобками и ограничивает явно область видимость). В частности, тело цикла совсем необязательно обрамлять {}, что бы переменные, объявленные в условии не утекли наружу, равно как и наоборот, одиночный блок {} не вводит нового стекового контекста и место под переменные, объявлённые в этом блоке выделяется и определяется ещё до начала выполнения описанных внутри тела функции инструкций и определений.
              • 0
                > Скорее всего, просто было проще сделать интерпретатор.
                Мне кажется это логичной причиной, но не понятно что за ней скрывалось. Может что-то для замыканий нужно было, там же своя система работы с контекстами, возможно уровень функций здорово все упрощает.
            • 0
              P.S. а знакомые при том, что JavaScript создавался как практичный язык. Нафига там LBS, если им на тот момент пользовалось очень малое кол-во людей? Напомню, большинство практически используемых языков тогда требовало объявления переменных либо перед телом фукнции, либо первыми её предложениями. Собственно, и проблемы f(){i=99; if (..) { var i = 42; } } не возникало, т.к. все писали f(){ var i=99, j = 15, k, l, m=23; if (..) { i = 42; } }
  • 0
    Да, первый пример сначала вгоняет в ступор, и потом только до меня дошло, что привычка использовать лямбда-функции немного расслабляет.
  • 0
    Stoyan Stefanov перечисляет такие преимущества использования Single var Pattern:

    • Provides a single place to look for all the local variables needed by the function
    • Prevents logical errors when a variable is used before it’s defined (see “Hoisting: A
    Problem with Scattered vars” on page 14)
    • Helps you remember to declare variables and therefore minimize globals
    • Is less code (to type and to transfer over the wire)
  • –1
    Я правильно понимаю, что функция b(), определённая вышеприведённым кодом

    function b() {
       a = 10;
       return;
       function a() {}
    } 
    

    после всплытия внутренней функции обретает вид

    function b(){
       var a = function(){}
       a = 10;
       return;
    }
    

    в силу чего переменная a неожиданно для программиста становится локальною — так что как раз поэтому, хотя она и обретает значение 10 перед выходом по return, значение «a=10» не сумеет уйти из функции в одноимённую глобальную переменную?

    Неожиданно, конечно; но и поделом всякому любителю обозначать одним именем функцию и переменную в одной и той же области видимости, хотя бы и не в глобальной.
    • 0
      после всплытия будет выглядеть так:
      function b(){
      function a(){}
      a = 10;
      return;
      }


      Притом FD всплывают раньше чем перменные объявленные с помощью var т.е.
      function b(){
      var a = 1;
      function a(){}
      alert(a);
      }

      b() // 1
      • 0
        Вы уверены в том, что этот Ваш комментарий безупречно отражает именно то, что Вы хотели сказать?
        • 0
          Я спрашиваю потому, что приведённый мною выше код «после всплытия внутренней функции» имеет вид

          function b(){
             var a = function(){}
             a = 10;
             return;
          }
          

          который и без того совершенно соответствует и Вашему тезису «FD всплывают раньше, чем переменные», да притом и Вашему коду «после всплытия будет выглядеть так», отличаясь от Вашего кода только тем, что у меня в явном виде записано «var a = function(){}» (что было мне необходимо, так как я намеревался максимально ясно показать, как именно переменная a стала вдруг локальною в функции b().
          • НЛО прилетело и опубликовало эту надпись здесь
          • 0
            Там будет не
            var a = function(){}
            а
            var a = function a(){}
        • 0
          Этот мой комментарий, как вы указали, показывает как работает hoisting. Если вы будете более внимательны вы увидите разницу. Function Expression != Function Declaration и в своем ответе я вам как бы намекаю на эту разницу.
    • 0
      Почему неожиданно, в JS функции сразу инициализированы уже при входе в чейн (если описаны не через var), где бы они не были описаны (в пределах чейна), все логично вроде бы.
  • +3
    Если уж честно признаться, мне не особенно по нраву манера записывать определения переменных единственным var:

    var x = 1, 
        bar, 
        baz = "something";
    

    Предпочитаю вместо этого использовать несколько var кряду:

    var x = 1;
    var bar;
    var baz = "something";
    

    Причины такого предпочтения довольно просты:

    • смысл каждой строки («здесь объявляется переменная») явствует при первом же взгляде на неё и не утрачивается в том случае, если начало блока объявлений переменных откручено за верхний край окна с кодом (что бывает важно, если их там не три, как в примере, а пара-тройка-другая десятков);
       
    • пунктуация в конце строк единообразна: не нужно менять запятую на точку с запятой (и наоборот) в том случае, когда некоторая строчка кода внезапно начала (или перестала) быть последнею (то же самое и с началами строк: не нужно возёхаться с добавлением или устранением кодового слова «var», если та или иная строка начала или перестала быть первою);
       
    • если над одним и тем же кодом работают несколько человек, стоящих по разные стороны фронта священной войны за употребление пробелов и символов табуляции, то они не передерутся по вопросу о том, что должно стоять во второй строке (и во всех последующих строках) под «var»: отступ ли там, или табуляция, и если табуляция, то из пробелов или «табов» и какого размера.
    • 0
      Главное преимущество единственного var вполне очевидно — сжатие javascript. Если вы хотите сжать минификатором свой скрипт до как можно меньших размеров — необходимо использовать один и только один var.
      Последний пункт имеет изящное решение:
      var
          x = 1, 
          bar, 
          baz = "something";
      

      Любители холиваров остались без пищи.
      • +3
        Google Closure Compiler и UglifyJS умеют объединять все идущие подряд объявления переменных в одно, причём Uglify делает это умнее
      • +7
        преждевременная минификация — корень всех зол.
        • +2
          Преждевременная минификация — корень не всех зол, а только некоторых.
    • 0
      >если над одним и тем же кодом работают несколько человек,
      то у них должен быть единый стандарт кодирования.
  • НЛО прилетело и опубликовало эту надпись здесь
  • 0
    Ни первый ни второй код не вызывают удивления. Достаточно просто знать принципы. Нет переменных или функций или массивов. Есть объекты или хэши.
    А теперь опять посмотрите на примеры кода вначале статьи. Все стало простым и логичным.
    • +1
      Что значит нет переменных и как это объясняет то, что в начале статьи?
  • 0
    Было бы хорошо с упоминания JSLint сделать ссылку хотя бы на habrahabr.ru/tag/jslint/
  • +1
    У Дмитрия Сошникова есть прекрасная серия статей, в которых очень подробно разжевано все внутреннее устройства JavaScript (ECMA-262-3): dmitrysoshnikov.com/tag/ecma-262-3/
    Очень рекомендую.
  • –1
    Коллеги, используйте CoffeeScript, там большинство этих проблем даже не возникает.

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