背景:我的最新项目无法使用大型图书馆,这让我很难过。我希望从任何库中获得一些内容,例如缺少的函数addClass
,hasClass
,removeClass
,兼容的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
它似乎在我的所有测试中都有效。
答案 0 :(得分:5)
jQuery的工作方式是首先测试this
是window
(称为函数),如果是,则返回一个新的自身实例。例如:
var $ = function() {
if(this === window) {
return new $();
}
this.name = "levi";
return this;
};
console.log($());
这是有效的,因为当您正常调用函数(func()
)时,this
将与调用者的this
相同。 (相关但不相关:obj.method()
this
将为obj
)由于默认范围为window
,this
内的$
将为{ {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'));
}