1

しばらく JS でコーディングした後、独自のフレームワークを作成することにしました。jQueryに似たもの。しかし、非常に簡素化されたバージョンです。いくつかのグーグルの後、私はこのコードをまとめました:

function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

$elect.prototype = {
    hide:   function () { this.elm.style.display = 'none';  },
    show:   function () { this.elm.style.display = '';      },
    toggle: function ()
            {
                if (this.elm.style.display !== 'none') {
                    this.elm.style.display = 'none';
                } else {
                    this.elm.style.display = '';
                }
            }
};

これまでのところ、これは機能しているようです。しかし、私は機能に興味がありません。論理を理解したい。メソッドの部分を追加することは理解できます。の機能を理解していませんでしたが、

    if (window === this) {
        return new $elect(id);
    }

外すと機能が壊れます。これは if ステートメントなので、2 つの結果があります。Trueまたはfalse。そのため、 if ステートメントを削除して、 return を想定して使用しようとしましたが、うまくいきませreturn new $elect(id);んでした。すると が返ってくるのではないかと思ったので、if文を丸ごと削除しました。それもうまくいきませんでした。誰かが私を啓発できますか?また、このコードは有効ですか? 私はおそらくいくつかのものが欠けています。window === thistruefalse

jsfiddle でテストしたところ、動作しません。jsbin oOで動作しますが

jsfiddle jsbin

編集:$elect(id).toggle();それを呼び出すために使用します。デモを確認することはできますが。

4

6 に答える 6

1

その条件がどのように機能するかを理解するには、まず、グローバル スコープでがオブジェクトthisを参照していることを知っておく必要がありwindowます。オブジェクト内などのローカル スコープではthis、オブジェクト自体を参照します。

関数$electは、フレームワークのコンストラクターです。直接呼び出す場合は、次のようにします。

$elect('some-id-blah')

最初にインスタンスを作成しようとしていることを認識し (条件window === thisが true と評価されるため)、それ自体の新しいインスタンスを再帰的に作成します。それが完了するとthis、オブジェクトを参照しなくなりwindow、ライブラリの新しいインスタンスを参照するため、条件は満たされません。

それが少し理解できることを願っています。

于 2013-09-18T16:24:11.110 に答える
1

論理を理解したい。

$electは、キーワード( )で呼び出されることになっているコンストラクター関数です。( ) でない場合はどうなりますか? 構築されたインスタンスはなく、キーワードはグローバル オブジェクト ( ) を指しますが、これは望ましくありません。したがって、このスニペットは、それ自体を正しく呼び出してそれを返すことを検出した場合のガードです。newnew $select$elect()thiswindownew

外すと機能が壊れる

$elect(id)ガードなしのように呼び出すと、elmプロパティがグローバル オブジェクト (本質的にはグローバル変数) に追加され、何も返されません。.toggle()そのメソッドを呼び出そうとすると、例外が発生しますundefined has no method 'toggle'

window === thistrue を返すと仮定して、if ステートメントを削除しようとしました

さて、呼び出したときにスタック オーバーフロー例外を引き起こす無限再帰関数を作成しました。


ところで、-less の呼び出しを防ぐ適切な方法newは、比較するのではなくwindow(ブラウザー以外の環境ではグローバル オブジェクトの名前が異なる場合があります)、他のすべてが正常であると想定し、正しい継承を確認することです。コンストラクターを「クラス」のインスタンス、つまり から継承するオブジェクトにのみ適用する必要があります$elect.prototypenewこれは、たとえばで呼び出されたときに保証されます。そのチェックを行うには、次のinstanceof演算子を使用します。

function $elect(id) {
    if (! (this instanceof $elect)) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

これにより、ガードの意図も明確になります。

于 2013-09-18T16:18:36.333 に答える
0

あなたの関数はコンストラクタです。デフォルトでは、メソッドとして他のオブジェクトでthis明示的に呼び出されていない in any 関数 ( $elect()、 not foo.$elect()) には、グローバル オブジェクト ( window) inが渡されthisます。ただし、が実際にオブジェクトを参照している場合は、が実行されることをif確認します。は次のことを行います。thiswindowreturn new $elect(id);new $elect(id)

  • の新しいインスタンスを作成します$elect.prototype
  • 新しく作成したインスタンスを に入れ、thisメソッドを再度呼び出します。

2 番目のパスで、 は にthis === window評価されfalseます。

于 2013-09-18T16:21:49.390 に答える
0

最初に理解しておくべきことは、この関数が自分自身を呼び出しているということです。

function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

関数ウィンドウを初めて呼び出すと、=== this になります。関数をメソッドとして呼び出しているからです。メソッドとして呼び出されると、関数は関数/メソッドが含まれるオブジェクトにバインドされます。この例でthisは、グローバル スコープであるウィンドウにバインドされます。

ただし、newキーワードを使用すると、関数をコンストラクターとして呼び出します。コンストラクターとして呼び出されると、新しいオブジェクトが作成され、thisそのオブジェクトにバインドされるため、2 回目this以降は参照されなくなりますwindow

$elect の新しいインスタンスを使用して、ローカル変数 elm をインスタンスに正しく設定し、他の関数が後でその elm を呼び出せるようにします。

于 2013-09-18T16:21:16.597 に答える
0

次のように呼び出す場合:

$elect("theId").hide();

その中で初めて関数として呼び出され、これを見つけwindow === thisて実行します:

return new $elect("theId")

新しいものを作成し、関数を再度呼び出します。(関数の 2 回目の呼び出しが返すものは何でも返されます。)

2回目はコンストラクタとして呼び出されるwindow !== thisため、要素を見つけて内部に保存するために渡されます。

関数自体から何も返さないコンストラクター呼び出しは、作成されたインスタンスを返します。

そうすれば、パーツは(最初に作成されたインスタンス).hide()の適切な値で実行されます。thisそして、要素が画面から消えます。

次のように呼び出す場合は注意してください。

var bob = {};
bob.$select("theId").hide();

thisget および 'elm' プロパティが設定されており、種類のオブジェクトでbobはないために呼び出される 'hide' プロパティがないため、機能しません。$elect

ノート

他の関数の他のすべてのメソッドが返さthisれる場合は、それらを連鎖させることができます。

$elect('theId').show().red();

要素を赤く着色する関数を追加したと仮定します。

于 2013-09-18T16:36:38.727 に答える
0

このロジック:

if (window === this) {
    return new $elect(id);
}

コンストラクター関数が関数として呼び出される場合、次のことを保証します。

var foo = $elect(id);

コンストラクタとしてではなく:

var fo = new $elect(id);

正しい結果、つまり新しい $elect オブジェクトが返されます。関数として呼び出された場合、デフォルトのコンテキストはグローバル コンテキストになりますwindow。ブラウザで実行されている場合は、句がトリガーifされ、コンストラクタとして呼び出した結果が返されます。


フィドルで機能しない理由

リンクされたフィドルでは、コードをonloadハンドラーにラップするように設定されています。その結果は次のようになります。

window.onload=function(){
function $elect(id) {
    if (window === this) {
        return new $elect(id);
    }
    this.elm = document.getElementById(id);
}

$elect.prototype = {
    hide:   function () { this.elm.style.display = 'none';  },
    show:   function () { this.elm.style.display = '';      },
    toggle: function ()
            {
                if (this.elm.style.display !== 'none') {
                    this.elm.style.display = 'none';
                } else {
                    this.elm.style.display = '';
                }
            }
};
}

そのため、$elect変数はonloadハンドラのスコープの外では見えません。

一般に、グローバル スコープに 1 つの変数を追加して、フレームワークへのアクセスを有効にします。上記のコードの最後に次のようなものを追加すると、コードが表示されます。

 window.$elect = $elect;

Demo Fiddle

于 2013-09-18T16:18:26.230 に答える