当您编写复杂的jQuery/javascript时,如何在不重新定义先前定义的this
变量的情况下使用this
进行管理?在命名this
变量时(随着嵌套的加深),您是否有经验法则或个人偏好?
有时我希望来自更高作用域的变量可用于嵌套函数/回调,但有时我希望有一个干净的历史/作用域;有没有一种调用函数/回调而不必担心变量冲突的好方法?如果有,你使用的是什么技术?
一些非常愚蠢的测试代码:
$(document).ready(function() {
console.warn('start');
var $this = $(this),
$dog = $('#dog'),
billy = function() {
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog);
var $this = $(this);
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog);
};
// (#1)
billy(); // BILLY! THIS: undefined | DOG: jQuery(p#dog)
// BILLY! THIS: jQuery(Window /demos/this/) | DOG: jQuery(p#dog)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // THIS: jQuery(Document /demos/this/) | DOG: jQuery(p#dog)
// (#2)
billy(); // BILLY! THIS: undefined | DOG: jQuery(p#dog)
// BILLY! THIS: jQuery(Window /demos/this/) | DOG: jQuery(p#dog)
$('#foo').slideUp(function() {
// (#3)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // BILLY! THIS: undefined | DOG: jQuery(p#dog)
var $this = $(this); // (#10)
// (#4)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // BILLY! THIS: jQuery(Window /demos/this/) | DOG: jQuery(p#dog)
});
$('#clickme').click(function() {
// (#5)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // THIS: undefined | DOG: jQuery(p#dog)
var $this = $(this);
// (#6)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // THIS: jQuery(button#clickme) | DOG: jQuery(p#dog)
$('#what').animate({
opacity : 0.25,
left : '+=50',
height : 'toggle'
}, 500, function() {
// (#7)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // THIS: undefined | DOG: jQuery(p#dog)
var $this = $(this);
// (#8)
console.log('THIS:', $this, ' | ', 'DOG:', $dog); // THIS: jQuery(div#what) | DOG: jQuery(p#dog)
});
});
// (#9)
billy(); // THIS: undefined | DOG: jQuery(p#dog)
// THIS: jQuery(div#foo) | DOG: jQuery(p#dog)
console.warn('finish');
});
A full demo page can be found here (jsbin.com)。
注意:正如您所看到的,为了便于参考,我已经用数字(#XX)“标记”了注释。
观察1:
标记(#1)
BILLY! THIS: undefined | DOG: jQuery(p#dog)
反问句:为什么$this
是未定义的,而$dog
是可访问的?
回答:,因为该作用域中的var
正在重新定义$this
;只是在该作用域中定义$this
之前,我正在尝试记录它。
如果我注释掉var $this = $(this);
,那么标记(#1)将返回:
BILLY! THIS: jQuery(Document index2.html) | DOG: jQuery(p#dog)
BILLY! THIS: jQuery(Document index2.html) | DOG: jQuery(p#dog)
同样的逻辑适用于标记(#2)、(#3)、(#4)、(#5)、(#6)、(#7)和(#8)。
基于这个观察(如果我错了请纠正我),我假设我可以把var $this = $(this);
放在函数的底部,并且当前作用域应该知道我想要使用当前作用域的$this
(即使它还没有定义),而不是父作用域的$this
(即使它的是定义的)。
避免$this
冲突的可能解决方案:
如果想要在其他闭包/函数/回调外部/内部缓存$(this)
并避免冲突,那么应该使用不同的变量标签,例如:
var $$ = $(this);
var $this2 = $(this);
var $t = $(this);
var $that = $(this);
问题:
上面的解决方案是如何避免$this
冲突的吗?如果没有,你最喜欢的技术是什么?
观察2:
标记(#9)
THIS: undefined | DOG: jQuery(p#dog)
...由于上述原因,$this
未定义,但是:
THIS: jQuery(div#foo) | DOG: jQuery(p#dog)
... $this
现在是$('#foo')
!
问题(S):
到底为什么会发生这种情况?
是因为$this
是通过标记(#10)重新定义的吗
(嗯,我觉得我需要用谷歌搜索“javascript中的垃圾收集”。)
同样,在编写复杂的jquery/javascript时,避免这种类型的变量冲突的最佳方法是什么?
我希望这些不是可怕的问题。提前感谢您抽出时间来帮助我。:)
发布于 2013-02-15 05:37:47
在内部作用域中重新声明var $this
时看到的行为称为hoisting。这就是为什么对于该作用域中所需的任何变量,在每个作用域的开头都应该始终只有一条var
语句的原因之一--这并不是说这是必要的,只是因为它做了相同的事情,并且变量名更容易定位。
至于必须在深度嵌套的作用域中使用变量..这可能是有问题的迹象(太多嵌套,单一责任,等等)。如果您需要大量使用某些构造,请考虑将它们添加到对象的作用域中,而不是为它们指定以2
结尾的名称。至少应该给它们起描述性的名称(我通常只在一个作用域中使用$this = $(this)
,这是为了避免重复调用$()
)。self
通常用于引用其自身作用域内的函数定义中的当前对象。
var Dog = function (boy, dog) {
this.boy = boy;
this.dog = dog;
this.$clickme = $("#clickme");
}
Dog.prototype.bind = function () {
var self = this;
self.$clickme.on('click', function() {
var $this = $(this);
console.log('THIS:', $this, ' | ', 'DOG:', self.dog);
$('#what').animate({
opacity : 0.25,
left : '+=50',
height : 'toggle'
}, 500, function() {
var $this = $(this);
console.log('CLICKME:', self.$clickme, ' | ', 'DOG:', self.dog);
});
});
}
发布于 2013-02-15 05:34:37
你实际上遇到了变量提升的问题:
billy = function() {
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog);
var $this = $(this);
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog);
};
在运行时实际上是这样解释的:
billy = function() {
var $this;
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog); // $this hasn't been set to anything yet...
$this = $(this);
console.log('BILLY!', 'THIS:', $this, ' | ', 'DOG:', $dog);
};
JavaScript将变量和函数声明提升到作用域块的顶部,以便您可以在手动声明它们之前引用它们。当人们从作用域块之外引用相同名称的变量时,这会给他们带来麻烦,正如您在示例中清楚地看到的那样。
发布于 2013-02-15 05:30:39
您已经体验到了scope和JavaScript带来的乐趣。很多人喜欢做的一件事是,如果您需要访问回调中的当前作用域,请将其定义为self,如下所示:
var $ = require('jquery')
, database = require('database')
$.on('click', function(action) {
var self = this;
database.connect(function() {
database.putSync(self.action.button);
});
});
请注意,当调用'connect‘时,"this“的作用域被重置为回调的作用域,而不是点击处理程序的作用域,这就是您将作用域存储在可访问变量中的原因。
https://stackoverflow.com/questions/14884342
复制相似问题