Pull to refresh

Comments 87

Огромное человеческое спасибо!
Готовлюсь к собеседованию — и в планах было выделить сегодняшний день на ES2015. А тут ты с переводом. Как знал! как знал.
Очень рад, что перевод оказался вовремя.
P.S. Для собеседования детали лучше посмотреть в учебнике Ильи Кантора, там больше подробностей.
UFO just landed and posted this here
Согласен. У меня и нет цели освоить весь современный стандарт за сегодня. Хочу лишь ознакомиться. А такая краткая выжимка — самое подходящее для этой цели.
В ECMAScript 3/5 это поведение стало возможным изменить, присвоив значение this другой переменной.

Вы видимо про Function.prototype.bind не слышали?
Вы видимо не слышали, что поддержка bind появилась только в 2011 году.
поддержка bind появилась в Firefox 4.0 в 2011 году. С остальными браузерами примерно та же фигня. Дата выпуска спецификации совершенно минорна в данном контексте.

До сих пор полной поддержки ES6 нет ни в одном стабильном браузере, а если брать в расчёт до сих пор живые IE… вот только ES6 используется чуть менее, чем повсеместно. Function#bind достаточно хорошо, хоть и не полностью, полифилится, чем все с самого начала и пользовались. Так что-что, а поддержка браузерами, в отличии от спецификации, в данном контексте, как вы выразились, "совершенно минорна".

С самого начала повсеместно было именно self = this, потому что это очевидное и простое решение. А уже потом, с появлением prototypejs публика прозрела, что оказывается JS — это Scheme в Cи-подобном синтаксисе. Вернитесь в 2005 год и расскажите мне, что там у вас полифилится и насколько хорошо.

Вы с кем и о чем спорите? Проспитесь.

При чем тут вообще ES6? Разговор о ES 3/5 и .bind

Действительно, какой смысл сравнивать реализацию стандартной библиотеки ES5 и ES6? Зачем приводить такой пример — эта статья ведь совершенно не о ES6, верно?

Про Function.prototype.bind я слышал, спасибо.

Здесь есть два момента:
1. Это перевод, в котором не было написано про bind
2. Насколько я понимаю, суть текста верна — для решения проблемы можно использовать приём с var self = this.

В связи с перечисленными двумя пунктами, в чём конкретно у вас претензия к тексту? В отстутствии упоминания про Function.prototype.bind?
Отличный материал, но стоило бы упомянуть, что у стрелочных функций нет не только своего this, но и своих arguments (а также super и new.target).
По мере чтения оригинального текста у меня появлялось желание что-то дописать, переписать, задать другую структуру. Но особо себя в этом не поощрял, за исключением нескольких случаев.
Думаю, что можно создать PR автору, он достаточно оперативно их рассматривает (мой PR рассмотрел в тот же день).

В любом случае спасибо за полезный комментарий.
«rest» (от переводчика: не нашёл подходящего перевода на русский язык, из примера ниже всё станет ясно)
Я бы предположил «остаток» или, по созвучию, «хвост» — использование rest-оператора в качестве единственного агрумента функции — это вырожденный случай, в общем виде это что-то вроде

function(a, b, c, ...moreArgs) {...}

Т.е. оператор возвращает в виде массива оставшиеся неописанными аргументы.
Спасибо за пример. В моём понимании, «остаток» или «хвост» ничего не говорят сами по себе. Вы написали, что означает «хвост», и мне стало понятно. Без объяснения это было бы неочевидно. В итоге просто поменялся бы «rest» на «хвост», но смысл бы очевидней не стал. ИМХО, конечно.
Потому пример приведенный MaxKitsch более правильный для понимания rest
Спасибо за перевод. Пожалуйста, проверьте:

1. Не работают ссылки на разделы (а код страницы показывает отсутствие якорей в заголовках).
2. В начале раздела про шаблоны странное:

\${… }`` — зачем-то экранирование и ${… } вынесено за кавычки
``` — зачем-то тройные кавычки
Спасибо за комментарий. Ссылки поправлю вечером.

К сожалению, ссылки всё ещё не работают. Я сам пробовал атрибуты id и name в заголовках, а также <a name='...'></a> перед заголовками, но Хабр это всё вычищает, хоть в исходном коде для редактирования сохраняет. Не могу понять, что нужно сделать, чтобы получалось как здесь, например.

Аналогично. У них в коде как раз id и name, но в моей публикации это почему-то не работает.
Вчера минут 40 потратил на то, чтобы попробовать различные варианты, но все не работали.
Простите, что не исправил. Буду разбираться дальше, а то непорядок.


P.S. Какое совпадение, я тоже ориентировался на дайджест фронтенд-разработки)

Поправил, теперь ссылки рабочие!
За объяснение спасибо alexzfort.

А в чём секрет?

В использовании anchor для указания якоря:


<a href="#1">Заголовок 1</a>
<anchor>1</anchor>

Это даже можно увидеть в правом верхнем углу поля набора сообщения — "html-теги". Там про anchor подробно написано)

А как быть с приватными членами в классах?

Согласно философии JavaScript: если не хотите обращаться к членам объекта из других объектов — не обращайтесь к ним.

Помимо сказанного RubaXa и Zenitchik, есть еще пара вариантов:

  • Использовать конвенцию, префиксуя приватные члены класса символом нижнего подчеркивания
  • Обернуть всё в функцию, используя ее локальные переменные для хранения приватных данных (с помощью замыканий)

Стоит заметить, что TS ограничивает доступ к приватным переменным только на уровне проверки типов. Они все равно будут доступны из кода на чистом JS, или при приведении объекта к типу any.
Зачем тогда вообще нужен этот новый стандарт? В принципе классический JS он самодостаточен и очень гибок. И все эти прибамбасы особо сильно не упрощают жизнь. Самым логичным было бы улучшить статический анализатор до уровня когда практически все ошибки были бы сразу видны на этапе компиляции. Так как сейчас в JS это самая большая головная боль на мой взгляд. И именно из-за того, что сложно делать объемные приложения на JS выдумывают всякие препроцессоры и новые стандарты.

Классовое наследование — это хороший синтаксический сахар. Одна строчка вместо трёх.
Лично мне не нравится, что системную переменную super ввели только для классов. Общая идея JavaScript предполагает, что раз есть системная переменная, то она всегда должна быть чему-то равна. Как это сделано для this.


Вы, кстати, писали когда-нибудь объёмное приложение на JavaScript? Я с не вижу в этом особой головной боли. А препроцессоры считаю ересью.

Да, писал большие и маленькие проекты. И в каждом проекте использовал разные стили — и мне это очень понравилось. Стили выбирал исходя из задачи. Если это сложный проект — писал в стандартном стиле классы с наследованием через прототипы — каждый класс в отдельном файле. Если же что то простое — писал модулем в одном файле. Единственное, что напрягало — так это то, что не всегда видны ошибки — только при запуске, а так же IDE показывают непонятно что ))).

С IDE вообще беда — ни одна среда пока что не может нормально обработать класс и отобразить что то адекватное в автокомплите. После долгих переборов IDE остановился пока что на VisualStudio. Там какой то хитрый автокомплит, что походу дела среда запускает некоторые куски кода, и получаем более адекватные подсказки при написании кода. Остальные же редакторы заточены под определенный стиль.

Справедливости для: приватные члены — просто соглашение. В тех же плюсах его нарушить достаточно просто. В js вы можете для этого использовать либо Symbol, либо по-старинке через нижнее подчёркивание, причём и то и другие — тоже соглашение и тоже запросто нарушается. Ну либо можно всё через замыкания и/или WeakMap делать, но получится страшно.

На замыканиях — это вообще классика.
Кстати, иногда неплохо затрудняет отладку какого-нибудь обфусцированного кода, когда, к примеру, нужно вызвать напрямую какой-нибудь «приватный» метод.
В принципе это можно сделать прямо в дебаггере из консоли, если поставить брейкпоинт на любом месте класса. Консоль подхватывает текущий контекст this и само замыкание.
Конечно. Но для срабатывания брейкпоинта метод должен быть вызван тем или иным способом. К примеру:

function test(){
  var innerFunction=function(){
     console.log("You can't call me outside");
  };

  this.outer=function(){
     console.log("You can call me, but for what?");
  };
  
  setTimeout(innerFunction, 1000);
}


Сферический пример в вакууме.
innerFunction вызовется 1 раз и нанай. А если для отладки нужно ее запустить раз 5. к примеру? Ну или не отладки. а каких-нибудь личных хитровымудренных нужд(к примеру. для автоматизации каких-либо процессов на сайте при помощи userscri[t'ов).
Ну ставите брейкпоинт на строку с setTimeout и вызываете сначала test(), а потом innerFunction() сколько нужно

Еще полезное применение деструктуризации аргументов функции:


function userId({id}) {
  return id;
}

let user = {id: 1}

userId(user)
в стрелочных функциях пример можно еще короче записать

let arr = ['apple', 'banana', 'orange'];

let breakfast = arr.map(fruit => fruit + 's');

alert(breakfast);
Лучше так:

const arr = ['apple', 'banana', 'orange'];
const breakfast = arr.map(fruit => `${fruit}s`);
console.log(breakfast);
Может быть стоит связаться с автором, чтобы он разместил в своем репозитории ссылку на репозиторий с переводом?
Это уже сделано. Ссылка на перевод уже находится в его репозитории)
Да, извиняюсь. Сразу не заметил.
При использовании const рекомендуется использовать ПРОПИСНЫЕ_БУКВЫ.

Кем рекомендуется? Укажите ссылку, пожалуйста.


let nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (let nickname of nicknames) {
console.log(nickname);
}


По-хорошему, стоит использовать const для всех переменных, которые не планируется переприсваивать:


const nicknames = ['di', 'boo', 'punkeye'];
nicknames.size = 3;
for (const nickname of nicknames) {
    console.log(nickname);
}

Функции, записанные с помощью ключевого слова static, используются для объявления статических свойств класса.

Пока что только только методов. Более общие свойства — в stage-1.

А, извините, это перевод. Надо будет задать эти вопросы в оригинальный репозиторий, если не забуду.


Upd: по крайней мере последний вопрос — к переводу, в оригинале:


Functions defined using the static keyword implement static/class functions on the class.

А как бы перевели вы эту фразу? ("Functions defined using the static keyword implement static/class functions on the class")

Спасибо за комментарии.
По поводу прописных букв написано на сайте MDN в части с примерами, если переводить дословно — "использование всех прописных букв является общим соглашением".
"Common convention is to use all-uppercase letters"

Документация с сайта MDN работает по принципу вики, и хотя в целом она адекватна, там есть весьма спорные вещи. Не следует ей всегда слепо верить.


За ссылку спасибо. =)

Конкретно эту правку внёс https://github.com/agutoli, и это был его единственный вклад в MDN.


https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const$compare?from=845755&to=871843


Оттуда она и перекочевала в ваш документ.


На самом деле общепринятая практика — это eslint c prefer-const, с которым в коде почти все переменные будут const. И прописными буквами их все никто не называет.

Спасибо большое! Не знал насчёт документации MDN.

Ну как бы прописные для констант имхо со времен С идет. Вы потом в коде как определять будете что это константа и в нее писать не надо? Держать в голове? Зачем?

Дело в том, что в коде на яваскрипте большая часть переменных — фактически константы (не переприсваиваются). Вы предлагаете всё именовать большими буквами?

Мне нравится подход, описанный на сайте learn.javascript.ru:


Константы, которые жёстко заданы всегда, во время всей программы, обычно пишутся в верхнем регистре. Например: const ORANGE = "#ffa500".


Большинство переменных – константы в другом смысле: они не меняются после присвоения. Но при разных запусках функции это значение может быть разным. Для таких переменных можно использовать const и обычные строчные буквы в имени.

То, что написано там — имеет смысл, да. Причём не только для переменных, но и для свойств объектов.


Но к ключевому слову const это имеет очень слабое отношение.

Нет конечно (хотя про большую часть я бы поспорил). Но переменная, которая не переприсваивается — это не константа. Она не переприсваивается в силу алгоритма работы и при смене алгоритма может быть изменена. Константа — не переприсваивается в силу алгоритма и при доработках — надо иметь в виду что изначально в нее не планировалось ничего писать — не потому что так вышло при реализации а потому что так изначально планировалось. И этот момент неплохо бы видеть при внесении правок. Поэтому данные из конфига — обычно в верхнем регистре. А временные переменные, рабочие лошадки — в нижнем. Но это соглашение, не более того. Оно придумано для облегчения жизни, и если его соблюдение лично Вам жизнь не облегчает — нет смысла его придерживаться.

Нет конечно (хотя про большую часть я бы поспорил).

Зашёл в первый попавшийся проект, посчитал — 90.6% const, 9.4% let. Общую статистику по всем подводить как-то не хочется, но если хотите — посчитайте =). Но в таком проекте, где с var слезли уже.


Всё, что вы дальше говорите — к const не имеет отношения. Дело как раз в том, что const — это не то же самое множество, что константы, которые именуются большими буквами. Те могут быть как var в ES5, так и вообще свойствами какого-то объекта вроде MyLib.CONSTANT_NAME. А const как раз используется для тех переменных, которые не собираются переприсваивать, и говорить «для переменных const названия пишите в верхнем регистре» — глупость несусветная.


Пример:


for (const name of names) {
  …
}

Тут я точно знаю с первого взляда на код, что name внутри блока — всегда один и тот же и не изменяется волшебным алгоритмом. Я его что, дожен NAME назвать?

и говорить «для переменных const названия пишите в верхнем регистре» — глупость несусветная.

А кто такое сказал?


Я его что, дожен NAME назвать?

Нет, Вы мне ничего не должны. Я Вам тоже.

А кто такое сказал?

Да в статье ж русским по белому написано:


При использовании const рекомендуется использовать ПРОПИСНЫЕ_БУКВЫ.
При использовании const рекомендуется

и говорить «для переменных const названия пишите в верхнем регистре»

разницу видите? Вы сами придумали глупость и сами ее глупостью назвали.

[зануда-моуд]
Хорошо. Рекомендовать использовать прописные буквы для именования всех без разбора const-переменных — глупость.
[/зануда-моуд]


Так лучше?

Вы рано зануду выключили, я только прогреваться стал )


Рекомендация — то же, что совет, пожелание или предписание, высказанное в необязательной форме


С вики конечно, но сути не меняет.
Необязательная форма подразумевает нестрогое исполнение, то есть по сути — по обстоятельствам. А никак не всех без разбора. Поэтому есть рекомендации, есть стандарты, в стандартах не просто так расписывают в начале should, must, may.

Да, но только отношение const к константам, которые действительно стоит именовать заглавными буквами — примерно как между тапками и красным. Тапки бывают красные, бывают не красные. Красные бывают тапки, бывают не тапки.


Так стоит ли в статье-инструкции по рукоделию для новичков включать пункт «тапки красьте в красный цвет»?

Тапки бывают красные, бывают не красные. Красные бывают тапки, бывают не тапки.

Какая классная фраза!
А по теме, тоже придерживаюсь именования заглавными констант уровня модуля, а «на месте» — строчными.

Новички — это будущие профессионалы и не надо к ним относиться как к бабочкам. Есть краска, есть тапки, есть кисточка. Они могут красить тапки в красный цвет, могут не красить. А могут и не тапки. Могут не кисточкой. Могут забить на программирование и пойти красить заборы — тоже польза.

А правильный ответ — накатать им тикет в апстрим. Но мне пока чуть не до этого.

Еще геттеры/сеттеры можно
Да, тоже интересно было бы что бы кто нибудь понимающий раскрыл суть этой концепции.
Я не разработчик на JavaScript, но языки программирования вообще — мой интерес, и поэтому я сталкивался с этой концепцией где-то еще… но так и не понял в чем фишка.
А вообще очень приятные фичи, рад за JavaScript.
Допустим, у вас есть объект { x: 1 }. Поскольку строки сравниваются по значению, любой, кто в состоянии написать букву x, будет иметь доступ к этому свойству объекта.

С другой стороны, каждый Symbol является уникальным:
var a = Symbol("a");
var b = Symbol("a");

console.log(a === a); // true
console.log(a === b); // false

У Symbol есть еще две особенности. Во-первых, его можно (и нужно!) использовать в качестве ключа объекта. Кроме него ключами могут быть только числа и строки, никакие другие объекты использовать нельзя. Во-вторых, при перечислении содержимого объекта (for(var x in obj) ...) свойства с символьными ключами не указываются.

Таким образом, можно создать уникальный идентификатор свойства и сохранить его в локальную переменную. Свойство будет содержаться в объекте, но обратиться к нему можно будет только если есть доступ к этому идентификатору. Получаются «почти что» приватные поля:

function createPerson(age) {
    var agePty = Symbol("age");
    var person = { };
    person[agePty] = age; // обращение по уникальному Symbol
    person.getAge = function() { return person[agePty]; };
    person.birthday = function() { person[agePty]++; };

    return person; // agePty больше не видна
}

var me = createPerson(21);

person.getAge(); // 21

person.birthday();
person.getAge(); // 22

me["age"]; // undefined - недоступно
me[Symbol("age")]; // также недоступно

Я говорю «почти» приватные, потому что список символов в объекте всё равно можно получить через специальный API.
Ну если это аналог private-свойств у экземпляров классов, то… как-то это костылями попахивает, честно говоря.
Вы правы. Но поскольку сама архитектура языка полностью состоит из костылей, оно даже как-то гармонично вписывается.
Не совсем. Вы можете через символ скрыть какую-то сервисную информацию на объекте, которую потом, имея доступ к этому символу (например через импорт в другом модуле), эту информацию по символу из объекта достать.
Ну и, опять же, каждый символ уникален, даже с одним и тем же описанием. Это дает гарантии на уникальность полей.
Мне, например, приглянулся способ «наладить общение» между декораторами в библиотеке, когда у одного из них есть доступ к символу другого, чтобы скорректировать по наличию этого символа на прототипе свою работу.
А как это будет фолбечиться в ES5?
Полезен чтоб разделить методы и данные, убрать коллизию имен, привести API к одному виду. Хороший замах на перегрузку операторов (возможно появится как раз благодаря символу (уже сейчас можно переопределять например for of с помощью Symbol.iterator)).
Если рассматривать это как шпаргалку — хорошо бы добавить разделы про Reflection и Proxy.
Огромное спасибо за перевод. Все таки на родном языке читать приятнее и понятнее, чем на буржуйском ))
Спасибо большое за перевод, весьма интересно.
Небольшой хинт — spread еще весьма удобно использовать для фокусов в стиле пуша массива в массив:

var a=[1,2,3];
var b=[4,5];
a.push(...b); //a==[1,2,3,4,5];
Есть же старый добрый «concat»

a = a.concat(b);

Кроме того у push`a есть ограничение на количество аргументов (для FF 47 — 5e5, для Ya 16 — 2.5e5).
Да и работает concat куда быстрее — jsfiddle
concat создает новый массив. Также spread работает не только с массивами, но и массиводоподобными элементами, например, arguments.

p.s. «a.push.apply(a, b)» работает быстрее, чем concat.
У concat тоже есть плюс — он может объединять сразу больше 2-х массивов. А приведенный вами же пример «a.push.apply(a, b)» сводит на нет, ваш первый комментарий. Т.к. «apply» также прекрасно работает с массиводоподобными объектами.

P.S. spread работает не с массиводоподобными, а с итерируемыми объектами! Т. е. если просто создадите объект с числовой последовательность в качестве ствойств и свойство «length», то spread работать не будет ( Exception: TypeError: obj is not iterable ).
Эх… Еще бы Python-овские срезы массива добавили, а не эти slice()
Sign up to leave a comment.

Articles