JavaScript中的“ new function()”,其小写字母“ f”


106

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

但是,我在任何地方都没有看到对此技术的任何参考。甚至道格拉斯·克罗克福德(Douglas Crockford)的JSLint也对此抱怨:

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

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


6
与IIFE(“立即调用功能”)相比,我更喜欢您的构造。1:您不需要显式的“实例”对象,这正是JavaScript中“ this”的含义。2:您无需返回任何内容,这意味着您无需记住。即使是接受答案的作者也忘记了最初返回实例对象!人们通常会喜欢使用IIFE(如果他们讨厌new),这有充分的理由-如果您有一个处理DOM事件的函数,this则将引用触发该事件的元素,而不是您的对象,而您可以引用它var instance = this
Lee Kowalkowski

1
为什么对这个问题指定“小写字母f”很重要?
2013年

7
因为在Javascript中还存在“函数”函数(大写的F),所以有所不同:函数是可以创建新函数对象的构造函数,而函数是关键字。
Stijn de Witt

1

@Bergi我阅读了您的链接。我认为没有理由抹黑这种模式。没错 这很简单。那怎么了 JSLint抱怨一切BTW :)
Stijn de Witt

Answers:


64

我之前已经看过该技术,它是有效的,您正在使用函数表达式,就像它是构造函数一样

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

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


1
第13节中的ECMAScript 262规范更正式地解释了这一点。诸如此类function foo () {}的结果返回创建Function对象的结果[大概使用new Function()]。这是语法糖。
克林顿·皮尔斯

3
我认为您return instance;最后缺少一个。否则,someObj将是undefined。:-)
马修·克鲁姆利

1
我是否可以建议您,如果您关心模块性和信息隐藏,您只是放弃这一点,而开始使用require.js之类的东西吗?你在那儿,为什么要在这里停下来?异步模块定义(这是require.js实现的)支持此用例,并为您提供了一个完整的工具集来处理范围,命名空间和依赖项管理。
Stijn de Witt

请注意,函数声明周围没有括号,因为存在以下内容,因此该声明已成为表达式:=
Explosion Pills 2013年

@StijndeWitt中途意味着您需要做两次工作才能使用require.js,但这可能是在简单情况下所需的全部。
xr280xr 2015年

15

您的代码类似于不太奇怪的构造

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

    ...
};
var someObj = new Foo;

9
它不仅相似,而且功能完全相同……唯一的例外是他们将无法重用Foo创建另一个对象。
kikito 2010年

3
可以通过新的someObj.constructor重用OP的版本。在这里,构造函数被显式添加到名称空间;正确的样式取决于功能的预期目的。同样,这种样式(尽管肯定是标准样式)可以让某人在Foo之前忘记名称时填充全局名称空间。
J布赖恩·普莱斯

@kikito是什么意思,这意味着不允许重复使用Foo创建另一个对象?var newObj = new Foo()应该创建一个新实例。
比尔·杨

1
@BillYang那是五年前。不知道。从那以后我再也没有碰过JavaScript。
kikito

12

为了阐明某些方面,并使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,而不是其实例。毕竟,这只是一个警告,而不是错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.