13

これには簡単な答えがあると思いますが、金曜日の午後で、疲れています。:(

説明の仕方がわからないので、先に進んでサンプルコードを投稿します...


以下は単純なオブジェクトです。

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

4 に答える 4

24

これは jQuery のせいではなく、JavaScript がオブジェクトを処理する方法に不可欠です。

他のほとんどのオブジェクト指向言語とは異なり、JavaScript では「this」はメソッドごとのレベルでバインドされていません。代わりに、関数がどのように呼び出されるかによって純粋に決定されます。

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です: Bob から関数を引き出し、doSomethingそれを純粋な関数として jQuery のイベント ハンドラー セッターに渡します: Bob やその他のオブジェクトへの接続がなくなるため、JavaScript はwindow代わりにグローバル オブジェクトを渡します。(これは JavaScript の最悪の設計機能の 1 つです。そうではないことにすぐに気付かwindowBob、プロパティへのアクセスを開始すると、奇妙で​​紛らわしい相互作用やエラーが発生する可能性があります。)

ボブを思い出すには、通常、ニッキーの答えのように関数を作成し、「ボブ」のコピーをクロージャーに保持して、コールバック時に記憶し、実際のメソッドを呼び出すために使用できるようにします。ただし、ECMAScript 第 5 版では、標準化された方法でこれを行うことができます。

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

(呼び出しに追加の引数を入れて、それらを使用しbindてコールdoSomethingバックすることもできます。これは便利です。)

第 5 版の bind() メソッドをネイティブでまだサポートしていないブラウザー (この時点では、ほとんどのブラウザーがそうです) の場合bind、次のような独自の実装をハックできます (Prototype ライブラリーもこれを行います)。

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))
            );
        };
    };
}
于 2009-10-09T16:45:56.060 に答える
8

変化する

$('#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 );
        }
}
于 2009-10-09T16:16:33.697 に答える
5

の同一性thisは、javascript でよくある問題です。へのショートカットを作成しようとすると、それも壊れますdoSomething:

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

の ID に依存しないことをお勧めしthisます。Bobさまざまな方法でこれを行うことができますが、最も簡単な方法は、の代わりに明示的に参照することthisですdoSomething。もう 1 つは、コンストラクター関数を使用することです (ただし、クールなオブジェクト リテラル構文が失われます)。

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();
于 2009-10-09T16:50:57.250 に答える
0

いつでも次のようなことを試すことができます。

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

doSomethingでも がBobありthis、関数の引数を使用すると、eventオブジェクトと、トリガーされた要素があります。

于 2010-04-22T14:54:01.167 に答える