JavaScript 中带有小写“f”的 `new function()`

IT技术 javascript function object instantiation
2021-01-28 18:55:39

我的同事一直在使用带有小写字母“f”的“new function()”来定义 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() 是特权方法,因此它们可以通过闭包访问“内部”。

但是,我在任何地方都没有看到对这种技术的任何引用。甚至 Douglas Crockford 的 JSLint 也抱怨它:

  • 奇怪的建筑。删除“新”

我们正在生产中使用这种技术,它似乎运行良好,但我对此有点担心,因为它没有在任何地方记录。有谁知道这是否是一种有效的技术?

3个回答

我以前见过这种技术,它是有效的,您正在使用函数表达式,就好像它是一个构造函数 Function

但是恕我直言,您可以使用自动调用函数表达式实现相同的目的,我真的不明白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]内部属性是如何制作的

上面的代码将产生等效的结果。

我可以建议,如果你关心module化和信息隐藏,你就放弃这个并开始使用像 require.js 这样的东西吗?你已经走到一半了,为什么要停在这里?异步module定义(这是 require.js 实现的)支持这个用例,并为您提供一个完整的工具集来处理范围、命名空间和依赖项管理。
2021-03-23 18:55:39
我认为你return instance;最后缺少一个否则,someObj只会是undefined:-)
2021-03-27 18:55:39
请注意,函数声明周围的括号是不必要的,因为由于存在 =
2021-03-30 18:55:39
@StijndeWitt 中途意味着您需要做两倍的工作才能使用 require.js,但在简单的情况下这可能就是您所需要的。
2021-04-04 18:55:39
第 13 节中的 ECMAScript 262 规范更正式地解释了这一点。类似的东西function foo () {}返回创建Function对象的结果[大概是用 new Function()]。这是语法糖。
2021-04-11 18:55:39

您的代码与不那么奇怪的构造相似

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

    ...
};
var someObj = new Foo;
OP 的版本可以通过新的 someObj.constructor重用这里将构造函数显式添加到命名空间中;正确的风格取决于函数的预期目的。此外,这种风格 - 尽管肯定是标准 - 如果有人Foo之前忘记了new则可以让他们填充全局命名空间
2021-03-17 18:55:39
@BillYang 那是 5 年前。不知道。从那以后我就再也没有接触过 javascript。
2021-03-24 18:55:39
它不仅相似,而且完全相同……唯一的例外是它们将无法重用 Foo 来创建另一个对象。
2021-03-30 18:55:39
@kikito 你是什么意思这不允许重用 Foo 来创建另一个对象?var newObj = new Foo() 应该创建一个新实例。
2021-04-05 18:55:39

为了澄清某些方面并使 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。

Douglas Crockford 的 JSLint “认为”您想将函数分配给 someObj,而不是它的实例。毕竟这只是一个警告,而不是一个错误。