在JS编写了一段时间后,我决定制作自己的框架。类似于jQuery的东西。但是一个非常简单的版本。经过一些谷歌搜索,我把这段代码放在一起:
function $elect(id) {
if (window === this) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
$elect.prototype = {
hide: function () { this.elm.style.display = 'none'; },
show: function () { this.elm.style.display = ''; },
toggle: function ()
{
if (this.elm.style.display !== 'none') {
this.elm.style.display = 'none';
} else {
this.elm.style.display = '';
}
}
};
到目前为止,这似乎有效。但我对功能不感兴趣。我想了解逻辑。添加方法部分是可以理解的。虽然我不明白
的功能 if (window === this) {
return new $elect(id);
}
如果我删除它,功能中断。由于这是一个if语句,因此有2个结果。 True
或false
。所以我尝试删除if语句,只使用return new $elect(id);
假设window === this
返回true
,但这不起作用。然后我认为它可能会返回false
,因此删除了整个if语句。这也行不通。有人可以开导我吗?这段代码也有效吗?我可能错过了一些东西。
刚刚在jsfiddle上测试过,它不起作用。虽然它适用于jsbin o.O
编辑:使用$elect(id).toggle();
来调用它。虽然你可以查看演示。
答案 0 :(得分:1)
我想了解逻辑。
$elect
是constructor function,应该使用new
keyword(new $select
)进行调用。如果不是($elect()
),那么会发生什么?没有构造实例,this
keyword将指向全局对象(window
) - 我们不想要它。因此,当它检测到它使用new
正确调用自身并返回时,此片段就是防范该场合。
如果我删除它,功能中断
当你在没有守卫的情况下调用它$elect(id)
时,它会向全局对象添加elm
属性(本质上是一个全局变量)并且不返回任何内容。尝试在其上调用.toggle()
方法将产生异常undefined has no method 'toggle'
。
我试图删除if语句,假设
window === this
返回true
那么,你刚刚创建了一个无限递归函数,在调用时会导致堆栈溢出异常。
顺便说一句,proper way to guard against new
-less invocation不与window
进行比较(全局对象在非浏览器环境中可能有不同的名称)并假设其他一切都没问题,但要检查是否正确遗产。您希望构造函数仅应用于“类”的实例,即从$elect.prototype
继承的对象。例如,使用new
调用时可以保证这一点。要进行此检查,您将使用instanceof
operator:
function $elect(id) {
if (! (this instanceof $elect)) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
这也使得警卫的意图明确。
答案 1 :(得分:1)
要了解该条件的工作原理,您必须首先知道全局范围this
引用window
对象。在本地范围内,例如在对象内,this
引用对象本身。
您的$elect
函数是框架的构造函数。如果你直接调用它,就像这样:
$elect('some-id-blah')
它将首先意识到您正在尝试创建一个实例(因为条件window === this
将评估为true),并且它将递归地创建自己的新实例。一旦这样做,this
将不再引用window
对象,它将引用库的新实例,因此不会满足条件。
我希望这有点可以理解。
答案 2 :(得分:0)
这个逻辑:
if (window === this) {
return new $elect(id);
}
确保将构造函数作为函数调用:
var foo = $elect(id);
而不是构造函数:
var fo = new $elect(id);
它将返回正确的结果 - 一个新的$ elect对象。当作为函数调用时,默认上下文将是全局上下文或window
在浏览器中运行时,触发if
子句并返回将其作为构造函数调用的结果。
为什么它不适合你的小提琴
在链接小提琴中,设置将代码包装在onload
处理程序中。结果如下:
window.onload=function(){
function $elect(id) {
if (window === this) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
$elect.prototype = {
hide: function () { this.elm.style.display = 'none'; },
show: function () { this.elm.style.display = ''; },
toggle: function ()
{
if (this.elm.style.display !== 'none') {
this.elm.style.display = 'none';
} else {
this.elm.style.display = '';
}
}
};
}
因此,您的$elect
变量在onload
处理程序范围之外不可见。
通常,您希望将一个变量添加到全局范围以启用对框架的访问。在上面的代码末尾添加的类似内容将使其可见:
window.$elect = $elect;
答案 3 :(得分:0)
首先要明白的是,这个函数正在调用自己:
function $elect(id) {
if (window === this) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
第一次调用函数窗口将是===这个。因为你正在调用函数作为方法。当作为方法调用时,函数将绑定到函数/方法所属的对象。在此示例中,this
将绑定到窗口,即全局范围。
然后使用new
关键字,您将该函数作为构造函数调用。当作为构造函数调用时,将创建一个新对象,this
将绑定到该对象,因此this
第二次不再引用window
。
使用$ elect的新实例,您还可以正确地将一个局部变量elm设置为该实例,允许您的其他函数稍后调用该elm。
答案 4 :(得分:0)
您的函数是构造函数。默认情况下,作为方法在任何其他对象上未显式调用(this
,而不是$elect()
)的任何函数中的foo.$elect()
将传递给全局对象(window
)在this
。但是if
检查如果this
确实引用window
对象,则执行return new $elect(id);
。 new $elect(id)
执行以下操作:
$elect.prototype
this
并再次调用该方法。在第二次传递中,this === window
评估为false
。
答案 5 :(得分:0)
如果你这样称呼它:
$elect("theId").hide();
第一次将其作为一个函数调用并找到window === this
并执行此操作:
return new $elect("theId")
创建一个新的并再次调用该函数。 (无论函数返回的第二次调用将返回。)
第二次,它被称为构造函数,所以window !== this
它将向下传递以找到元素并将其存储在内部。
不从函数本身返回任何内容的构造函数调用将返回创建的实例。
这样.hide()
部分将以this
的正确值(第一次创建的实例)执行。元素将从屏幕上消失。
请注意,如果您这样称呼它:
var bob = {};
bob.$select("theId").hide();
它不起作用,因为this
设置为bob
得到和'elm'属性设置,并且没有'hide'属性被调用,因为它不是$elect
一种对象。
注意强>
如果其他函数中的所有其他方法都返回this
,您将能够将它们链接起来:
$elect('theId').show().red();
假设您添加了一个将元素着色为红色的函数。