返回其自身实例的Object

时间:2011-05-21 22:34:14

标签: javascript library-design

背景:我的最新项目无法使用大型图书馆,这让我很难过。我希望从任何库中获得一些内容,例如缺少的函数addClasshasClassremoveClass,兼容的addEventListener等等。所以我创建了{ {3}}我想在其他时间提出一些意见,但我在设置方面遇到了一些麻烦。

为了方便使用,我希望对象在创建时返回自己的新实例。

假设:

 $ = function() {
    this.name = "levi";

    return this;
};

console.log($());

我们得到DOMWindow而不是$,因为JavaScript中this的古怪性质。 对我来说更奇怪的是console.log(new $().name)正确地返回“levi”。如果this绑定到窗口,为什么对象正确获取值?。我们可以添加新的console.log(new $())并且它可以正常工作。但是,我不想每次都写新的。所以我试过了:

$ = function() {
    var obj = function() {
        this.name = "levi";
    };

    return new obj();
};

console.log($());

这给了我想要的东西,但是将对象包装在创建它的函数中似乎没有必要。此外,返回的对象是obj而不是$。比较测试将失败。

有什么其他方法可以做到这一点?有更优雅的解决方案吗?我对重新思考整个过程没有任何疑虑。我认为自己非常善于使用JavaScript,但创建新的JavaScript是我非常新的。


有没有人发现以下解决方案有什么问题?

$a = function() {};

$ = function() {
    if (!(this instanceof $)) {
        return new $();
    }

    this.name = "levi";

    return this;
};

//helper function
var log = function(message) {
    document.write((message ? message : '') + "<br/>");
};

log("$().name == window.name: " + ($().name == window.name)); //false
log("$().name: " + $().name); //levi
log("window.name: " + window.name); //result

log();

log("$a instanceof $: " + ($a instanceof $)); //false
log("typeof $a: " + (typeof $a)); //function
log("typeof $: " + (typeof $)); //function

它似乎在我的所有测试中都有效。

4 个答案:

答案 0 :(得分:5)

jQuery的工作方式是首先测试thiswindow(称为函数),如果是,则返回一个新的自身实例。例如:

var $ = function() {
    if(this === window) {
        return new $();
    }
    this.name = "levi";
    return this;
};

console.log($());

这是有效的,因为当您正常调用函数(func())时,this将与调用者的this相同。 (相关但不相关:obj.method() this将为obj)由于默认范围为windowthis内的$将为{ {1}}将其称为window

使用$()调用函数时,JavaScript会创建一个新对象,然后调用函数并将new设置为该对象。

此解决方案有效,因为它首先测试this是否为this,因此被调用为window。如果它被称为$(),它将返回$()。否则,它会被new $()调用,并将按预期工作。

答案 1 :(得分:5)

做你想做的最简单的方法是(我认为):

$ = function(){
    if (!(this instanceof $)){
     return new $;
    }
    this.name = 'levi'; 
    return this;
}

刚刚返回this的事实不会创建$的实例,这是因为this创建执行$作为常规函数的方式:在这种情况下的值this指向全局对象(在浏览器中:window,实际上调用执行$()window.$()相同。这可以说是javascript生活的事实。 console.log(new $().name)显示正确值的事实是因为您将该函数称为构造函数,该构造函数返回该构造函数的实例(即$的新实例)。但console.log($().name)也会打印'levi',因为它会返回属性为name的全局对象,即window.name。尝试$(); console.log(name),您会看到name现在是一个全局变量。因此,如果您不想每次都使用new关键字,请检查您的函数是作为常规函数调用,还是作为构造函数中的实例(=== instanceof $)的构造函数。使用上面的方法,实例构造函数,无论是否使用new进行实例化都将是$

也许您应该将问题的标题改为:'一个返回自身实例的对象[构造函数] '

也许this blog entry可以减轻额外的光线。

答案 2 :(得分:4)

>  $ = function() {
>     this.name = "levi";
> 
>     return this; };
> 
> console.log($());
  

我们得到DOMWindow而不是$

当你将 $ 作为一个函数调用时,它的 this 关键字被设置为全局对象,就像任何被调用的函数一样。

  

因为这个的古怪性质   在JavaScript中

Javascript的关键字*按照指定的方式工作。它与其他语言不同,但这就是它的工作方式。

  

对我来说更奇怪的是   console.log($()。name)正确返回   “列维”。

当您将 $ 作为函数调用时,其关键字是全局对象,因此:

this.name = 'levi';

创建名为 name 的全局对象的属性,其值为'levi'。当你知道发生了什么事时并不奇怪。 : - )

  

我们可以添加新的console.log(新的   $())并且它有效。

这就是构造函数应该在javascript中调用的方式。当使用 new 调用函数时,其 this 关键字将设置为新构造的对象,因此this.name将创建该对象的新属性。顺便提一下,return this是多余的,构造函数默认返回 this

> $ = function() {
>     var obj = function() {
>         this.name = "levi";
>     };
> 
>     return new obj(); };
  

的console.log($());这给了我什么   我想,但似乎有点不必要   将对象包装在一个   创造它的功能。进一步   更多,它是obj类型而不是$

据推测,您使用的是 typeof ,它只能返回ECMA-262指定的值之一。该短列表(包括对象,数字,字符串等)不包括 $

  

这可能有什么其他方式   做什么?

你可以使用你已经发现的方法,Lasse Reichstein Nielsen的克隆(也被Doublas Crockford推广为“beget”)和Richard Cornford的模块模式。使用Google,有很多很多关于以上所有内容的帖子。

答案 3 :(得分:1)

尝试这样的事情:

function $(name){
    if( !(this instanceof arguments.callee) ){
        return new arguments.callee(name);
    }
    this.name = name;
    return this;
}

更新

@Levi Morrison

  

编辑:有没有人发现以下解决方案有任何问题:

既然你问了I'm not exactly in love with document.write 试试这个:

var log = function(message){
    if(message){
        document.body.appendChild(document.createTextNode(message));
    }
    document.body.appendChild(document.createElement('br'));
}