Обзор базовых возможностей ES6

Original author: Adrian Mejia
  • Translation

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


История


Новые добавления в язык называются ECMAScript 6. Или ES6 или ES2015+.


С момента появления в 1995, JavaScript развивался медленно. Новые возможности добавлялись каждые несколько лет. ECMAScript появился в 1997, его целью было направить развитие JavaScript в нужное русло. Выходили новые версии – ES3, ES5, ES6 и так далее.



Как видите, между версиями ES3, ES5 и ES6 есть пропуски длиной в 10 и 6 лет. Новая модель – делать маленькие изменения каждый год. Вместо того, чтобы накопить огромное количество изменений и выпустить их все за раз, как это было с ES6.


Browsers Support


Все современные браузеры и среды исполнения уже поддерживают ES6!



Chrome, MS Edge, Firefox, Safari, Node и многие другие системы имеют встроенную поддержку большинства возможностей JavaScript ES6. Так что, все из этого пособия можно использовать прямо сейчас.


Поехали!


Главные возможности ES6


Все сниппеты можно вставлять в консоль браузера и запускать.


Block scope variables


В ES6 мы перешли от var к let/const.


Что не так с var?


Проблема var в том, что переменная "протекает" в другие блоки кода, такие как циклы for или блоки условий if:


ES5
var x = 'outer';
function test(inner) {
  if (inner) {
    var x = 'inner'; // scope whole function
    return x;
  }
  return x; // gets redefined on line 4
}

test(false); // undefined 
test(true); // inner

В строке test(false) можно ожидать возврат outer, но нет, мы получаем undefined. Почему?


Потому что даже не смотря на то, что блок if не выполняется, на 4й строке происходит переопределение var x как undefined.


ES6 спешит на помощь:


ES6
let x = 'outer';
function test(inner) {
  if (inner) {
    let x = 'inner';
    return x;
  }
  return x; // gets result from line 1 as expected
}

test(false); // outer
test(true); // inner

Изменив var на let мы откорректировали поведение. Если блок if не вызывается, то переменная x не переопределяется.


IIFE (immediately invoked function expression)


Давайте сначала рассмотрим пример:


ES5
{
  var private = 1;
}

console.log(private); // 1

Как видите, private протекает наружу. Нужно использовать IIFE (immediately-invoked function expression):


ES5
(function(){
  var private2 = 1;
})();

console.log(private2); // Uncaught ReferenceError

Если взглянуть на jQuery/lodash или любые другие проекты с открытым исходным кодом, то можно заметить, что там IIFE используется для содержания глобальной среды в чистоте. А глобальные штуки определяются со специальными символами вроде _$ или jQuery.


В ES6 не нужно использовать IIFE, достаточно использовать блоки и let:


ES6
{
  let private3 = 1;
}

console.log(private3); // Uncaught ReferenceError

Const


Можно также использовать const если переменная не должна изменяться.


Итог:


  • забудьте var, используйте let и const.
  • Используйте const для всех референсов; не используйте var.
  • Если референсы нужно переопределять, используйте let вместо const.

Template Literals


Не нужно больше делать вложенную конкатенацию, можно использовать шаблоны. Посмотрите:


ES5
var first = 'Adrian';
var last = 'Mejia';
console.log('Your name is ' + first + ' ' + last + '.');

С помощью бэктика () и интерполяции строк ${}` можно сделать так:


ES6
const first = 'Adrian';
const last = 'Mejia';
console.log(`Your name is ${first} ${last}.`);

Multi-line strings


Не нужно больше конкатенировать строки с + \n:


ES5
var template = '<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" >\n' +
'  <div class="view">\n' +
'    <input class="toggle" type="checkbox" [checked]="todo.isDone">\n' +
'    <label></label>\n' +
'    <button class="destroy"></button>\n' +
'  </div>\n' +
'  <input class="edit" value="">\n' +
'</li>';
console.log(template);

В ES6 можно снова использовать бэктики:


ES6
const template = `<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" >
  <div class="view">
    <input class="toggle" type="checkbox" [checked]="todo.isDone">
    <label></label>
    <button class="destroy"></button>
  </div>
  <input class="edit" value="">
</li>`;
console.log(template);

Оба блока кода генерируют одинаковый результат


Destructuring Assignment


ES6 destructing – полезная и лаконичная штука. Посмотрите на примеры:


Получение элемента из массива


ES5
var array = [1, 2, 3, 4];

var first = array[0];
var third = array[2];

console.log(first, third); // 1 3

То же самое:


ES6
const array = [1, 2, 3, 4];

const [first, ,third] = array;

console.log(first, third); // 1 3

Обмен значениями


ES5
var a = 1;
var b = 2;

var tmp = a;
a = b;
b = tmp;

console.log(a, b); // 2 1

То же самое:


ES6
let a = 1;
let b = 2;

[a, b] = [b, a];

console.log(a, b); // 2 1

Деструктуризация нескольких возвращаемых значений


ES5
function margin() {
  var left=1, right=2, top=3, bottom=4;
  return { left: left, right: right, top: top, bottom: bottom };
}

var data = margin();
var left = data.left;
var bottom = data.bottom;

console.log(left, bottom); // 1 4

В строке 3 можно вернуть в виде массива:


return [left, right, top, bottom];

но вызывающему коду придется знать о порядке данных.


var left = data[0];
var bottom = data[3];

С ES6 вызывающий выбирает только нужные данные (строка 6):


ES6
function margin() {
  const left=1, right=2, top=3, bottom=4;
  return { left, right, top, bottom };
}

const { left, bottom } = margin();

console.log(left, bottom); // 1 4

Заметка: В строке 3 содержатся другие возможности ES6. Можно сократить { left: left } до  { left }. Смотрите, насколько это лаконичнее по сравнению с версией ES5. Круто же?


Деструктуризация и сопоставление параметров


ES5
var user = {firstName: 'Adrian', lastName: 'Mejia'};

function getFullName(user) {
  var firstName = user.firstName;
  var lastName = user.lastName;

  return firstName + ' ' + lastName;
}

console.log(getFullName(user)); // Adrian Mejia

То же самое (но короче):


ES6
const user = {firstName: 'Adrian', lastName: 'Mejia'};

function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}

console.log(getFullName(user)); // Adrian Mejia

Глубокое сопоставление


ES5
function settings() {
  return { display: { color: 'red' }, keyboard: { layout: 'querty'} };
}

var tmp = settings();
var displayColor = tmp.display.color;
var keyboardLayout = tmp.keyboard.layout;

console.log(displayColor, keyboardLayout); // red querty

То же самое (но короче):


ES6
function settings() {
  return { display: { color: 'red' }, keyboard: { layout: 'querty'} };
}

const { display: { color: displayColor }, keyboard: { layout: keyboardLayout }} = settings();

console.log(displayColor, keyboardLayout); // red querty

Это также называют деструктуризацией объекта (object destructing).


Как видите, деструктуризация может быть очень полезной и может подталкивать к улучшению стиля кодирования.


Советы:


  • Используйте деструктуризацию для получения элементов из массива и для обмена значениями. Не нужно делать временные референсы – сэкономите время.
  • Не используйте деструктуризацию массива для нескольких возвращаемых значений, вместо этого используйте деструктуризацию объекта.

Классы и объекты


В ECMAScript 6 мы перешли от “функций-конструкторов” к “классам” .


Каждый объект в JavaScript имеет прототип, который является другим объектом. Все объекты в JavaScript наследуют методы и свойства от своего прототипа.

В ES5 объектно-ориентированное программирование достигалось с помощью функций-конструкторов. Они создавали объекты следующим образом:


ES5
var Animal = (function () {
  function MyConstructor(name) {
    this.name = name;
  }
  MyConstructor.prototype.speak = function speak() {
    console.log(this.name + ' makes a noise.');
  };
  return MyConstructor;
})();

var animal = new Animal('animal');
animal.speak(); // animal makes a noise.

В ES6 есть новый синтаксический сахар. Можно сделать то же самое с меньшим кодом и с использованием ключевых слов class и construсtor. Также заметьте, как четко определяются методы: construсtor.prototype.speak = function () vs speak():


ES6
class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(this.name + ' makes a noise.');
  }
}

const animal = new Animal('animal');
animal.speak(); // animal makes a noise.

Оба стиля (ES5/6) дают одинаковый результат.


Советы:


  • Всегда используйте синтаксис class и не изменяйте prototype напрямую. Код будет лаконичнее и его будет легче понять.
  • Избегайте создания пустого конструктора. У классов есть конструктор по умолчанию если не задать собственный.

Наследование


Давайте продолжим предыдущий пример с классом Animal. Допустим, нам нужен новый класс Lion.


В ES5 придется немного поработать с прототипным наследованием.


ES5
var Lion = (function () {
  function MyConstructor(name){
    Animal.call(this, name);
  }

  // prototypal inheritance
  MyConstructor.prototype = Object.create(Animal.prototype);
  MyConstructor.prototype.constructor = Animal;

  MyConstructor.prototype.speak = function speak() {
    Animal.prototype.speak.call(this);
    console.log(this.name + ' roars ');
  };
  return MyConstructor;
})();

var lion = new Lion('Simba');
lion.speak(); // Simba makes a noise.
// Simba roars.

Не будем вдаваться в детали, но заметьте несколько деталей:


  • Строка 3, напрямую вызываем конструкторAnimal с параметрами.
  • Строки 7-8, назначаем прототип Lion прототипом класса Animal.
  • Строка 11, вызываем метод speak из родительского класса Animal.

В ES6 есть новые ключевые слова extends и super.


ES6
class Lion extends Animal {
  speak() {
    super.speak();
    console.log(this.name + ' roars ');
  }
}

const lion = new Lion('Simba');
lion.speak(); // Simba makes a noise.
// Simba roars.

Посмотрите, насколько лучше выглядит код на ES6 по сравнению с ES5. И они делают одно и то же! Win!


Совет:


  • Используйте встроенный способ наследования – extends.

Нативные промисы


Переходим от callback hell к промисам (promises)


ES5
function printAfterTimeout(string, timeout, done){
  setTimeout(function(){
    done(string);
  }, timeout);
}

printAfterTimeout('Hello ', 2e3, function(result){
  console.log(result);

  // nested callback
  printAfterTimeout(result + 'Reader', 2e3, function(result){
    console.log(result);
  });
});

Одна функция принимает callback чтобы запустить его после завершения. Нам нужно запустить ее дважды, одну за другой. Поэтому приходится вызывать printAfterTimeout во второй раз в коллбеке.


Все становится совсем плохо когда нужно добавить третий или четвертый коллбек. Давайте посмотрим, что можно сделать с промисами:


ES6
function printAfterTimeout(string, timeout){
  return new Promise((resolve, reject) => {
    setTimeout(function(){
      resolve(string);
    }, timeout);
  });
}

printAfterTimeout('Hello ', 2e3).then((result) => {
  console.log(result);
  return printAfterTimeout(result + 'Reader', 2e3);

}).then((result) => {
  console.log(result);
});

С помощью then можно обойтись без вложенных функций.


Стрелочные функции


В ES5 обычные определения функций не исчезли, но был добавлен новый формат – стрелочные функции.


В ES5 есть проблемы с this:


ES5
var _this = this; // need to hold a reference

$('.btn').click(function(event){
  _this.sendData(); // reference outer this
});

$('.input').on('change',function(event){
  this.sendData(); // reference outer this
}.bind(this)); // bind to outer this

Нужно использовать временный this чтобы ссылаться на него внутри функции или использовать bind. В ES6 можно просто использовать стрелочную функцию!


ES6
// this will reference the outer one
$('.btn').click((event) =>  this.sendData());

// implicit returns
const ids = [291, 288, 984];
const messages = ids.map(value => `ID is ${value}`);

For…of


От for переходим к forEach а потом к for...of:


ES5
// for
var array = ['a', 'b', 'c', 'd'];
for (var i = 0; i < array.length; i++) {
  var element = array[i];
  console.log(element);
}

// forEach
array.forEach(function (element) {
  console.log(element);
});

ES6 for…of позволяет использовать итераторы


ES6
// for ...of
const array = ['a', 'b', 'c', 'd'];
for (const element of array) {
    console.log(element);
}

Параметры по умолчанию


От проверки параметров переходим к параметрам по умолчанию. Вы делали что-нибудь такое раньше?


ES5
function point(x, y, isFlag){
  x = x || 0;
  y = y || -1;
  isFlag = isFlag || true;
  console.log(x,y, isFlag);
}

point(0, 0) // 0 -1 true 
point(0, 0, false) // 0 -1 true 
point(1) // 1 -1 true
point() // 0 -1 true

Скорее всего да. Это распространенный паттерн проверки наличия значения переменной. Но тут есть некоторые проблемы:


  • Строка 8, передаем 0, 0 получаем 0, -1
  • Строка 9, передаем false, но получаем true.

Если параметр по умолчанию это булева переменная или если задать значение 0, то ничего не получится. Почему? Расскажу после этого примера с ES6 ;)


В ES6 все получается лучше с меньшим количеством кода:


ES6
function point(x = 0, y = -1, isFlag = true){
  console.log(x,y, isFlag);
}

point(0, 0) // 0 0 true
point(0, 0, false) // 0 0 false
point(1) // 1 -1 true
point() // 0 -1 true

Получаем ожидаемый результат. Пример в ES5 не работал. Нужно проверять на undefined так как falsenullundefined и 0 – это все falsy-значения. С числами можно так:


ES5
function point(x, y, isFlag){
  x = x || 0;
  y = typeof(y) === 'undefined' ? -1 : y;
  isFlag = typeof(isFlag) === 'undefined' ? true : isFlag;
  console.log(x,y, isFlag);
}

point(0, 0) // 0 0 true
point(0, 0, false) // 0 0 false
point(1) // 1 -1 true
point() // 0 -1 true

С проверкой на undefined все работает как нужно.


Rest-параметры


От аргументов к rest-параметрам и операции spread.


В ES5 работать с переменным количеством аргументов неудобно.


ES5
function printf(format) {
  var params = [].slice.call(arguments, 1);
  console.log('params: ', params);
  console.log('format: ', format);
}

printf('%s %d %.2f', 'adrian', 321, Math.PI);

С rest  ... все намного проще.


ES6
function printf(format, ...params) {
  console.log('params: ', params);
  console.log('format: ', format);
}

printf('%s %d %.2f', 'adrian', 321, Math.PI);

Операция Spread


Переходим от apply() к spread. Опять же, ... спешит на помощь:


Помните: мы используем apply() чтобы превратить массив в список аргументов. например, Math.max() принимает список параметров, но если у нас есть массив, то можно использовать apply.

ES5
Math.max.apply(Math, [2,100,1,6,43]) // 100

В ES6 используем spread:


ES6
Math.max(...[2,100,1,6,43]) // 100

Мы также перешли от concat к spread'у:


ES5
var array1 = [2,100,1,6,43];
var array2 = ['a', 'b', 'c', 'd'];
var array3 = [false, true, null, undefined];

console.log(array1.concat(array2, array3));

В ES6:


ES6
const array1 = [2,100,1,6,43];
const array2 = ['a', 'b', 'c', 'd'];
const array3 = [false, true, null, undefined];

console.log([...array1, ...array2, ...array3]);

Заключение


JavaScript сильно изменился. Эта статья покрывает только базовые возможности, о которых должен знать каждый разработчик.

AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 37

    –7
    Кстати, наши онлайн-курсы учат новому стандарту с самого начала, с «основ программирования» :-)
      –3
      А я долго гадал думал, зачем в таком большом количестве вы выбрасываете переводы так себе статей (хотя некоторые интересны). Теперь то понятно — пиарить совой проект обучения web проганью, вот только этих сервисов развелось как грязи в последнее время, чему то там конечно обучают, но только минимальным основам и так себе (Кто умеет, тот делает; кто не умеет, тот учит — пословица такая). В итоге на итак перегретый рынок it разработки выплёскиваются люди прошедшие пару курсов с завышенным чсв и требованием 1000$ в месяц и красной ковровой дорожки чтобы просто прийти на собеседование (к сожалению это гиперболизированная но всё же реальность). Вообщем печалька.
        +2
        Пусть выплескиваются. За минувший год у меня на собеседовании были десятка таких «талантов» с уровнем зарплатных ожиданий от *совсем мало* (студент на парт-тайм) до *офигеть сколько* (вуз закончил или даже не начинал) тысяч. Одному, пришедшему с претензией на senior, предложили junior-позицию за вменяемую сумму. Согласился, до сих пор с нами работает.
        А изначальную позицию закрыли опытным и сильным девелопером. Стоит он дорого, но такие люди на контрасте с общей массой начинают еще больше цениться.
      –3
      А как насчет поддержки ES6 устаревшими браузерами? Тот же IE9, который является последней версией для Висты (которая до сих является поддерживаемым ОС), сможет выполнить код? Часто заказчики вообще требуют поддержки IE6.
        +4
        Ладно IE6 или IE9. Многое из описанного не поддерживается и в IE11 о чем почему-то умолчали в статье
        +1
        Вам помогут полифилы.
          0

          Полифиллы, транспиляция.

            0
            https://babeljs.io/
              +9
              Часто заказчики вообще требуют поддержки IE6.

              вокруг вас там черти с вилами не бегают?
              +3
              Слава Богу, наконец-то кто-то написал псто про новые фичи в ES6.
                +4
                25 октября 2016
                Слава Богу, наконец-то кто-то написал просто про новые фичи в ES2015.
                  +1
                  псто !== просто
                0
                забудьте var, используйте let и const.

                Между тем, node.js team пока старается избегать их в местах, критичным к скорости выполнения (например, в циклах). https://github.com/nodejs/node/pull/8873 и https://gist.github.com/Salakar/6d7b84f7adf1f3bc62a754752a6e5d0e

                Со времен JS-движки оптимизируют под новый стандарт.
                  +2
                  Но как? В байткоде let плодит замыкание, у него нет других вариантов кроме как сделать замыкание, а это не бесплатная вещь. Фактически такие статьи сейчас предлагают завернуть любой цикл таким образом:
                  for(var i = 0; i < length; i++)
                    (function(i){ 
                      тело
                    })(i);
                  

                  Это несомненно решает проблему когда в теле оказывается ассинхронный код, единственное что могут изобрести js-движки — jit оптимизацию, которая проверит что код синхронен и тогда заменит let на var (логику поведения). Но что если мне действительно надо в ассинхронном коде использовать последнее значение i?
                  ES6 принёс очень много загадочных мест.
                    0
                    Да, над этим работают
                    https://docs.google.com/document/d/1EA9EbfnydAmmU_lM8R_uEMQ-U_v4l9zulePSBkeYWmY
                    +4
                    переменная "протекает" в другие блоки кода

                    протекает наружу

                    Всега было "поднимается" ну или "всплыввает", зачем вводить новое понятие да еще и такое запутанное.
                    Все же четко: объявление переменной "поднимается" в начало области видимости (функции). И не нужно объяснять почему переменная настолько вредная, что "проникает" в другие блоки

                      0
                      Видимо чтобы вызвать ассоциацию с тем, что протекает. По трубам.
                      0
                      В целом, очень даже ничего.
                      Некоторые фишки очень даже понравились.Особенно «class, constructor».
                      Но вот это как-то не очень:

                      ES6
                      function settings() {
                        return { display: { color: 'red' }, keyboard: { layout: 'querty'} };
                      }
                      
                      const { display: { color: displayColor }, keyboard: { layout: keyboardLayout }} = settings();
                      
                      console.log(displayColor, keyboardLayout); // red querty
                      
                        0

                        Это, на мой взгляд, просто пример неуместного использования деструктуринга, строка получилась очень длинной и плохо читаемой, при этом вариант settings.display.color гораздо читабельнее в данном случае.
                        Но это не потому что деструктуринг плох, а потому что надо в меру фичи использовать.
                        То же можно сказать и про [...array1, ...array2, ...array3]. Лучше бы + починили (ну или какой-нибудь ++ добавили), если concat не нравится.

                          –1
                          Да вроде нормально, если отформатировать по строкам
                          –1
                          Удивительно дело.

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

                          В C++ изначально было сделано по уму — friend-функции
                          А вот дальше пошло хуже, но хоть как-то развивалось:
                          • в Delphi «протекали» private-поля внутри модуля, потом протечки залепили с помощью strict protected;
                          • в Java protected-поля протекают внутри пакета,
                          • но потом появился ее близнец C#, в котором protected не протекает, а для контролируемых протечек внутри сборки придумали internal.

                          На мой взгляд, когда private var виден наружу, это именно «протечка», лучше называть вещи своими именами.
                          Ок, придумали, let и const теперь. Неясно, почему это нельзя было придумать сразу, с учетом опыта других языков.

                          Тем более путаница ключевых слов — если с const все понятно, то разницу между var и let нужно держать в голове, или гуглить. Опять же, неужели опыт других языков не учит, где тоже полно схожих ключевых слов с разной семантикой.
                            0
                            Неясно, почему это нельзя было придумать сразу, с учетом опыта других языков.

                            Javascript появился в 1995 году, опыта других языков типа Java и тем более C# еще не было.

                              0
                              Здесь было немного сарказма про «модные веб-языки», но тем не менее:
                              1. в 1995-м появился LiveScript, а не JavaScript
                              2. Сколько раз его можно было переделать, пока браузеры не стали массово исполнять JS как стандарт де факто?
                              3. в 1995-м уже давно был C++, и вовсю была Delphi, было на что ориентироваться
                              4. Java вышла в 1995-96-м

                              Так что по ходу развития JS было на что ориентироваться.
                              Поэтому и неясно, почему такие детские болезни, как var в JS, дожили аж до 2016.
                                0

                                Ну когда смогли, тогда и сделали.


                                Лучше поздно, чем никогда, правда?

                                  0
                                  Все верно, лучше поздно, чем никогда.

                                  Но этот и множество других примеров в веб-технологиях удивляют — как будто их разработчики занимались разработкой где-то на Альфа Центавра, иной раз кажется, что ну совершенно без учета опыта индустрии.

                                  А теперь если что-то и исправляется, то преподносится как откровение (а в индустрии в целом это уж 10-20-30 лет как решено).

                                  Проблема в том, что веб давно стал очень актуальным, и дальше — больше (но — со всеми своими детскими болезнями), и было бы интересно понять причины, предпосылки сложившегося состояния дел именно в веб-отрасли.

                                  А так, считаю, что и традиционным языкам есть чему получиться у того же JS (например, доступ к элементами класса как словарю «ключ — значение» — по сути, это рефлексия, встроенная в язык, а не в библиотеки платформы).
                                    0

                                    Ответ на первой картинке в посте.


                                    С 2000 года почти 10 лет никто языком не занимался вообще, браузеры реализовывали функциональность кто во что горазд.
                                    Потом понадобилось некоторое время, чтобы разобраться с проблемами и прийти к какому-то удовлетворительному решению.

                                      0
                                      >С 2000 года почти 10 лет никто языком не занимался вообще

                                      Была попытка неудавшаяся протащить ООП в JavaScript в ES4.

                                      Так что работа велась. ;-)
                            0
                            После первого примера дальше даже читать не стал. Область видимости для var — функция(она же объект). Почему вернуло undefined? Да потому что переменная объявляется внутри функции независимо от наличия условия, оно влияет только на присвоение значения этой переменной.
                              0
                              В примере с классами для ES5 не слишком ли усложнена обертка? Можно ведь и так написать:
                              var Animal = function(name){
                                this.name = name;
                                this.speak = function(){
                                  console.log(this.name + ' makes a noise.');
                                }
                              }
                              
                                0
                                Это не одно и то же. Там метод вынесен в прототип.
                                  0
                                  Ок, просьба не пинать больно, а что нам дает замыкание в функцию по сравнению с такой записью?
                                  var Animal = function(name){
                                    this.name = name;  
                                  }
                                  Animal.prototype.speak = function(){
                                      console.log(this.name + ' makes a noise.');
                                  }
                                  
                                    0
                                    А вот на этот вопрос у меня нет хорошего ответа.
                                      0
                                      Вроде бы на примере с наследованием становится ясно что с классами проще, но опять же
                                      var lion = Object.create(new Animal('Simba'))
                                      lion.speak = function(){
                                      	Animal.prototype.speak.call(this);
                                      	console.log(this.name + ' roars.');
                                      }
                                      
                                      lion.speak(); // Simba makes a noise.
                                      

                                      Тоже нормально читается. В общем не отпускает чувство что пример нарочно усложнен для контраста, «как все клево стало».
                                      +1

                                      В вашем первом примере на каждый новый экземпляр Animal будет создан свой инстанс метода speak.


                                      Если вынести метод в прототип, то он будет один на все экземпляры. В теории, это сэкономит вам немного памяти, если объектов много.

                                        0
                                        В той записи, которую вы прокомментировали, метод вынесен в прототип.

                                Only users with full accounts can post comments. Log in, please.