【问题标题】:Returning a new object if new operator wasn't used如果未使用 new 运算符,则返回一个新对象
【发布时间】:2012-05-16 08:48:34
【问题描述】:

我在 js 中有一个名为 Foo 的“类”(函数)来创建对象。由于它使用非常频繁,我希望它避免在创建新实例时使用new 关键字:Foo(something); 而不是new Foo(something);

我让它在 Firefox 中工作:

function Foo(arg) {
    if (this instanceof Window)
        return new Foo(arg);

    //Object construction here.
    this.bar = "Hello " + arg;
}

现在我可以通过将其作为函数调用来创建 Foo 的实例。

console.log(Foo("World").bar); //Output "Hello World" in console.

虽然这在 FF 中有效,但在 Chrome 中却没有,我还不敢测试 IE。

chrome 中的问题是 window 在 chrome 中确实是 DOMWindow 类型

Uncaught ReferenceError: Window is not defined

this instanceof DOMWindow 在 chrome 中不起作用,因为出于某种原因它给出了:

ReferenceError: DOMWindow is not defined

我也尝试过使用!(this instanceof Foo)typeof this 似乎总是给"object"

如何可靠地检测在所有浏览器上调用 Foo 时是否省略了 new 关键字?

更新:!(this instanceof Foo) 确实有效,我只是在我真正的 Foo 函数中有一个流浪的 return this

【问题讨论】:

  • 使用 !(this instanceof Foo) 对我有用(Mac 上的 Chrome、Safari、Firefox)。该代码:function Foo() { console.log(this instanceof Foo) } 将记录 false 用于在上述浏览器中执行 Foo()true 用于 new Foo()
  • @ZER0 是的,我刚刚意识到我的函数中有一个杂散的return this 阻止它工作。

标签: javascript oop google-chrome object v8


【解决方案1】:

测试这是一个 Foo 实例在 Chrome 20、FF 12 和 IE 8 中工作,并且应该可以正常工作:

function Foo(arg) {
    if (!(this instanceof Foo)) return new Foo(arg);

    //Object construction here.
    this.bar = "Hello " + arg;
}

var foo = Foo('World');
var baz = new Foo('Baz');

console.log(foo.bar);
console.log(baz.bar);

作为一个小提琴:http://jsfiddle.net/YSEFK/

【讨论】:

  • 这对我以前不起作用。但现在我确实弄清楚了原因。我在函数的末尾有一个流浪的return this。这是一种更简洁的方式。
【解决方案2】:

我还没有测试过,但也许这样的东西会起作用?

var realWindow = this;

function Foo(arg) {
    if (this === realWindow)
        return new Foo(arg);

    //Object construction here.
    this.bar = "Hello " + arg;
}

当然,您需要确保在任何范围之外声明 realWindow,以避免可能与 this 发生冲突。

一般来说,虽然这个 很聪明,但我不建议这样做只是为了节省输入的几个字符。它混淆了未来开发人员的代码,通常不是好的做法。

【讨论】:

  • 这取决于你想要什么。对于像 jQuery 这样的框架,这非常舒服——想象一下,如果你必须一直使用 new $() 而不是 $()
  • @ThiefMaster,你是对的,当然。这就是为什么我说“一般”。几乎总是有这样的情况,违反规则或最佳实践是可以的,甚至是推荐的。 :)
  • 是的,这行得通,非常感谢。正如 ThiefMaster 所建议的那样,在某些情况下确实有意义。
  • 我能问一下为什么这被否决了吗?我的回答完全正确。
【解决方案3】:

反转条件呢?

function Foo(arg) {
    if (!(this instanceof Foo))
        return new Foo(arg);

    //Object construction here.
    this.bar = "Hello " + arg;
}

【讨论】:

  • 这行得通,但你必须重复函数的名称。当然你可以使用arguments.callee,但这在 ES 严格模式下是行不通的。
  • 我刚刚回复了OP的需求。就个人而言,我更喜欢在新实例上使用Object.create 然后apply constructor。这样你就不需要重复自己了,你也可以创建一个实用函数来为你完成这项工作。
【解决方案4】:

你应该这样做的方法是检查当前实例与它自己的类型:

function Foo(...args...) {
    if (!(this instanceof Foo)) {
        return new Foo(...args...);
    }
    ...do stuff...
}

它可以避免尝试检查全局对象,并且几乎可以在任何上下文中工作(尽管在其他情况下可能没有意义):

var a = {};
Foo.call(a);

这应该返回什么?在我的示例中,它将返回一个新的 Foo 实例,尽管您可能希望它创建一个新的 Foo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-14
    • 2014-12-05
    相关资源
    最近更新 更多