Подтвердить что ты не робот

OO Конструктор конструктора Javascript: неоклассический против прототипа

Я смотрел разговор Дугласа Крокфорда о хороших частях в Javascript и мои глаза были открыты. В какой-то момент он сказал, что-то вроде: "Javascript - это единственный язык, на котором хорошие программисты считают, что могут эффективно использовать его, не изучая его". Тогда я понял, что я тот парень.

В этом разговоре он сделал несколько заявлений, которые для меня были довольно неожиданными и проницательными. Например, JavaScript является самым важным языком программирования на планете. Или это самый популярный язык на планете. И, что он разбит многими серьезными способами.

Самое удивительное выражение, которое он сделал для меня, было "новым опасным". Он больше не использует его. Он не использует this.

Он представил интересный шаблон для конструктора в Javascript, который позволяет использовать частные и общедоступные переменные-члены и не использует ни new, ни this. Это выглядит так:

// neo-classical constructor
var container =  function(initialParam) {
    var instance = {}; // empty object 

    // private members
    var privateField_Value = 0;
    var privateField_Name = "default";

    var privateMethod_M1 = function (a,b,c) {
        // arbitrary
    }; 

    // initialParam is optional
    if (typeof initialParam !== "undefined") {
        privateField_Name= initialParam;
    }

    // public members
    instance.publicMethod = function(a, b, c) {
        // because of closures,
        // can call private methods or
        // access private fields here. 
    };

    instance.setValue = function(v) {
        privateField_Value = v;
    };

    instance.toString = function(){
        return "container(v='" + privateField_Value + "', n='" + privateField_Name + "')";
    };

    return instance;
}


// usage
var a = container("Wallaby");
WScript.echo(a.toString()); 
a.setValue(42);
WScript.echo(a.toString()); 

var b = container();
WScript.echo(b.toString()); 

EDIT: обновлен код для переключения на имя нижнего регистра.

Этот шаблон развился из ранее использовавшихся моделей Crockford.

Вопрос: Используете ли вы такой шаблон конструктора? Вы находите это понятным? У вас есть лучший?

4b9b3361

Ответ 1

Это похоже на не-синглтонную версию шаблона в результате чего частные переменные можно моделировать, используя преимущества "закрытия" JavaScript,

Мне нравится (вид...). Но я не вижу преимущества в частных переменных, выполненных таким образом, особенно когда это означает, что любые новые методы, добавленные (после инициализации), не имеют доступа к закрытым переменным.

Кроме того, он не использует прототипную модель JavaScript. Все ваши методы и свойства должны быть инициализированы КАЖДЫЙ раз, когда вызван конструктор - это не происходит, если у вас есть методы, хранящиеся в прототипе конструктора. Дело в том, что использование обычного шаблона конструктора/прототипа намного быстрее! Действительно ли вы считаете, что частные переменные делают производительность успешной?

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

Используете ли вы такой шаблон конструктора?

Нет, хотя я использую его одноэлементный вариант, шаблон модуля...

Вы находите это понятным?

Да, это читаемо и понятно, но мне не нравится идея сбрасывать все внутри такого конструктора.

У вас есть лучший?

Если вам действительно нужны частные переменные, тогда обязательно используйте его. В противном случае просто используйте обычный шаблон конструктора/прототипа (если вы не разделяете страх Crockford с комбо new/this):

function Constructor(foo) {
    this.foo = foo;
    // ...
}

Constructor.prototype.method = function() { };

Другие подобные вопросы, касающиеся взглядов Дуга по теме:

Ответ 2

Я избегаю этого шаблона, поскольку большинству людей сложнее читать. Я обычно придерживаюсь двух подходов:

  • Если у меня есть только что-то, я использую анонимные объекты:

    var MyObject = {
        myMethod: function() {
            // do something
        }
    };
    
  • Для более чем одного из них я использую стандартное прототипное наследование javascript

    var MyClass = function() {
    };
    MyClass.prototype.myMethod = function() {
        // do something
    };
    
    var myObject = new MyClass();
    

(1) гораздо легче читать, понимать и писать. (2) более эффективен при наличии нескольких объектов. Код Crockford каждый раз создает новую копию функций внутри конструктора. Закрытие также имеет недостатки в отладке.

Хотя вы теряете действительно частные переменные, вы префикс предполагаемых к существованию членов с _ в качестве условного обозначения.

this - это, по общему признанию, трудная проблема в javascript, но ее можно использовать с помощью .call и .apply для правильной настройки. Я также часто использую var self = this; для создания переменной закрытия, используемой в качестве this внутри функций, определенных внутри функции-члена.

MyClass.prototype.myMethod = function() {
    var self = this;

    // Either
    function inner1() {
        this.member();
    }
    inner1.call(this);

    // Or
    function inner2() {
        self.member();
    }
    inner2();
};

Ответ 3

Используете ли вы такой шаблон конструктора?

Неа

Вы находите это понятным?

Да, это очень прямо.

У вас есть лучший?

Я еще не смотрел этот разговор, но скоро приеду к нему. До тех пор я не вижу опасности использования new и this, и вот почему:

Не услышав его моментов, я могу только предположить, что он предлагает избегать таких вещей из-за природы this и того, как она подвержена изменениям в зависимости от контекста, в котором выполняется конкретный метод (непосредственно на исходный объект или в качестве обратного вызова и т.д.). Как преподаватель, он может учить избегать этих ключевых слов из-за демографических, в значительной степени неосознанных и неопытных разработчиков, которые балуются в JavaScript без предварительного анализа характера языка. Для опытных разработчиков, которые близко знакомы с языком, я не убежден, что необходимо избегать этой особенности языка, которые придают ему невероятную гибкость (что совершенно не так, как можно избежать таких вещей, как with). Все, что сказал, я сейчас буду смотреть.

Во всяком случае, если вы не используете какой-либо фреймворк, который поддерживает автоматическое наследование (например, dojo.declare), или при написании независимого от структуры объекта, я в настоящее время применяю следующий подход.

Определение:

var SomeObject = function() {
    /* Private access */
    var privateMember = "I am a private member";
    var privateMethod = bindScope(this, function() {
        console.log(privateMember, this.publicMember);
    });

    /* Public access */
    this.publicMember = "I am a public member";

    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
    this.privateMethodWrapper = function() {
        privateMethod();
    }
};

Использование

var o = new SomeObject();
o.privateMethodWrapper();

Где bindScope - это функция полезности, аналогичная Dojo dojo.hitch или прототипу Function.prototype.bind.

Ответ 4

В своей книге он называется функциональным наследованием (стр. 52). Я еще не использую его. Это понятно, если вы изучите javascript из Дугласа. Я не думаю, что есть лучший подход. Это хорошо, потому что это:

  • позволяет программисту создавать частные члены

  • защищает частных членов и устраняет это, если вы не согласны с притворством-конфиденциальности (частные члены начинаются с _)

  • делает наследование гладким и без ненужного кода

Однако он имеет некоторые недостатки. Подробнее об этом можно прочитать здесь: http://www.bolinfest.com/javascript/inheritance.php

Ответ 5

Используете ли вы такой шаблон конструктора?

Я использовал этот patter раньше, когда я впервые изучил JavaScript и наткнулся на литературу Дугласа Крокфорда.

Вы находите это понятным?

Пока вы понимаете закрытие, этот метод понятен.

У вас есть лучший?

Это зависит от того, что вы пытаетесь выполнить. Если вы пытаетесь написать библиотеку, которая будет как можно больше идиот, я могу полностью понять использование частных переменных. Это может помочь предотвратить непреднамеренное нарушение пользователем целостности вашего объекта. Да, стоимость во времени может быть немного больше (примерно в 3 раза больше), но стоимость времени - спорный аргумент, пока он фактически не повлияет на ваше приложение. Я заметил тест, упомянутый в предыдущем посте (test) не учитывает, сколько времени требуется для доступа к объектным функциям.

Я обнаружил, что метод прототипа/конструктора обычно приводит к более быстрому времени построения, да, но это не обязательно экономит время на поиск. Существует дополнительная стоимость использования цепочки прототипов для поиска функции по сравнению с функцией, прикрепленной непосредственно к используемому вами объекту. Поэтому, если вы вызываете много прототипов и не создаете много объектов, может иметь смысл использовать шаблон Крокфорда.

Я склонен не любить использовать частные переменные, хотя, если я не пишу свой код для большой аудитории. Если у меня есть группа людей, которые все способны кодеры, я могу, как правило, доверять, что они будут знать, как использовать мой код, если я правильно код и комментарий. Затем я использую нечто похожее на шаблон Крокфорда без частных участников/методов.

Ответ 6

Если нам нужно создать всегда один и тот же объект, я скорее использую шаблон конструктора Prototypal, так как он позволяет обмениваться методами и свойствами с помощью автоматического делегирования через цепочка прототипов.

Также мы можем сохранить частные объекты; посмотрите на этот подход:

var ConstructorName = (function() { //IIFE
    'use strict';

    function privateMethod (args) {}

    function ConstructorName(args) {
        // enforces new (prevent 'this' be the global scope)
        if (!(this instanceof ConstructorName)) {
            return new ConstructorName(args);
        }
        // constructor body
    }

    // shared members (automatic delegation)
    ConstructorName.prototype.methodName = function(args) {
        // use private objects
    };

    return ConstructorName;
}());

Я рекомендую рассмотреть этот ответ, где мы можем найти интересный способ создания функции-конструктора: Различные способы создания объекта Javascript

Это пример, где вы можете использовать подход прототипального конструктора: Как создать пользовательскую ошибку в JavaScript?

Ответ 7

Подумайте, что может помочь в обсуждении, чтобы сообщить здесь, что является основным моментом в этом шаблоне, как объяснил Дуглас Крокфорд в своем презентационном видео "Advanced JavaScript".

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

Это основной момент этого шаблона Powerconstructor.

Частная/привилегированная часть является вторичной. Это нормально делать по-другому. Так что элементы-прототипы не используются.

HTH luKa