1. ホーム
  2. ジャバスクリプト

[解決済み】関数内で "this "キーワードはどのように機能するのでしょうか?

2022-04-01 08:24:14

質問

JavaScriptで面白い場面に出くわしました。 オブジェクトリテラル記法でいくつかのオブジェクトを定義するメソッドを持つクラスがあります。 それらのオブジェクトの内部では this ポインタが使用されています。 プログラムの動作から推論すると this ポインターは、メソッドが呼び出されたクラスを参照しており、リテラルによって作成されるオブジェクトを参照しているわけではありません。

これは、私が期待する動作ではありますが、恣意的に思えます。 これは定義された動作なのでしょうか? クロスブラウザでも大丈夫なのでしょうか? なぜこのような動作になるのか、仕様に書かれている以上の理由があるのでしょうか?(たとえば、より広範な設計上の決定や哲学の結果なのでしょうか?) パースされたコードの例。

// inside class definition, itself an object literal, we have this function:
onRender: function() {

    this.menuItems = this.menuItems.concat([
        {
            text: 'Group by Module',
            rptletdiv: this
        },
        {
            text: 'Group by Status',
            rptletdiv: this
        }]);
    // etc
}

解決方法は?

私の別の記事からの共食いですが、ここにあなたが今まで知りたかった以上のことがあります。 これ .

始める前に、Javascriptについて覚えておくべき、そして意味がわからないときに自分に言い聞かせるべき、最も重要なことを説明します。 Javascriptにはクラスがありません(ES6 class 構文糖 ). もし何かがクラスのように見えたら、それは巧妙なトリックです。Javascriptには オブジェクト 機能 . (100%正確ではありません。関数は単なるオブジェクトですが、別物として考えることが役に立つこともあります)

その これ 変数は関数に付属しています。 関数を呼び出すと必ず これ は、関数を呼び出す方法に応じて、ある特定の値が与えられます。 これを呼び出しパターンと呼ぶことが多い。

javascriptで関数を呼び出すには、4つの方法があります。 関数を呼び出すには メソッド として、または 関数 として コンストラクタ で、そして 適用 .

メソッドとして

メソッドは、オブジェクトに付属する関数です。

var foo = {};
foo.someMethod = function(){
    alert(this);
}

メソッドとして呼び出された場合。 これ は、その関数/メソッドが属するオブジェクトに束縛されます。 この例では、fooにバインドされます。

関数として

単体で機能を持つ場合は これ 変数はグローバルオブジェクトにバインドされ、ほとんどの場合、そのグローバルオブジェクトは ウィンドウ オブジェクトを使用します。

 var foo = function(){
    alert(this);
 }
 foo();

これは、あなたがつまづいている原因かもしれません。 しかし、悪く思わないでください。 多くの人が、これは設計上の悪い判断だと考えています。 コールバックはメソッドとしてではなく関数として呼び出されるため、一貫性のない動作に見えるのはそのためです。

多くの人がこの問題を回避するために、えーと、こんなことをやっています。

var foo = {};
foo.someMethod = function (){
    var that=this;
    function bar(){
        alert(that);
    }
}

変数を定義します。 その を指し示す。 これ . クロージャは(それ自体がトピックである)、次のように保持します。 その そのため、コールバックとしてbarを呼び出すと、まだ参照が残っています。

use strict モードとなります。 this はグローバルに束縛されない。(それは undefined ).

コンストラクタとして

また、コンストラクタとして関数を呼び出すこともできます。 使用している命名規則 (TestObject) に基づいて、これもまた あなたがやっていることが、あなたをつまずかせる原因かもしれません。 .

コンストラクタとして関数を呼び出すには、new キーワードを使用します。

function Foo(){
    this.confusing = 'hell yeah';
}
var myObject = new Foo();

コンストラクタとして呼び出されると、新しい Object が作成されます。 これ はそのオブジェクトにバインドされます。 繰り返しますが、インナー関数があり、それがコールバックとして使われている場合、関数として呼び出すことになります。 これ はグローバルオブジェクトにバインドされます。 var that = this のトリック/パターンを使ってください。

コンストラクタ/new キーワードは、Java/伝統的な OOP プログラマがクラスに似たものを作成する方法として投げられた骨だと考える人もいます。

Applyメソッドで

最後に、すべての関数には "apply" という名前のメソッドがあります(そう、関数はJavascriptのオブジェクトなのです)。 Applyを使うと これ になります。また、引数の配列を渡すこともできます。 以下は役に立たない例です。

function foo(a,b){
    alert(a);
    alert(b);
    alert(this);
}
var args = ['ah','be'];
foo.apply('omg',args);