JavaScript でこれを理解する

怪我咯
怪我咯オリジナル
2017-04-05 13:55:241151ブラウズ

なぜこの記事を書いているのですか?

この質問は以前アリババや他の企業の面接で聞かれたことがあるので、皆さんにも共有したいと思います。以下の7つの状況の違いを明確に理解できれば、面接官にわかりやすく説明できます。この記事を理解すれば、面接官はどのように質問しても、間違いなく大きなプラスになります。

Javascript でこれについて話すのは実際には頭の痛い問題です。Java とは異なり、C++ の this は this を呼び出すオブジェクトを指します。

関数内の this の値は、その関数が実際に呼び出されて実行されるときに決定され、関数の定義時には決定できません。

this の値は実行コンテキストの一部であるため、関数が呼び出されるたびに、新しい実行コンテキストが生成されます。コードで this を使用すると、this の値はスコープ チェーン内で検索せずに、実行コンテキストから直接取得されます。

this の値については、以下の 7 つの状況に大別できます。

ケース 1: グローバル & 通常の関数を呼び出す

グローバル環境では、これは常に window を指します。

console.log(this === window);     //true

通常の関数が呼び出されるとき (これはコンストラクターではないことに注意してください。新しい関数は前に追加されません)、これもウィンドウを指します。

var x = 10;
function foo(){
    console.log(this);     //Window
    console.log(this.x);   //10
}
foo();

ケース 2: コンストラクター

いわゆるコンストラクターは、関数 new から派生したオブジェクトです。通常、コンストラクターの関数名の最初の文字は大文字になります。たとえば、Object、Function、Array はすべてコンストラクターです。 。

function Foo(){
    this.x = 10;
    console.log(this);    //Foo {x:10}
}
var foo = new Foo();
console.log(foo.x);      //10

上記のコードでは、関数がコンストラクターとして使用されている場合、その関数内の this は、新しく作成しようとしているオブジェクトを表します。

ただし、 new Foo() の代わりに Foo 関数を直接呼び出すと、ケース 1 になり、Foo() は通常の関数になります。

function Foo(){
    this.x = 10;
    console.log(this);    //Window
}
var foo = Foo();
console.log(foo.x);      //undefined

ケース 3: オブジェクト メソッド

関数がオブジェクトのメソッドとして使用される場合、メソッド内の this はオブジェクトを指します。

var obj = {
    x: 10,
    foo: function () {
        console.log(this);        //Object
        console.log(this.x);      //10
    }
};
obj.foo();

注: 関数がオブジェクト メソッドで定義されている場合は、状況が異なります。

var obj = {
    x: 10,
    foo: function () {
        function f(){
            console.log(this);      //Window
            console.log(this.x);    //undefined
        }
        f();
    }
}
obj.foo();

これは次のように理解できます。関数 f は obj.foo 内で定義されていますが、依然として通常の関数に属しており、これは依然として window を指しています。 (これは落とし穴です、覚えておいてください)

ここで、上位スコープで変数 obj.x を呼び出したい場合は、self を使用して外部の this 変数をキャッシュすることができます。

var obj = {
    x: 10,
    foo: function () {
        var self = this;
        function f(){
            console.log(self);      //{x: 10}
            console.log(self.x);    //10
        }
        f();
    }
}
obj.foo();

foo 関数がオブジェクト メソッドとして呼び出されない場合:

var obj = {
    x: 10,
    foo: function () {
        console.log(this);       //Window
        console.log(this.x);     //undefined
    }
};
var fn = obj.foo;
fn();

obj.foo はグローバル変数に割り当てられ、obj のプロパティとして呼び出されない場合、この値は window になります。

ケース 4: コンストラクター プロトタイプ属性

function Foo(){
    this.x = 10;
}
Foo.prototype.getX = function () {
    console.log(this);        //Foo {x: 10, getX: function}
    console.log(this.x);      //10
}
var foo = new Foo();
foo.getX();

Foo.prototype.getX 関数では、これは foo オブジェクトを指します。それだけでなく、プロトタイプチェーン全体においても、これは現在のオブジェクトの値を表します。

ケース 5: 関数は、call、apply、bind を使用して呼び出されます。

var obj = {
    x: 10
}
function foo(){
    console.log(this);     //{x: 10}
    console.log(this.x);   //10
}
foo.call(obj);
foo.apply(obj);
foo.bind(obj)();

call、apply、またはbindによって関数が呼び出された場合、thisの値は渡されたオブジェクトの値になります。

ケース 6: DOM イベント this

HTML DOM イベント ハンドラーでは、this は常にこのハンドラーにバインドされている HTML DOM ノードを指します:

function Listener(){   
    document.getElementById('foo').addEventListener('click', this.handleClick);     //这里的 this 指向 Listener 这个对象。不是强调的是这里的 this
}
Listener.prototype.handleClick = function (event) {
    console.log(this);    //<p id="foo"></p>
}
var listener = new Listener();
document.getElementById(&#39;foo&#39;).click();

これは理解するのが簡単で、関数にパラメーターを渡すのと同等です。 handleClick の実行時コンテキストが変更されます。これは次のコードと同等です:

var obj = {
    x: 10,
    fn: function() {
        console.log(this);         //Window
        console.log(this.x);       //undefined
    }
};
function foo(fn) {
    fn();
} 
foo(obj.fn);

バインドを通じてコン​​テキストを切り替えることもできます:

function  Listener(){
    document.getElementById(&#39;foo&#39;).addEventListener(&#39;click&#39;,this.handleClick.bind(this));      
}
Listener.prototype.handleClick = function (event) {
    console.log(this);    //Listener {}
}
var listener = new Listener();
document.getElementById(&#39;foo&#39;).click();

最初の 6 つの状況は 1 つの文にまとめられています: これはメソッドを呼び出すオブジェクトを指します。

ケース 7: アロー関数内の this

アロー関数を使用する場合、状況は異なります。アロー関数内の this は、コンテキストによって決定される字句スコープです。

var obj = {
    x: 10,
    foo: function() {
        var fn = () => {
            return () => {
                return () => {
                    console.log(this);      //Object {x: 10}
                    console.log(this.x);    //10
                }
            }
        }
        fn()()();
    }
}
obj.foo();

さて、アロー関数は this のポインティングを完全に修正し、これは常に外部呼び出し元 obj である字句スコープを指します。

アロー関数を使用する場合、以前のハック記述方法:

var self = this;

は必要なくなります。

var obj = {
    x: 10,
    foo: function() {
        var fn = () => {
            return () => {
                return () => {
                    console.log(this);    // Object {x: 10}
                    console.log(this.x);  //10
                }
            }
        }
        fn.bind({x: 14})()()();
        fn.call({x: 14})()();
    }
}
obj.foo();

これはアロー関数の字句スコープに従ってバインドされているため、call() または apply() でアロー関数を呼び出す場合、これはバインドできません。つまり、渡された最初のパラメータは無視されます。

補足:

  • これは予約語であり、書き換えることはできません。

function test(){
    var this = {};     //Uncaught SyntaxError: Unexpected token this
}
  • ホストオブジェクト:

  1. 言語を実行する場合、ホスト環境と呼ばれる環境が必要です。

  2. JavaScript の場合、最も一般的なホスト環境は Web ブラウザです。この環境では、JavaScript エンジンがホスト環境に接続できるように、いくつかのインターフェイスが提供される必要があります。

  3. JavaScript エンジンは、JavaScript コードが実際に実行される場所です。一般的なエンジンには、V8 (Google が開発した現在最速の JavaScript エンジン) と JavaScript コアが含まれます。

  4. ブラウザとサーバー (nodejs) の両方に独自の JS エンジンがあります。ブラウザでは、グローバル オブジェクトは window であり、nodejs では、グローバル オブジェクトはグローバルです。


以上がJavaScript でこれを理解するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。