Изучаем JavaScript при помощи иллюстраций
апреля 23, 2011 | Published in JavaScript | 1 Comment
Один из секретов отличного JavaScript разработчика — это ясное понимание семантики языка JavaScript. Эта статья расскажет вам об основных элементарных частях языка JavaScript используя простые для понимания иллюстрации того, как работают программы написанные на JavaScript.
Ссылки повсюду
В JavaScript переменные это просто ссылки, которые ссылаются на определенные значения, которые находятся в памяти компьютера. Эти значения могут иметь примитивный тип, такой, как: строка, число и булевы значения, но могут также являться объектами или функциями.
Локальные переменные
В ниже приведенном примере, мы создадим четыре локльные переменные в основной области видимости и сошлемся ими на некоторые примитивные значения:
//variable.js // Давайте создадим несколько локальных переменных в глобальной области видимости var name = "Tim Caswell"; var age = 28; var isProgrammer = true; var likesJavaScript = true; // Проверяем, ссылаются ли две переменные на одно то же значение isProgrammer === likesJavaScript; //output: => true
Обратите внимание на то, что обе переменные ссылающиеся на булево значение, ссылаются на одно и то же значение в оперативной памяти. Это объясняется тем, что примитивы (примитивные типы) неизменяемы и таким образом движок JavaScript оптимизрует потребление памяти и разделяет единственный экземпляр между всеми ссылками на него.
В коде примера мы проверяли ссылаются ли две ссылки на одно и то же значение используя оператор === и результатом было значение true.
Внешняя таблица [Scope] представляет внешнее замкнутое пространство, переменные которого являются локальным переменными основной области видимости, не путайте с свойствами глобального/window объекта.
Объекты и цепочки прототипирования
Объекты — это просто коллекции ссылок на другие объекты и прототипы. Единственное, что они добавляют к этим коллекциям — это цепочки прототипирования, когда вы пытаетесь обратиться к чему-то, чего нет в локальном (текущем) объекте, но есть в его родительском объекте.
// создаем родительский объект var tim = { name: "Tim Caswell", age: 28, isProgrammer: true, likesJavaScript: true } // создаем дочерний объект var jack = Object.create(tim); // локально переопределяем свойства нового объекта jack.name = "Jack Caswell"; jack.age = 4; // получаем доступ к содержимому через цепочку прототпрования jack.likesJavaScript; //output: => true
Здесь мы имеем один объект с четырмя свойствами на который ссылается переменная tim. Также мы создал новый объект который наследуется от первого объекта на который ссылается переменная jack. Затем мы перегружаем два свойства в локальном объекте.
Теперь, если взглянуть на jack.linesJavaScript, мы первым делом найдем объект, на который ссылается переменная jack. Затем мы найдем свойство likesJavaScript. Поскольку оно не определено в текущем объекте, мы обращаемся к родительскому объекту где оно определено. Затем мы находим значение true, на которое ссылается это свойство.
Глобальный объект
Все удивляются, почему инструменты типа jslint всегда напоминают о необходмости использования выражения var при определении переменных. Если забудете набрать var, то вот что произойдет:
#gloals.js var name = "Tim Caswell"; var age = 28; var isProgrammer = true; // Ой! Мы забыли var likesJavaScript = true;
Обратите внимание, что likesJavaScript теперь является свойством глобального объекта, а не свободной переменной снаружи замыкания. Это имеет реальное значение только если вы собираетесь совместить несколько скриптов, что являеться очень частой практикой при написании реальных приложений.
Всегда помните об использовании выражения var при объявлении переменных для удержания пространств ваших переменных в текущем замыкании и его потомках — вложенных замыканиях. Вы будете очень счастливы, если будете придерживаться этого простого правила.
Если вы должны добавить что-то в глобальный объект, делайте это при помощи window.woo для браузерных приложений и global.goo в node.js.
Функции и Замыкания
JavaScript не просто набор объединенных (вложенные в цепочку) структур данных. Язык JavaScript включает также исполняемые вызываемые куски кода, обзываемые функциями. Эти функции создают объединенные пространства и замыкания.
Представление замыканий
Функции могут быть описаны как специальные объекты, которые содержат исполняемый код помимо свойств. Каждая функция имеет специальное свойство scope, которое представляет окружение в котором она была объявлена. Если функция возвращается из другой функции, то эта ссылка на старое окружение закрыта новой функцией в замыкании.
В этом примере мы создадим простой метод-фабрику функций, который создает замыкание и возвращает функцию.
#closure.js function makeClosure(name) { return function () { return name; }; } var description1 = makeClosure("Cloe the Closure"); var description2 = makeClosure("Albert the Awesome"); console.log(description1()); console.log(description2()); //output: //Cloe the Closure //Albert the Awesome
Когда мы вызываем description(), то движок JavaScript ищет функцию, на которую переменная ссылается и выполняет ее. После обращения к функции, функция ищет локальную переменную name, которую в результате находит в пространстве замыкания. Этот метод-фабрика функций является отличным примером, поскольку каждая созданная им функция имеет свое собственное пространство для локальных переменных.
Разделяемые функции и this
Иногда в целях повышения производительности или просто из-за предпочтения такого стиля, JavaScript предоставляет программистам ключевое слово this, которое позволяет вам повторно использовать функциональный объект в отличном пространстве в зависимости от того, как функция была вызвана.
Здесь мы создадим несколько объектов, которые будут предоставлять простую функцию. Эта функция будет ссылаться на this внутри для того, чтобы показать как она будет меняться от вызова к вызову.
//function.js var Lane = { name: "Lane the Lambda", description: function () { return this.name; } }; var description = Lane.description; var Fred = { description: Lane.description, name: "Fred the Functor" }; // Вызываем функцию из четырех различных пространств console.log(Lane.description()); console.log(Fred.description()); console.log(description()); console.log(description.call({ name: "Zed the Zetabyte" })); //output: //Lane the Lambda //Fred the Functor //undefined //Zed the Zetabyte
На иллюстации, мы видим что даже хотя переменная Fred.description была установлена в Lane.description, это реально просто ссылание на функцю. Таким образом все три ссылки имеют равные права собственности на анонимную функцию. Это причина того, почему я не пытался вызвать функцию на прототипах конструктора «methods». Причина этому то, что это подразумевает некоторый вид приплетения функции к конструктору и его «классу».
Оригинал статьи на английском:
апреля 27, 2011 at 17:07 (#)
спасибо за фронт-енд)