web-dev-qa-db-ja.com

基本的なオブジェクト/関数チェーンはjavascriptでどのように機能しますか?

私は、jQueryスタイルの関数チェーンを頭の中でまっすぐに行うという原則を理解しようとしています。これはつまり:

var e = f1('test').f2().f3();

私は1つの例が機能するようになりましたが、別の例は機能しません。以下に投稿します。私は常に、何かがどのように機能するかについての第一原理の基礎を学び、その上に構築できるようにしたいと思っています。これまで、チェーンがどのように機能するかについては大雑把で大まかな理解しかなく、インテリジェントにトラブルシューティングできないバグに遭遇しています。

私が知っていること:

  1. 関数は自分自身を返す必要があります。別名「これを返す」です。
  2. 連鎖可能な関数は、親関数、別名jQueryに存在する必要があります。css()はjQuery()のサブメソッドであるため、jQuery()。css();
  3. 親関数は、それ自体またはそれ自体の新しいインスタンスを返す必要があります。

この例は機能しました:

var one = function(num){
    this.oldnum = num;

    this.add = function(){
        this.oldnum++;
        return this;
    }

    if(this instanceof one){
        return this.one;    
    }else{
        return new one(num);    
    }
}
var test = one(1).add().add();

しかし、これはそうではありません:

var gmap = function(){

    this.add = function(){
        alert('add');

        return this;    
    }   

    if(this instanceof gmap) {
        return this.gmap;   
    } else{
        return new gmap();  
    }

}
var test = gmap.add();
24
Geuis

JavaScriptでは、関数はファーストクラスのオブジェクトです。関数を定義するとき、それはその関数オブジェクトのコンストラクターです。言い換えると:

var gmap = function() {
    this.add = function() {
        alert('add');
    return this;
    }

    this.del = function() {
       alert('delete');
       return this;
    }

    if (this instanceof gmap) {
        return this.gmap;
    } else {
        return new gmap();
    }
}
var test = new gmap();
test.add().del();

を割り当てることによって

新しいgmap();

上記の例では、関数を別の関数またはオブジェクトでラップしない限り、「this」はウィンドウオブジェクトを指します。

連鎖は最初は理解しづらいですが、少なくとも私にとってはそうだったのですが、理解してみると、ツールの威力を実感しました。

36
Lark

悲しいことに、直接の答えは「いいえ」でなければなりません。既存のメソッドをオーバーライドできる場合でも(おそらく多くのUAで可能ですが、IEではできないと思われます)、厄介な名前変更に悩まされることになります。

HTMLElement.prototype.setAttribute = function(attr) { 
    HTMLElement.prototype.setAttribute(attr) //uh-oh;  
}

おそらく回避できる最善の方法は、別の名前を使用することです。

HTMLElement.prototype.setAttr = function(attr) {
    HTMLElement.prototype.setAttribute(attr);
    return this;
}
4
kojiro

関数を「書き換え」ても元のバージョンを使用できるようにするには、最初に元の関数を別の変数に割り当てる必要があります。サンプルオブジェクトを想定します。

function MyObject() { };

MyObject.prototype.func1 = function(a, b) { };

書き直すにはfunc1連鎖性のために、これを行います:

MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
    this.std_func1(a, b);
    return this;
};

これが 実例 です。連鎖性が必要だと思われるすべての標準オブジェクトにこの手法を採用する必要があります。

このすべての作業を行うときまでに、チェーン機能がすでに組み込まれているライブラリを使用するなど、実行しようとしていることを達成するためのより良い方法があることに気付くかもしれません。 *咳*jQuery*咳*

1
FishBasketGordo

まず、私が自分の言葉でこれを説明していることを述べさせてください。

メソッドチェーンは、別の関数/メソッドによって返されるオブジェクトのメソッドを呼び出すこととほぼ同じです。たとえば(jqueryを使用):

$('#demo');

このjquery関数は、jqueryオブジェクトを選択してIDデモのDOM要素を返します。要素がテキストノード(要素)の場合、返されたオブジェクトのメソッドをチェーンできます。例えば:

$('#demo').text('Some Text');

したがって、関数/メソッドがオブジェクトを返す限り、返されたオブジェクトのメソッドを元のステートメントにチェーンできます。

後者が機能しない理由については、キーワードthisがいつどこで使用されるかに注意してください。コンテキストの問題である可能性があります。 thisを呼び出すときは、thisがウィンドウオブジェクト/グローバルスコープではなく、その関数オブジェクト自体を参照していることを確認してください。

お役に立てば幸いです。

0
ryanwaite28