Является ли JavaScript "новым" ключевым словом считается вредным (часть 2)?
Прочитав следующие question, я чувствую, что большинство ответов не понимают, почему некоторые люди (Crockford) предпочитают не использовать "новые", ключевое слово. Это не мешает случайному вызову функции без "нового" ключевого слова.
В соответствии со следующей статьей Крокфорда относительно прототипного наследования, он реализует технику создания объекта, которая более четко демонстрирует прототипность JS. Этот метод теперь даже реализован в JS 1.8.5.
Его аргумент против использования нового можно более четко подвести следующим образом:
"Это косвенное предназначение предназначалось для того, чтобы язык выглядел более знакомым для программистов с классической подготовкой, но не смог этого сделать, как мы можем видеть из очень низкого мнения, которое у Java-программистов есть JavaScript. Шаблон конструктора JavaScript не понравился классическому толпа, а также затмевает JavaScript истинный прототипный характер. В результате очень мало программистов, которые знают, как эффективно использовать этот язык".
Я не обязательно считаю "новым" вредным, но я согласен, что он "скрывает истинный прототипический характер JavaScript", и поэтому я должен согласиться с Крокфордом по этому вопросу.
Каково ваше мнение об использовании "более четкой" технологии создания прототипов, используя "новое" ключевое слово?
Ответы
Ответ 1
Вы правы, используя new
считается вредным, поскольку он не уделяет достаточного внимания ОО в JavaScript, являющемся прототипом. Основная проблема заключается в том, что она слишком сильно похожа на классические классы, и не стоит думать о class
. Нужно думать об объекте и создавать новые объекты с существующими объектами в качестве чертежей.
new
является остатком тех дней, когда JavaScript принял синтаксис Java, чтобы получить "популярность".
В наши дни мы делаем Prototypical OO с Object.create
и используем Прокладка ES5.
Больше нет необходимости new
.
До того, как дни ES5 обычно внедряются (только FF3.6 и IE8 ослабляются), мы использовали new
, потому что у нас не было выбора. someFunction.prototype
был способом сделать прототипическое наследование.
Недавно я написал "приятную" демонстрацию Object.create
, хотя мне все равно нужно сгладить некоторые изломы в использовании. Важно отделить объекты от factory функций.
Ответ 2
Я не считаю, что new
скрывает прототипность языка для меня. Конечно, я провел несколько лет, чтобы хорошо знать язык (совершив ошибку из-за погружения и начала писать код без подсказки, как на самом деле работал язык, с моей начальной стоимостью).
Я нахожу выражение new
выразительным таким образом, что префикс "нового" на имена функций или использование вспомогательной функции и т.д. не является:
var fido = new Dog(); // Simple, clear
var rover = Dog(); // Very unclear (fortunately people mostly don't do this, but I've seen it)
var scruffles = newDog(); // Clearer, but hacky
var fifi = Object.create(Dog); // (Crockford) Verbose, awkward, not esp. clear
Независимо от того, является ли он прототипом или основан на классе (и большинство из них вообще не относится к ключевому слову new
), я по-прежнему считаю лучше всего с точки зрения функциональности, сгруппированной вместе в строительные блоки (объекты или классы или что-то еще) и то конкретные объекты, которые я могу обмануть, не затрагивая эти строительные блоки. Для меня new
как средство четкого определения моего намерения не является ни стильным, ни прототипным, это просто понятно.
Для меня new
столь же жизненно важен как часть JavaScript, поскольку сами прототипы, как замечательно ловкие функции. Это не конфликт.
И, говоря практически, существует гораздо больше программистов, использующих new
для создания новых экземпляров вещей, чем нет, и это широко распространенная практика в сообществе JavaScript, несмотря на усилия Крокфорда (не поймите меня неправильно, я имею много уважения к Крокфорду). Если я укомплектовываю проект, я не хочу переучиваться.
Это не означает, что способ, которым вы определяете иерархии прототипических объектов в JavaScript, является вещью красоты и радости навсегда. Это королевская боль, особенно без усовершенствований ECMAScript5. Но определите вспомогательную функцию, которая поможет вам подключить ваши иерархии (что бы вы ни назвали их), и все готово. (См. Обновление ниже.)
[И да, вся информация о функциях конструктора, вызываемых без new
, действительно является красной селедкой (вы сказали, что не считали, что это тоже главное). Вы почти никогда не видите, что это происходит в реальном мире. На самом деле, некоторые из того, что делает JavaScript с этим, довольно приятны (например, String
и Number
); другие части (что Date
делает ** содрогание **) не так приятно...]
Как и в ES2015 (ES6), создание иерархии прототипов и конструкторов является легким, благодаря новому синтаксису класса. Больше не нужны помощники.
class Base {
constructor(name) {
this.name = name;
}
greeting() {
return "Hi, I'm " + this.name;
}
}
class Derived extends Base {
constructor(name, age) {
super(name);
this.age = age;
}
greeting() {
return super.greeting() + " and I'm " + this.age + " years old";
}
}
Это не значит, что мы хотим их для всего, конечно. Я использую Object.create
для большого эффекта, когда мне нужно расширить один объект.
Ответ 3
Моя самая большая проблема с new
заключается в том, что она нарушает принцип Open/Closed. Из-за способа, которым new
управляет значением this
, конструкторы закрываются для расширения, а это означает, что если вам нужно его расширить, вы должны изменить его, возможно, сломав вызывающие в процессе.
Некоторые примеры того, как можно продлить предприятия, что new
не позволяет:
-
Скрыть детали создания объекта. (Остальные из них - примеры того, почему вы, возможно, захотите это сделать)
-
Храните измененные прототипы и функции init на объекте factory, доступном с помощью this
. (С new
, this
всегда ссылается на вновь созданный объект).
-
Расширить пул возможных типов объектов, разрешив вам добавить возможности к объекту factory (расширяемый полиморфизм).
-
Переопределите значение this
во время создания экземпляра с помощью .call()
или .apply()
(расширение повторного использования кода).
-
Возвращает прокси-сервер новому объекту в другом пространстве памяти (iframe, окно, другая машина).
-
Условно вернуть ссылку на существующий объект (на самом деле вы можете сделать это с помощью new
и конструкторов, но тогда this
бессмысленно и вводит в заблуждение внутри конструктора, потому что новый экземпляр получает выделение и затем отбрасывается если вы возвращаете нечто иное, чем новый объект).
-
Включение изменений в стратегию создания экземпляров без прерывания звонков.
Примечание. Меня постоянно раздражает то, что я не могу легко использовать любую из этих стратегий с помощью Backbone.js
, потому что это заставляет вас использовать new
, если вы не обернете его, но затем вы закрываете его стандартный механизм наследования. В противоположность этому, я никогда не чувствовал себя раздраженным тем, что jQuery использует функцию factory для создания экземпляров DOM, обернутых jQuery.