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

Deathmatch: Self Executing Anonymous Function -vs- "новая функция"

Ответ встроен ниже в UPDATE 2/ANSWER

Спасибо Джозефу за то, что он помог мне найти ответ (хотя мне это не нравится =).

ОРИГИНАЛЬНЫЙ ВОПРОС

Проводя некоторое исследование лучших практик при использовании именных слов в JavaScript, я натолкнулся на это определение "Model Pattern": http://yuiblog.com/blog/2007/06/12/module-pattern/.

Я обычно использовал этот шаблон, так как видел его в YUI2 года назад, и эта статья дает хороший обзор концепции. Но на что это не влияет, почему "Self Executing Anonymous Functions" используется вместо "новой функции". Это было задано в комментариях, но автор не был хорошо описан. Поскольку этой статье 4+ года (и я не нашел ответ в другом месте в Интернете), я думал, что приведу его здесь.

Это уже в закрытии, так? (см. Почему эта функция заключена в круглые скобки, а затем скобки?, которая также не отвечает на мой вопрос =).

Предполагая следующий установочный код.

var MyNamespace = window.MyNamespace || {};

Какое из них является предпочтительным и почему?

MyNamespace.UsingNew = new function() {
    var fnPrivate = function() {
        return "secrets1";
    };

    this.property = "value1";
    this.method = function() {
        return "property = " + this.property + ' ' + fnPrivate();
    }
};

MyNamespace.UsingSelfEx = (function() { //# <- Added "pre-parens" suggested by chuckj
    var fnPrivate = function() {
        return "secrets2";
    };
    var fnReturn = {};

    fnReturn.property = "value2";
    fnReturn.method = function() {
        return "property = " + this.property + ' ' + fnPrivate();
    }

    return fnReturn;
})();

UPDATE:

Кажется, что, подобно jQuery, все классные дети используют "Self Executing Anonymous Functions" (SEAF)! Но я просто этого не понимаю, поскольку я считаю, что использовать более эффективный подход .UsingNew гораздо проще, поскольку вы публикуете публичные функции при определении (а не ниже в возврате, которые необходимо поддерживать отдельно или вынуждать использовать встроенный объект обозначения).

Аргумент о том, что для этого не требуется "this = this", не может содержать воду для меня по ряду причин:

  • Чтобы избежать "var that = this", вы получаете либо "var obj", либо оператор return (который должен содержать отдельное определение того, что является общедоступным) или вынужден использовать встроенную запись объекта ( return {1,2,3}) для ваших общедоступных свойств/методов.
  • Вы всегда можете сделать приватную переменную "var that = this" в верхней части пространства классов/имен и использовать "это" во всем.

Теперь... Я полагаю, что мой стиль разработки вполне может облегчить управление шаблоном .UsingNew. Мои функции "private" почти всегда "статичны" по своей природе, поэтому мне нужно передать контекст в любом случае (вытесняя необходимость "this"). Я также привык использовать пространство имен аббревиатуры, поэтому, когда мне действительно нужен доступ к "this", я просто ссылаюсь на полный объект через пространство имен аббревиатуры, а не через его полный путь. Например:.

var PrivateFunct = function() {
    var rThis = Cn._.val; //# The abbreviated form of Cn.Renderer.Form.Validation
    //...
};

или если это Частная статическая функция...

var PrivateStaticFunct = function(oContext) {
    //...
};

В других случаях, приведенных выше, я лично считаю, что подход .UsingNew гораздо читабельнее в источнике. У меня довольно обширная база кода, в которой используется шаблон .UsingNew: http://code.google.com/p/cn-namespace/source/browse/Cn.Web/js/Cn/ с Функциональность валидации, вероятно, самая легкая задача, чтобы получить вашу голову в 1 быстром чтении. Я также использую некоторые функции SEAF (см. ErrorMessages.js.aspx), но только тогда, когда они имеют смысл.

Я не мог себе представить, что нужно поддерживать отдельные возвраты, чтобы разоблачить публичные интерфейсы внизу! Тьфу!

Теперь, не поймите меня неправильно, есть несколько мест, где SEAF очень полезен для обеспечения закрытия, но я лично считаю, что это злоупотребление внутри объектов.

ОБНОВЛЕНИЕ 2:

После дальнейшего размышления (и благодаря расширенному обсуждению с Джозефом под его ответом), похоже, существуют некоторые правила, которые могут быть применены к этому DEATHMATCH:

Per Douglas Crockford (см.: JS мы вряд ли начинаем Ya) Анонимные функции никогда не должны использовать "новый", потому что:

  • Быстрее использовать литерал объекта.
  • Используя new для вызова функции, объект удерживается на бесполезном объекте прототипа. Это отнимает память без компенсирующего преимущества. Если мы не используем новое, мы не храним потраченный впустую прототип объекта в цепочке. (ПРИМЕЧАНИЕ. Прототипные вызовы появляются после определения конструктора, и поскольку SEAF или "новые" анонимные функции запускаются в ближайшее время, нельзя использовать с ними прототип)
  • Это требует меньше кода для использования литерала объекта. (хотя это правда, я должен не согласиться с тем, что ненавижу объектную литературную нотацию, я бы предпочел использовать ее, а затем, поскольку она более читаема).
  • Не рекомендуется добавлять новые функции непосредственно перед функцией. Например, новая функция не дает преимуществ при построении новых объектов.

Таким образом, кажется, что это мясо и картофель: SEAF предпочтительнее var obj = new function() {...}; из-за скорости и меньших накладных расходов (без ненужного прототипа объекта). То, что вы должны испытывать, - это то, что вы вынуждены использовать объектную нотацию (так, а не между вашими публичными членами) или поддерживать отдельный список общедоступных объектов в возвращаемом объекте.

SEAF не рекомендуется, если вы планируете использовать функцию как конструктор объекта, поскольку instanceof не будет работать должным образом (см. создание объектов из закрытия JS: следует ли использовать "новое" ключевое слово?).

ОТВЕТ:

  • Если это анонимная функция, предназначенная для работы в качестве Singleton/Global Static Instance, используйте SEAF.
  • Если вы намерены использовать его как Constructor (чтобы потенциально представлять несколько объектов), или вы используете .prototype, используйте "стандартное" определение функции и вызовите "новый", например:

    function PseudoClass1() {}

    var PseudoClass2 = function() {};

    var myClass1 = new PseudoClass1();

    var myClass2 = new PseudoClass2();

Я должен сказать, что я не доволен этим ответом;) Я нахожу шаблон .UsingNew MUCH более читаемым в базе кода, но он медленнее и использует больше памяти, чем SEAF, из-за того, что неиспользуемая ссылка на прототип инстанцируется и остается в цепочке объектов.

4b9b3361

Ответ 1

С одной стороны, этот шаблон:

MyNamespace.UsingNew = new function() {
    var fnPrivate = function() {

        //what this in here?

        return "secrets1";
    };

    this.property = "value1";
    this.method = function() {

        //what this in here?

        return "property = " + this.property + ' ' + fnPrivate();
    }
};
  • использует ключевое слово "новое" для создания экземпляра объекта, который моделируется с использованием функции-конструктора. забыв использовать "новый", вы в конечном итоге называете создание функции MyNamespace.UsingNew() вместо объекта.

  • это функция-конструктор и еще не экземпляр объекта (пока вы не построите его с помощью нового). вам нужно использовать "this" для обозначения объекта, которым он станет. это просто добавляет проблемы в область видимости, особенно когда вы вставляете в нее больше функций, а значение "this" будет меняться время от времени (и вы не увидите его, пока консоль не сообщит об этом). знакомы с self=this или that=this, чтобы сохранить значение "this"? это довольно заметно при использовании этого шаблона

с другой стороны, следующий шаблон несколько лучше (для меня), поскольку:

  • вам не нужно использовать "новое", так как он возвращает объект.

  • не использует "this", поскольку он уже возвращает объект. вам даже не нужно "this".

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

ns.myobj = (function(){

    //private
    var _privateProp = '';
    var _privateMeth = function(){};

    //public
    var publicProp = '';
    var publicMeth = function(){};

    //expose public
    return {
        prop:publicProp,
        meth:publicMeth
    };
}());

Ответ 2

Оба они почти идентичны и должны иметь относительно одни и те же рабочие характеристики. Это просто вопрос стиля. Я, лично, предпочитаю второй, но он написан немного напуганным. Я бы написал это,

MyNamespace.UsingSelfEx = (function () {
    function fnPrivate() {
        return "secrets2";
    }
    return {
        property: "value2";
        method: function () { 
            return "property = " + this.property + " " + fnPrivate();
        }
    }
})();

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

Ответ 3

Я видел это, и мне это нравилось

var MyThing = (function(){

    function MyThing(args){
    }

    MyThing.prototype = {
        prototypeMethod: function() {}
    };

    return MyThing;
})();

Вы также можете сделать это

MyThing.create = function(args){
    return new MyThing(args);
}

Обычно он заключен в другую функцию self invoking. Во избежание именования столкновений.

(function({

})(window);

И объект window передается как аргумент, чтобы присвоить его верхней области.

window.MyThing = MyThing;

В этом примере вы можете использовать статические переменные, частные и т.д.