JS对象this.method()通过jQuery中断

15 浏览
0 Comments

JS对象this.method()通过jQuery中断

我确定对于这个问题有一个简单的答案,但是现在是星期五下午,我很累。\n不确定如何解释,所以我将直接发布示例代码...\n以下是一个简单的对象:\n

var Bob =
{ Stuff : ''
, init : function()
    {
        this.Stuff = arguments[0]
    }
, doSomething : function()
    {
        console.log( this.Stuff );
    }
}

\n这是它的使用方式:\n

$j = jQuery.noConflict();
$j(document).ready( init );
function init()
{
    Bob.init('hello');
    Bob.doSomething();
    $j('#MyButton').click( Bob.doSomething );
}

\n除了最后一行之外,一切正常。当jQuery调用doSomething方法时,它覆盖了\'this\'并阻止其工作。\n尝试仅使用Stuff也不起作用。\n那么,如何以一种允许jQuery调用它的方式引用对象的自有属性,并使对象能够与调用的jQuery对象一起工作?\n即,我希望能够像这样做一些事情:\n

doSomething : function()
    {
        console.log( .Stuff + $j().attr('id') );
    }

\n(其中将被替换为适当的名称。)

0
0 Comments

在JavaScript中,this的身份是一个常见的问题。如果你尝试创建一个指向doSomething的快捷方式,它也会出现错误:

var do = Bob.doSomething;
do(); // this is no longer pointing to Bob!

不依赖于this的身份是一个好的实践。你可以通过多种方式来实现,但最简单的方法是在doSomething内部显式地引用Bob,而不是this。另一种方法是使用构造函数(但这样你就失去了酷炫的对象字面量语法):

var createBob = function() {
    var that = {};
    that.Stuff = '';
    that.init = function() {
        that.Stuff = arguments[0];
    };
   that.doSomething = function() {
       console.log( that.Stuff );
   };
   return that;   
}
var bob = createBob();

这似乎是最好的折中方案(尽管我的真实对象的名称要长得多,不幸的是)。鉴于我实际上是在'断开'从Bob到doSomething的连接,那么在doSomething内部引用Bob是否会有其他潜在的副作用呢?

在正常的使用中,不应该有副作用。你可能能够想出一个复杂的情况,其中你将Bob.doSomething赋值给一个变量,然后更改Bob的值,从而破坏你的doSomething快捷方式。然而,在实践中很少会遇到这种情况。我还增加了一个更封装的建议。

0
0 Comments

问题出现的原因是使用jQuery的click事件绑定方法时,使用了`this.method()`的语法,导致`this`指向了不正确的对象。解决方法是改用匿名函数来调用`Bob.doSomething()`,或者在Bob对象中添加一个私有字段`that`来代替`this`的使用。

具体解决方法如下:

$('#MyButton').click(function() {
    Bob.doSomething();
});

或者在Bob对象中添加私有字段`that`:

var Bob = new function() {
    // Private Fields
    var that = this;
    // Public Members   
    this.Stuff = '';
    this.init = function() {
        that.Stuff = arguments[0];
    }
    this.doSomething = function() {
        console.log(that.Stuff);
    }
}

这样做的原因是,jQuery在执行回调函数时会将`this`绑定为触发事件的元素,因此它试图执行`someElement.doSomething()`。但是这样做很丑陋,而且如果想访问调用对象的jQuery对象,就无法实现了。

对于问题的进一步澄清,使用上述方法将阻止`doSomething`方法了解到是`#MyButton`调用了它,这并不是本意。尝试在匿名函数中传递`arguments`会导致嵌套的参数,这是不可取的。因此,希望能有更好的解决方案。

0
0 Comments

JS Object this.method() breaks via jQuery是一个关于JavaScript对象和jQuery之间交互的问题。出现这个问题的原因是JavaScript中的this关键字的特性。与其他大多数面向对象语言不同,JavaScript中的this关键字并不是在每个方法级别上绑定的,而是纯粹由函数的调用方式决定。

在给定的例子中,当我们执行Bob.foo()时,this指向了Bob对象。但是当我们执行Brian.foo()时,this指向了全局的window对象,而不是Bob对象。这是因为在调用Bob.foo()时,this是由Bob对象调用的,但在调用Brian.foo()时,this是由Brian对象调用的(Brian对象是Bob对象的一个副本,但它并不具有Bob对象的方法)。

在使用jQuery的事件处理器时,如果我们像下面这样传递一个函数给click()方法:

$j('#MyButton').click( Bob.doSomething );

此时的doSomething函数已经与Bob对象断开了联系,它被作为一个纯函数传递给了jQuery的事件处理器。因此,JavaScript将全局的window对象作为this传递给了doSomething函数,而不是Bob对象。这就会导致在函数内部访问window对象的属性,从而引发一些奇怪和混乱的错误。

为了解决这个问题,我们可以使用闭包来保存Bob对象的副本,以便在回调时记住它并用于调用真正的方法。在ECMAScript第五版中,引入了一个标准的方法来实现这个目的:

$j('#MyButton').click( Bob.doSomething.bind(Bob) );

通过调用bind()方法,我们将Bob对象绑定到doSomething方法,这样在回调时就可以正确地访问Bob对象。

对于那些尚未原生支持bind()方法的浏览器(目前大多数浏览器都不支持),可以使用自己实现的bind()方法。例如,Prototype库提供了自己的实现。下面是一个简单的bind()方法的实现示例:

if (!Object.bind) {

Function.prototype.bind= function(owner) {

var that= this;

var args= Array.prototype.slice.call(arguments, 1);

return function() {

return that.apply(owner,

args.length===0? arguments : arguments.length===0? args :

args.concat(Array.prototype.slice.call(arguments, 0))

);

};

};

}

总结起来,避免使用this关键字是一个简单的解决方法,但在某些情况下可能并不容易实现。因此,使用bind()方法是一种更为通用和标准的解决方案,可以确保在不同的浏览器环境下都能正常工作。

0