Является ли 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.