代码之家  ›  专栏  ›  技术社区  ›  Peter Boughton

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

  •  13
  • Peter Boughton  · 技术社区  · 15 年前

    我相信有一个简单的答案,但现在是星期五下午,我累了。:(

    不知道该如何解释,所以我将继续并发布示例代码…


    下面是一个简单的对象:

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

    它的用途是:

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

    除了最后一行,一切都正常。当jquery调用dosomething方法时,它将重写“this”并停止它的工作。

    尝试使用 Stuff 也不起作用。

    那么,如何以允许jquery调用对象的方式引用对象自己的属性,以及允许对象使用调用的jquery对象?

    也就是说,我希望能够这样做:

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

    (在哪里) <CurrentObject> <CallerElement> 替换为适当的名称。)

    4 回复  |  直到 14 年前
        1
  •  5
  •   Gabe Moothart    15 年前

    的身份 this 是JavaScript中的常见问题。如果你试图创建一个 doSomething :

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

    不依赖于 . 你可以用各种方法来做到这一点,但最简单的方法是明确地引用 Bob 而不是 里面 剂量测定法 . 另一种方法是使用构造函数函数(但随后会丢失酷对象的文本语法):

    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();
    
        2
  •  24
  •   bobince    15 年前

    这不是jquery的错误,它是javascript处理对象方式的一个组成部分。

    与大多数其他面向对象语言不同,此是 在javascript中绑定到每个方法级别;相反,它完全取决于如何调用函数:

    Bob= {
        toString: function() { return 'Bob!'; },
    
        foo: function() { alert(this); }
    };
    Brian= {
        toString: function() { return 'Brian!'; },
    };
    
    Bob.foo(); // Bob!
    Bob['foo'](); // Bob!
    
    Brian.foo= Bob.foo;
    Brian.foo(); // Brian! NOT Bob
    
    var fn= Bob.foo;
    fn(); // window NOT Bob
    

    您在以下情况下所做的工作:

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

    就像最后一个例子 fn :您正在拉功能 doSomething 关闭bob并将其作为纯函数传递给jquery的事件处理程序setter:它不再与bob或任何其他对象有任何连接,因此javascript在全局中传递 window 对象。(这是JavaScript最糟糕的设计特性之一,因为您可能不会立即注意到 窗口 不是 Bob ,并开始访问它的属性,导致奇怪和混乱的交互和错误。)

    要记住Bob,通常需要像nickyt的答案那样创建一个函数,在一个闭包中保存一个__Bob_的副本,以便在回调时记住它,并用于调用real方法。然而,在ECMAScript第五版中,现在有了一种标准化的方法:

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

    (您也可以在 bind 呼叫呼叫 剂量测定法 回到他们身边,这很方便。)

    对于本机还不支持第五版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))
                );
            };
        };
    }
    
        3
  •  8
  •   nickytonline    14 年前

    变化

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

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

    您还可以在Bob对象中添加一个私有字段 var that = this 在成员中使用它,而不是 this 如果你真的想避免匿名函数。

    例如

    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 );
            }
    }
    
        4
  •  0
  •   gnarf    14 年前

    你可以尝试这样做:

    $j('#MyButton').click(function(event) {
      Bob.doSomething(event, this);
    });
    

    现在 doSomething 仍将拥有 Bob 为其 this ,并使用函数参数,它将具有 event 对象及其触发的元素。