`new function()` с нижним регистром "f" в JavaScript

Мой коллега использует "новую функцию()" с нижним регистром "f" для определения новых объектов в JavaScript. Кажется, он хорошо работает во всех основных браузерах, и он также кажется довольно эффективным для скрытия частных переменных. Вот пример:

    var someObj = new function () {
        var inner = 'some value';
        this.foo = 'blah';

        this.get_inner = function () {
            return inner;
        };

        this.set_inner = function (s) {
            inner = s;
        };
    };

Как только используется "this", он становится общедоступным свойством someObj. Итак, someObj.foo, someObj.get_inner() и someObj.set_inner() доступны публично. Кроме того, set_inner() и get_inner() являются привилегированными методами, поэтому они имеют доступ к "внутренним" путем закрытия.

Однако я нигде не видел ссылок на эту технику. Даже Дуглас Крокфорд JSLint жалуется на это:

  • странная конструкция. Удалить 'новый'

Мы используем этот метод в производстве и, похоже, хорошо работаем, но я немного беспокоюсь об этом, потому что он нигде не документирован. Кто-нибудь знает, является ли это правильной техникой?

Ответ 1

Я видел эту технику раньше, это действительно так, вы используете выражение функции, как будто это Функция конструктора.

Но IMHO, вы можете добиться того же с помощью выражения функции автоматического вызова, я действительно не вижу смысла использовать оператор new таким образом:

var someObj = (function () {
    var instance = {},
        inner = 'some value';

    instance.foo = 'blah';

    instance.get_inner = function () {
        return inner;
    };

    instance.set_inner = function (s) {
        inner = s;
    };

    return instance;
})();

Целью оператора new является создание новых экземпляров объектов, настройка внутреннего свойства [[Prototype]], вы можете увидеть, как это делается с помощью [Construct] внутреннее свойство.

Приведенный выше код даст эквивалентный результат.

Ответ 2

Ваш код просто похож на менее странную конструкцию

function Foo () {
    var inner = 'some value';
    this.foo = 'blah';

    ...
};
var someObj = new Foo;

Ответ 3

Чтобы прояснить некоторые аспекты и заставить Douglas Crockford JSLint не жаловаться на ваш код, вот несколько примеров создания экземпляра:

1. o = new Object(); // normal call of a constructor

2. o = new Object;   // accepted call of a constructor

3. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
})(); // normal call of a constructor

4. var someObj = new (function () {  
    var inner = 'some value';
    this.foo = 'blah';

    this.get_inner = function () {
        return inner;
    };

    this.set_inner = function (s) {
        inner = s;
    };
}); // accepted call of a constructor

В примере 3. выражение в (...) как значение является функцией/конструктором. Это выглядит так: new (function() {...})(). Поэтому, если мы опускаем конечные скобки, как в примере 2, выражение по-прежнему является допустимым вызовом конструктора и выглядит как пример 4.

Дуглас Крокфорд JSLint "думает", что вы хотите назначить функцию someObj, а не ее экземпляр. А ведь это всего лишь предупреждение, а не ошибка.