JS-инженер Андреа Джаммарки написал на medium.com пост, в котором назвал заблуждением утверждение, что классы JS — это просто синтаксический сахар для прототипного наследования. По его мнению, есть множество вещей, которые можно смоделировать с помощью ES5 и прототипного наследования, но ни один из этих методов не настолько быстрый и безопасный, как использование соответствующего синтаксиса для классов JS.
Вот как он обосновал позицию в пользу использования классов JS:
use strict
в ES5 не запрещает вызов конструкторов без служебного слова new
.// ES5 function Test() { "use strict"; } Test.call({}); // it's OK // ES6+ class Test {} Test.call({}); // it throws
Современные классы имеют свойство new.target
, которое невозможно сымитировать в ES5 без использования транспайлера, копирующего такое поведение.
// ES5 epic fail function List() { "use strict"; } List.prototype = Object.create(Array.prototype); var list = new List; list.push(1, 2, 3); JSON.stringify(list); // {"0":1,"1":2,"2":3,"length":3} list.slice(0) instanceof List; // false
По словам автора, он не использует в конструкторе свойство Array.apply(this, arguments)
, так как расширение массива ES5 неудобно.
// ES5 epic fail v2 function Text(value) { "use strict"; String.call(this, value); } new Text("does this work?"); // nope, it doesn't ... no way it can.
С помощью прототипного наследования не получится расширить String
, а с помощью классов JS можно
list.slice (0)
не является экземпляром List
из-за свойства Symbol.species
// ES6+ class List extends Array {} (new List).slice(0) instanceof List; // true [].slice.call(new List) instanceof List; // true
Array.apply(this, arguments)
, потому что:— встроенный массив создает новый массив, которому не важен контекст и другие встроенные функции;
— классы JS обновляют экземпляры, что невозможно сделать в ES5 без транспайлера.
// ES5 function Button() { return document.createElement('button'); } function MyButton(value) { Button.call(this); this.textContent = value; } Object.setPrototypeOf(MyButton, Button); Object.setPrototypeOf(MyButton.prototype, Button.prototype);
new MyButton(“content”)
возвращается экземпляр MyButton
со свойством textContent
.function MySubClass() { var self = Class.apply(this, arguments) || this; // do anything with the self return self; }
Этот подход плох тем, что:
— если суперкласс возвращает что-то еще, теряется наследование;
— если суперкласс является встроенным, вместо этого может быть команда self
, указывающая на примитив.
Как в этом случае работают классы JS:
// ES6+ class Button { constructor() { return document.createElement('button'); } } class MyButton extends Button { constructor(value) { super(); this.textContent = value; } } document.body.appendChild(new MyButton("hello"));
// ES6+ class Test { method() {} } new Test.prototype.method; // TypeError: Test.prototype.method is not a constructor
В ES5 все функции могут использоваться как конструкторы.
// ES5 function Test() {} Test.prototype.method = function () { if (!(this instanceof Test)) throw new TypeError("not a constructor"); };
// ES5 function WithArrows() { Object.defineProperties(this, { method1: { configurable: true, writable: true, value: () => "arrow 1" } }); } // ES6+ class WithArrows { method1 = () => "arrow 1"; } // (new WithArrows).method1();
// ES6+ class WithPrivates { #value; #method(value) { this.#value = value; } constructor(value) { this.#method(value); } }
В ES5 можно смоделировать частные свойства, только используя транспайлер и коллекции WeakMap
.
Автор призывает перестать называть классы JS просто «синтаксическим сахаром». По мнению Андреа Джаммарки, множество вещей можно симулировать с помощью прототипного наследования, но некоторые просто невозможно. Использование современных классов из ES6 поможет создать лучшее ООП в JS, чем оно было в течение последних 20 лет.
Прокси (proxy), или прокси-сервер — это программа-посредник, которая обеспечивает соединение между пользователем и интернет-ресурсом. Принцип…
Согласитесь, было бы неплохо соединить в одно сайт и приложение для смартфона. Если вы еще…
Повсеместное распространение смартфонов привело к огромному спросу на мобильные игры и приложения. Миллиарды пользователей гаджетов…
В перечне популярных чат-ботов с искусственным интеллектом Google Bard (Gemini) еще не пользуется такой популярностью…
Скрипт (англ. — сценарий), — это небольшая программа, как правило, для веб-интерфейса, выполняющая определенную задачу.…
Дедлайн (от англ. deadline — «крайний срок») — это конечная дата стачи проекта или задачи…