【问题标题】:`new function()` with lower case "f" in JavaScriptJavaScript中带有小写“f”的`new function()`
【发布时间】:2011-01-17 11:55:52
【问题描述】:

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

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

  • 奇怪的结构。删除“新”

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

【问题讨论】:

  • 我更喜欢你的构造而不是 IIFE('立即调用函数')。 1:您不需要显式的“实例”对象,这正是 JavaScript 中的“this”。 2:您不需要退回任何东西,这意味着您不需要记住。甚至接受答案的作者最初也忘记返回实例对象!如果人们讨厌 new 和 this,他们通常更喜欢使用 IIFE,这是有充分理由的 - 如果你有一个处理 DOM 事件的函数,this 将引用触发事件的元素,而不是你的对象,但你可以有var instance = this 代替。
  • 为什么指定“小写 f”对这个问题很重要?
  • 因为在Javascript中也存在'Function'函数(大写F),不同的是:Function是构造函数,可以创建新的函数对象,而function 是一个关键字。
  • @Bergi 我读了你的链接。我认为没有理由抹黑这种模式。这是有效的。这很简单。那么有什么问题。 JSLint 抱怨一切顺便说一句:)

标签: javascript function object instantiation


【解决方案1】:

我以前见过这种技术,它是有效的,你正在使用一个函数表达式,就好像它是一个 Constructor 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] 内部属性是如何做到的。

上面的代码会产生一个等价的结果。

【讨论】:

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

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

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

    ...
};
var someObj = new Foo;

【讨论】:

  • 它不仅相似,而且做同样的事情......唯一的例外是他们将无法重用 Foo 来创建另一个对象。
  • OP 的版本可以通过 new someObj.constructor 重用。这里构造函数被显式地添加到命名空间中;正确的样式取决于函数的预期目的。此外,这种风格 - 虽然肯定是标准 - 允许某人在 Foo 之前忘记 new 时填充全局命名空间。
  • @kikito 你是什么意思这不允许重用 Foo 来创建另一个对象? var newObj = new Foo() 应该创建一个新实例。
  • @BillYang 那是 5 年前的事了。不知道。从那以后我再也没有接触过javascript。
【解决方案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 中,(...) 中的表达式作为值是一个函数/构造函数。它看起来像这样: 新的(函数(){...})()。因此,如果我们在示例 2 中省略结束括号,则表达式仍然是有效的构造函数调用,并且看起来像示例 4。

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

【讨论】:

    猜你喜欢
    • 2023-04-09
    • 2016-12-04
    • 1970-01-01
    • 2019-11-03
    • 2022-11-10
    • 2021-12-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多