向对象添加方法
Adding methods to objects
在用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
JSFIDDLE JSBIN
编辑:使用$elect(id).toggle();
调用它。虽然你可以检查演示。
我想了解其中的逻辑。
$elect
是一个构造函数,应该使用 new
关键字 (new $select
) 调用。如果不是($elect()
),那会发生什么?没有构造实例,this
关键字将指向全局对象 ( window
) - 我们不想要。因此,当它检测到它使用 new
正确调用自身并返回该时,此代码段可以防止这种情况。
如果我删除它,功能会中断
当你在没有守卫的情况下像$elect(id)
一样调用它时,它将向全局对象(本质上是一个全局变量)添加一个 elm
属性并且不返回任何内容。尝试调用 .toggle()
方法将产生异常undefined has no method 'toggle'
。
我试图删除 if 语句,假设
window === this
返回 true
好吧,然后你刚刚创建了一个无限递归函数,该函数在调用时会导致堆栈溢出异常。
顺便说一句,防止new
-less调用的正确方法不是与window
进行比较(全局对象在非浏览器环境中可能具有不同的名称)并假设其他一切都正常,而是检查正确的继承。您希望构造函数仅应用于"类"的实例,即从$elect.prototype
继承的对象。例如,当使用 new
调用时,这是可以保证的。要执行该检查,您将使用 instanceof
运算符:
function $elect(id) {
if (! (this instanceof $elect)) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
这也使守卫的意图明确
要了解该条件的工作原理,您必须首先知道在全局范围内this
是指window
对象。在本地范围内,例如在对象内,this
是指对象本身。
$elect
函数是框架的构造函数。如果你直接调用它,就像这样:
$elect('some-id-blah')
它将首先意识到您正在尝试创建一个实例(因为条件window === this
的计算结果为 true),并且它将递归创建自身的新实例。一旦这样做,this
将不再引用window
对象,它将引用库的新实例,因此将不满足条件。
我希望这在某种程度上是可以理解的。
你的函数是一个构造函数。默认情况下,任何未在任何其他对象上显式调用($elect()
,而不是foo.$elect()
)的函数中的this
作为方法,将在this
中传递全局对象(window
)。但是,if
检查如果this
确实引用了window
对象,则执行return new $elect(id);
。new $elect(id)
执行以下操作:
- 创建
$elect.prototype
的新实例 - 将新创建的实例放入
this
,然后再次调用该方法。
在第二遍时,this === window
的计算结果为 false
。
首先要了解的是,这个函数正在调用自己:
function $elect(id) {
if (window === this) {
return new $elect(id);
}
this.elm = document.getElementById(id);
}
第一次调用函数窗口将是===这个。因为在那里您将函数作为方法调用。当作为方法调用时,函数将绑定到函数/方法所属的对象。在此示例中,this
将绑定到窗口,即全局范围。
但是,使用 new
关键字,您将函数作为构造函数调用。当作为构造函数调用时,将创建一个新对象,并且this
将绑定到该对象,因此this
不再第二次引用window
。
使用 $elect 的新实例,您还可以为该实例正确设置局部变量 elm,从而允许其他函数稍后调用该 elm。
这个逻辑:
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;
演示小提琴
如果你这样称呼它:
$elect("theId").hide();
第一次在其中调用为函数,将找到window === this
并执行以下操作:
return new $elect("theId")
这将创建一个新函数并再次调用该函数。(无论函数返回的第二次调用是什么,都将返回。
第二次,它被称为构造函数,所以window !== this
,它将向下传递以查找元素并将其存储在内部。
不从函数本身返回任何内容的构造函数调用将返回创建的实例。
这样,.hide()
部分将以正确的值 this
(第一次创建的实例)执行。并且该元素将从屏幕上消失。
请注意,如果您这样称呼它:
var bob = {};
bob.$select("theId").hide();
它不起作用,因为this
设置为bob
哪个 get 和 'elm' 属性集,并且没有要调用的"隐藏"属性,因为它不是一个$elect
类型的对象。
注意
如果其他函数中的所有其他方法都返回this
您将能够链接它们:
$elect('theId').show().red();
假设您添加了一个函数来将元素着色为红色。
- 如何在Angular单元测试中从另一个控制器的rootScope将方法添加到rootScope中
- 如何将onChange方法添加到ExtJS 4表单中的所有字段(textField)中
- 如何向.apply()方法添加回调
- 向 Firebase “push” 方法添加时间戳
- jQuery方法添加一个TextBox
- 如何将方法添加到Html5画布
- 什么'在javascript中将新方法添加到对象中的区别是什么
- 如何在角度控制器中为该方法添加验证
- 是否可以将方法添加到空值的原型中
- 如何使用 util 将方法添加到模块 express() 中
- 在 JavaScript 中隐式地将方法添加到构造函数的原型中
- 如何将另一个方法添加到Pinterest按钮的onlick事件中
- 将方法添加到数字引发异常
- 向方法添加方法
- 通过下拉列表框上的 appendChild 方法添加的项目不会显示在 IE8 下
- 如何将实例方法添加到帆中的所有模型.js
- 为什么我的javascript .push方法添加了太多对象
- 分机.js确认方法添加新行字符
- 使用原型将新方法添加到JScrollPane
- 我想克隆一个 javascript 类. 将方法添加到克隆的属性中,而不实际覆盖现有方法