7

剣道の控えめな JavaScript スタイルのイベント呼び出しがthis、私のメソッド コンテキストで壊れているようです。

Fooとしてインスタンス化されたオブジェクトがあるとしますbar = new Foo()

function Foo(){};

Foo.prototype.name = "Herring";
Foo.prototype.doSomething = function(e) {
   alert(this.name);
};

bar = new Foo();

たとえば、データクリックを使用してイベントを添付します

<a data-role="button" data-click="bar.doSomething">Click Me</a>

オブジェクト コンテキスト tobarは置き換えられます (便利elementなコンテナーがあるため、理由はわかりません) this.name。未定義です。

オブジェクトコンストラクターで古いものを試しましたが、うまくいきませんvar self = this;。これを解決する最善の方法を知っている人はいますか?

更新:ハッキーな回避策

モジュールをクラスとしてラップする利点を失いたくないので、適切なオブジェクトのメソッドを呼び出すイベント呼び出し関数ラッパーを作成しました。

たとえば、マークアップをラッパー関数に接続します。

<a data-role="button" data-click="doSomething">Click Me</a>

ラッパー関数は object.method を呼び出すだけです。

function doSomething(e){ bar.doSomething(e) };  

これで意図した結果が得られますが、非常に恐ろしいことです。マークアップから呼び出されるすべてのイベントには、上記のようなプロキシ関数が必要です。300 のイベントがあるシナリオを想像してみてください...そして、これが恐ろしい理由がすぐにわかります。

他に解決策がない場合は、それがあることを心から願っています。この回避策を回答として投稿しますが、私に関する限り、望ましいとは言えません。

脚注

正直なところ、マークアップからイベントを呼び出すこの方法は「剣道のやり方」であるため、これは剣道の主要なアーキテクチャ上の欠陥のように思えます。おそらくかなりの量のコードthisが html 要素への参照として既に処理されているため、パッチを適用することはできません。

それをオーバーライドできること、またはこれらのイベント呼び出しを呼び出しを渡すことができる汎用ハンドラー (本質的には汎用プロキシ関数) を介してルーティングできることが、これに対処できる可能性のある方法です。オブジェクトの単純な構成可能な値にすることもできkendo.ます。

理論解

これが機能する場合は、フォローアップを投稿します。理論的には、汎用プロキシでイベントをスローし、適切にスコープされた関数を呼び出すことができます。

イベント属性を使用してプロキシを呼び出し、オブジェクト/メソッド呼び出しを伝達する別の属性を作成するとします。例えば。

<a data-role="button" data-click="prox" data-prox="o.eventHandler">Click Me</a>

プロキシ関数はprox、属性データセットからプルします。

メソッド - eval の使用

私が悪いからではありませんが、必要があります。

// sitting in global namespace 
function prox(e){
    var p = e.sender.element.data['prox'];
    // make sure our delegate is a function.
    if("function" == eval("typeof "+p)) { 
        eval(p + "(e)");
    }
}

明らかに、これを行うためのより良い方法が必要ですが、少なくとも DRY です。

(すぐに非評価メソッドをクックします...)

評価を開始...

オブジェクト/メソッドを見つけるためにウィンドウコンテキストを使用しましょう。

function prox(e) {
   var p = e.sender.element.data['prox'];
   if(p.indexOf(".") == -1){
      // global function : where *this* is window.
      // check you've got the function if not ditch it.
      if("function" == typeof window[p]) window[p](e);
   } else {
      // object/method (one level deep only.)
      var s = p.split(".");
      var o = s[0], m = s[1];
      // check the object/method is a function before executing it.
      if("function" == typeof window[o][p]) window[o][p](e);
   }
}

もちろん、グローバル(ウィンドウ)スコープの関数の場合、これは要素としておそらくより便利ですが、その場合、選択肢があります。

4

4 に答える 4

0

使用中のバージョン。

// dynamic proxy for retaining object context on methods called by
// data- attributes in Kendo.
// 
// e.g.
//
//     data-click="o.method" 
//
// Would lose context with `o` - context would be set in the same
// way as JQuery handlers, which is an inconvenience.
// 
// Alternatively we use the prox method
//
//     data-click="prox"
// 
// We'd then set `data-prox` on the same element, to the
// object.method pair.
//
//     data-prox="o.method"
//
// This is read by prox, transformed into a method call, type
// checked and executed if it's a valid method.
//
// A `data-prox` value in any form other than `object.method` will
// be ignored, for example, `object.child.method` will fail. If
// you're doing that sort of thing, feel free to hack it.
// 
// There's a backup eval() to locate the object if window doesn't
// own it. It should be possible to remove it under most
// circumstances, it's here for compatability with
// JSFiddle. (JSBin works without it.)
function prox(e) {
    var p = this.element.data().prox;
    if(p.indexOf(".") > -1){
        var s = p.split("."); if(s.length > 2) return; 
        var o = s[0], m = s[1];
        if("object" == typeof window[o]) {
            o = window[o];
        } 
        if("function" == typeof o[m]) o[m](e);
        // comment this out in production:
        l( "prox called " + s[0] + "::" + s[1] );
    }
}

function l(s) { console.log(s); }

警告

同じ要素に複数のハンドラーがある場合、prox()たとえば、、などがある場合は区別できず、失敗します。data-initdata-showprox

特にこれが私にとって一般的なユースケースになる場合は、おそらくこれを更新します。

于 2012-12-31T09:11:35.667 に答える
0

jQuery プロキシ ( http://api.jquery.com/jQuery.proxy/ ) を使用できます。

function Foo(){};

Foo.prototype.name = "Herring";
Foo.prototype.doSomething = function(e) {
   alert(this.name);
};

bar = new Foo();

$("btn").click($.proxy(bar.doSomething), bar);

または内部使用

$("btn").click($.proxy(this.doSomething), this);
于 2013-03-19T11:53:07.747 に答える
0

このように機能する非一般的な手法を使用して、一時的に3番目の方法を試しました。

擬似コード:

MyObject {

   method : function(e) {
      if (this instanceof MyObject) {
        // Do something with this
      } else {
        myInstance.method(e); // otherwise re-call the method to set this properly.
      }
   }
}
myInstance = new MyObject();

prox メソッドほど柔軟ではありませんが、私のユースケースには適しています。少なくとも、使用したいメソッドから離れた別の関数プロキシは必要ありません。事前に型チェックと再呼び出しを行うことで、これをより簡潔にすることができます。

例えば

MyObject = {
   method : function(e) {
      if (! this instanceof MyObject) myInstance.method(e); // re-call

      // Method body... 

   }
}
myInstance = new MyObject();

data-また、マークアップにカスタム属性が必要ないことも意味しました。

注:この方法は、複数のインスタンスを持つオブジェクトには問題がありますが、私が適用していたオブジェクトは単一のインスタンスでした。

インスタンス固有にする必要があるハンドラーがある場合 (これが私がこの質問を提起した主な理由です)、proxメソッドはこれよりもはるかに適しています

于 2013-01-05T08:38:26.393 に答える