即使忘记了"新",我应该何时自动创建一个对象?

qwe*_*ynl 16 javascript object

我们假设我有以下对象构造函数:

function Foo(bar) {
    this.bar = bar;
}
Run Code Online (Sandbox Code Playgroud)

如果我在没有new关键字的全局范围内运行该函数,那么bar将在以下任何范围内设置Foo():

var foo = Foo(42);
console.log(bar); // 42
console.log(foo.bar); // ERROR
Run Code Online (Sandbox Code Playgroud)

所以我的想法是做这样的事情:

function Foo(bar) {
    if(!(this instanceof Foo)) {
        // return a Foo object
        return new Foo(bar);
    }
    this.bar = bar;
}
Run Code Online (Sandbox Code Playgroud)

这样,如果我做的new Foo(42) 还是 Foo(42),它会始终返回一个Foo对象.

这是有史以来一个好主意?如果是的话,何时?何时(和为什么)避免这种技术是明智的?

Che*_*try 8

虽然我没有任何反对这种风格的东西,但我个人并不只是为了保持一致.当然,我可以使我的所有构造函数都像这样,但看起来似乎要编写更多的代码.

如果我担心没有意外调用构造函数new,我宁愿使用JSHint来警告我.请参阅http://www.jshint.com/docs/options/#newcap.


Tra*_*s J 8

当您希望在内部构造对象包装器时,这可能很有用.

一个鲜为人知的库在内部使用这种方法,jQuery.

他们不再使用这种instanceof方法了.每次调用jQuery时,它都会自动执行以下操作:

// Define a local copy of jQuery
jQuery = function( selector, context ) {
 // Need init if jQuery is called (just allow error to be thrown if not included)
 return new jQuery.fn.init( selector, context );
}
Run Code Online (Sandbox Code Playgroud)

它在内部所做的一切都引用了这个本地副本.在其工作的最后,它将其附加到全球范围

window.jQuery = window.$ = jQuery;
Run Code Online (Sandbox Code Playgroud)

所以每次你$()在内部使用时都会调用它new.它也假设您使用new外部,但如果您不这样做,它真的不在乎.


编辑

jsFiddle Demo

//Foo entrance
function Foo(bar){
 //construct a new Foo object to return
 return new Foo.prototype.build(bar);
}

//constructor for returning new prototype
Foo.prototype.build = function(bar){
 //initialize base settings
 this.bar = bar;
 //chain object
 return this;
};

//this is the complex part
//tie the prototype of Foo.prototype.build.prototype to Foo.prototype
//so that is "seems" like Foo is the parent of the prototype assignments
//while allowing for the use of returning a new object in the Foo entrance
Foo.prototype.build.prototype = Foo.prototype;

//simple expansions at this point, nothing looks too different
//makes a function for a constructed Foo that logs hello
Foo.prototype.hello = function(){
 console.log("Hello "+this.bar+" :)");
 //returns this for chaining
 return this;
};

//more extensions, this one changes this.bar's value
Foo.prototype.setBar = function(arg){
 //accesses the current Foo instance's .bar property
 this.bar = arg;
 //returns this for chianing
 return this;
};

//should be seeing a pattern
Foo.prototype.goodbye = function(){
 console.log("Bye "+this.bar+" :(");
 return this;
};

var foo = Foo(42);
//console.log(bar); // ERROR
console.log(foo.bar); // 42
foo.hello(); //Hello 42 :)
foo.hello().setBar(9001).goodbye(); //Hello 42 :) Bye 9001 :(
Foo(12).hello(); //Hello 12 :)
Run Code Online (Sandbox Code Playgroud)

  • @qwertynl - 我认为返回值必须是复杂类型.如果它是值类型,那么您仍然可以获得构造的Function对象.所以`return bar`或`return"hi"`仍将返回一个新的Foo,但是`return []`,或`return {}`,或`return new Something()`,或者返回任何其他复杂类型代替.例如:`function Foo(bar){this.bar = bar; return []; } var foo = new Foo(42); 的console.log(FOO); 的console.log(foo.bar);`.foo将是[]和foo.bar将是未定义的.然而,如果`Foo`返回`bar`,那么foo将是一个构造的`Foo`和`foo.bar`将是42. (2认同)