Pull to refresh

Comments 36

Мне просто понравилось как тут всё разложено по полочкам.

Для тех, кто с js уже больше года тут, конечно ничего интересного не будет.
UFO just landed and posted this here
вы бы знали сколько людей приходит собеседоваться на миддл жс дева и понятия не имеет об описанном в этой статье.
Недавно даже книга появилась, которая называется You Don't Know JS: Scope & Closures, а скоро выйдет Objects & Prototypes той же серии. Видимо тема не скоро устареет. И я на несколько часов раньше вас опубликовал статью 2004го года Замыкания в Javascript [Часть 1], правда ее гораздо труднее читать.
UFO just landed and posted this here
Ненуачо.
1. Берём главу из Флэнагана
2. Разжевываем для ленивых
3. Рисуем пару диаграмм
4. ???
5. ПРОФИТ!
В главе про области видимости не сказано, что переменная будет доступна в дочерней области видимости (ближе к Global контексту) только в случае её прямого использования. Если вы попытаетесь динамически вызвать переменную, она не будет «проброшена» в дочерний контекст. В следующем примере первый вызов переменной a — динамический, второй — явный.

function test() { var a = 10; return function() { console.log(window['a']); }; }; test()(); //undefined

function test() { var a = 10; return function() { console.log(a); }; }; test()(); //10

PS: Простите, хабрапарсер съел \n. Вставьте в IDE и отформатируйте для читаемости.
UFO just landed and posted this here
В первом примере undefined, потому что вы переменную в глобальную область не положили. Можете попробовать вызвать динамический через eval, и получить значение переменной = 10.
Я думал он сейчас расскажет о другом. Если поставить в функцию точку останова и переменная в функции не используется, то gc скорее всего её уже подберёт, потому console.log(a) не даст 10.
да, изначально и хотел привести пример с дебаггером, ибо частенько сталкивался с этим. но почему-то казалось, что будет слишком муторно описывать и решил придумать другой пример.
придумал… спасибо за поправку, вы сказали именно о том, что я изначально хотел рассказать :)
Есть такое поведение у дебаггера, но это не повод для таких выводов. Переменная не доступна в дебаггере, но в реальности она доступна.
Про разворачивание циклов с вычислениями еще полезно упомянуть — у меня в asmcrypto.js таким образом неплохой буст получается.
Спасибо за упоминание вашей библиотеки. Думал уже OpenSSL или LibreSSL через emscripten заворачивать, а времени нет, и тут ваше! Буду использовать именно его, спасибо еще раз.

И, если не секрет, почему не опубликуете библиотеку в репозитории npm?
Она же для браузеров, я ее соответственно в bower опубликовал. А в npm своего добра хватает с нативными бэкэндами.
<ЗанудаМод>
(Стоит упомянуть что браузеры сохраняют ссылку на прототип в свойстве __proto__, но его использование очень портит карму, как минимум потому что его нет в стандарте ECMAScript, так что не надо его использовать).

В спецификации это свойство называется [[Prototype]].
All objects have an internal property called [[Prototype]]. The value of this property is either null or an object and is used for implementing inheritance. Whether or not a native object can have a host object as its [[Prototype]] depends on the implementation...

</ЗанудаМод>
Верно, я ступил, извиняюсь. __proto__ это свойство доступа (геттер, сеттер), изменяющее внутренне свойство [[Prototype]], а не переименованное [[Prototype]], как я решил.
Да нет, всё правильно, я же сказал: внесено в проект.
Прототип обьекта можно получить используя Object.getPrototypeOf.
Небольшое уточнение: __proto__ — это геттер/сеттер в прототипе объекта (Object.prototype.__proto__), а не самого объекта.

var o = Object.create(null);
o.__proto__; // => undefined, потому что мы не имеем доступа к Object#__proto__
// но
Object.getPrototypeOf(o); // => null
Всегда когда сталкиваюсь с JavaScript появляется вопрос про реализацию вложенных функций — они создаются (происходит парсинг, выделение памяти и т.д.) каждый раз по новой при вызове родительской функции или все-таки каким-то образом кэшируются? Потому что в первом случае получается что нужно абсолютно все функции делать именованными и глобальными.
Мне кажется v8 их точно кеширует

В сухом остатке, нужно всегда руководствоваться целесообразностью — выносить в глобальное или нет; как правило, от вынесения в глобальную область видимости нет никакого толка :)
JIT-компилируются; JIT-код кэишруется.
Точно не знаю как это реализовано, но описывают так: объект функции создается либо во время процесса создания переменных (variable instantiation), если это декларация функции. Либо во время выполнении операции присваивания (могут быть другие операции, например выполнение оператора группировки) т.е. на этапе интерпретации, если это функция-выражение (Function Expression). Когда вызывается внешняя функция, то в стек добавляется контекст исполнения, содержащий объект активации (Activation object AO). Этот AO содержит все формальные параметры, локальные переменные и ссылки на объекты функций, но только те, которые были созданы декларацией (они не могут быть без имени). А вот объекты функции созданные выражением (могут быть именованными, но почти не отличаются от анонимных) не засоряют AO (только если не присвоены локальной переменной).
Т.е. получается в случае деклараций функция, в контексте исполнения используются ссылки на уже созданные объекты. Насчет кэширования функций-выражений ничего не знаю.

Ответ на сообщение groaner.
console.log(p1.prototype);                // выводит 'undefined'
console.log(p1.prototype.getFullName());  // выкидывает ошибку


Вообще вторая строка ни о чём. Вызов метода с любым именем от undefined выкинет соответствующую ошибку.
При использовании прототипного наследования, помните о том, что свойства прототипа нужно (??) задавать после наследования от родительского объекта.

В оригинале:
When using prototypal inheritance, remember to define properties in the prototype after having either inherited from the parent class or specified an alternate prototype.

Оба высказывания неточны, а перевод просто неверен. Не «нужно». Причём, автор чуть выше сказал, что понимает возможность смены свойств прототипа после наследования. Мне кажется, тут в оригинале было пропущено слово «может» — надо не забывать, что свойства прототипов предков могут задаваться после наследования. Ничего не изменится, если мы их объявим до, но ошибки для программиста кроются как раз в возможности "после".
Насколько я понимаю, в данном контексте имелось ввиду что следует задавать специфичные для дочернего объекта свойства после того как произошло наследование, а не до.
Собственно приведенные вами слова это описание картинки дальше, я поправил перевод, сделав его более конкретным.
Спасибо за перевод статьи JavaScript Prototypes, Scopes, and Performance: What You Need to Know из нашего блога! Если обнаружатся какие-то ошибки в статье по ее сути — я помогу обеспечить связь с автором оригинала Diego Castorina, чтобы поправить ошибки.
Каждая функция это объект:

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
}

var p1 = new Person('John', 'Doe');
var p2 = new Person('Robert', 'Doe');


Может создаться впечатление, что p1 и p2 это новые функции. Но это не так. В результате выполнения этого кода образуются три переменные:
Person, p1, p2, только одна из которых содержит функциональный объект.
Sign up to leave a comment.

Articles

Change theme settings