javascript実行文脈と文脈this

18446 ワード

文脈thisは面接の頻度が非常に高い問題です.今日は一緒にthisを理解しましょう.
コンテキストを実行
まず、私たちはまず、コンテキストの前の文章を実行するかどうかを見に来ました.コードの運行環境は主に二つの種類に分けられています.
  • グローバル運転環境
  • 関数実行環境
  • javascriptコードの運行は主に二つの段階に分けられます.
  • コンパイルステージ
  • 実行フェーズ
  • コードコンパイルは主にコンパイラによって行われますが、コード実行はjsエンジンによって行われます.コードが実行環境に入るごとに、現在の環境の実行コンテキストが作成されます.実行文脈は作成時に以下のことをします.
  • は、まず変数オブジェクトを生成します.前の記事では、変数オブジェクトの内部には現在の環境のすべての変数と関数が格納されていますが、変数オブジェクトは最初はargmentsパラメータリストだけです.したがって、変数オブジェクトを生成する際には、実際にはargmentsを作成し、function関数宣言を確認し、var変数宣言を確認します.したがって、変数の昇格もこの段階で実現されます.
  • 以降、thisの指向が確定されます.だからこの時、私達はいつも聞いたことがあるひと言を思い付くことができます.一つの関数が呼び出されていない時、あなたは永遠に彼のthisが誰を指しているのか分かりません.
  • 以降は変数の割り当てや関数の参照などが行われます.
  • したがって、thisは、実際にはコンテキストの属性を実行するだけです.これは関数が呼び出された時だけ確定されます.
    this
    次のように、thisの使用シーンを見てみます.実は、主に次のような状況に分けられています.
    1、グローバルコンテキストで
    全体的な文脈では、thisは常にwindowを指します(厳格なモードではundefindです).
    var a = 10
    console.log(this.a)
      
    10
    
    2、一般関数呼び出し((()の形で直接呼び出す)
    関数が直接に()の形で呼び出されると、関数内のthisは常にグローバルコンテキストwindowを指します.(厳密なモードではundefindです.)
    setTimeout(function () {
         
    	aaa()
    }, 0)
    
    function aaa () {
         
    	console.log(this)   // window
    }
    
    すぐに関数またはコールバック関数を指す場合があります.下記のコードを見てください.
    var promise = new Promise(function (resove, reject) {
         
        console.log(this)
    })
    
    setTimeout(function () {
         
        console.log(this)
    }, 1000)
    
      
    window
    window
    
    上記のコードの中で、new Promise内部は関数ですが、この関数内のthisはwindowを指しています.これはこの関数がPromise()という方法の中で、実はfun()の普通関数の形式で呼び出されたので、window(前にPromiseソースを書いた人を見れば、この関数はどうやって呼び出されたのかが分かります.)
    setTimeoutのコールバック関数も同じで、setTimeoutという方法では、通常の呼び出しによってこの関数を呼び出すので、thisもwindowを指します.
    3、対象とする方法が呼び出されます.
    関数がオブジェクトとして呼び出された場合、thisはこのメソッドを呼び出すオブジェクトを指します.
    var obj = {
         
        name: 'chen',
        say: say
    }
    
    function say () {
         
        console.log(this)
        console.log(this.name)
    }
    
    obj.say()
    
      
    {
          name: 'chen', say: [Function: say] }
    chen
    
    もう一つは、イベント方法がトリガーされた時に、メソッド内のthisがトリガーイベントのdom要素を指します.実はdomオブジェクトに呼び出されたものなので、このタイプにします.
    <button class="btn">  </button>
    <script>
        var btn = document.querySelector('.btn')
        btn.onclick = function () {
         
            console.log(this)
        }
    </script>
      
    <button class="btn">  </button>
    
    4、newキーワードの実装対象時に呼び出します.
    newを使ってオブジェクトを実例化するときに構造関数を呼び出すと、関数内のthisがnewから出てくる例を指します.
    function China (name, age) {
         
        this.name = name
        this.age = age
    }
    
    const zhangSan = new China('  ', 18)
    
    console.log(zhangSan.name, zhangSan.age)
    
      
         18
    
    5、callにより、applyはthis指向を変更する.
    callによって、applyがある方法を呼び出すと、この方法の呼び出し時のthisの方向を指定することができます.このような行為は方法貸しとも言われています.
    var zhang = {
         
        name: '  ',
        age: 18,
        say: say,
        sayAag: sayAag
    }
    
    var wang = {
         
        name: '  ',
        age: 20
    }
    
    function say () {
         
        console.log(this.name)
    }
    
    function sayAag () {
         
        console.log(this.age)
    }
    
    zhang.say.call(wang)
    zhang.sayAag.apply(wang)
    
      
      
    
    上記のコードにより、zhangオブジェクトはsayの方法がありますが、wangオブジェクトはありません.この時zhangは彼のsay方法を呼び出す時、call方法を使ってthisをwangに向けます.say内部出力のnameは実はwangのnameです.appyも同じです.callとappyは、後の第一パラメータの伝達と違い、一つは伝達パラメータリスト(一つの形式伝達)、一つは伝達パラメータを含む配列である.
    obj.fun.call(obj2, a, b, c)
    obj.fun.apply(obj2, [a, b, c])
    
    6、ビッドバインディングthis指向
    一つのオブジェクトをbingで結びつけると、この方法の内部thisは常にバインディングされたオブジェクト(二度と変化しない)bind方法とcallを指し、applyは異なり、bindは関数の呼び出しをすぐにトリガしない.彼は新しい関数を返し、この新しい関数のthisをバインディングされたオブジェクトに向けている.注意:bindは一回だけ有効になります.つまり、新しく戻った関数にもう一度bindを使ってオブジェクトを結合すると、有効になりません.
    var name = '  '
    var obj = {
         
        name: '  ',
        age: 20
    }
    var obj2 = {
         
        name: '  ',
        age: 28
    }
    function say () {
         
        console.log(this.name)
    }
    var fun = say.bind(obj)
    fun()
    fun.call(obj2)
    
      
      
      
    
    上記のコードから分かるように、最初のfun()は直接普通に呼び出された時、元々thisはwindowを指しているはずです.出力は張三のものですが、bindによって彼のthisはずっとObjを指しています.だから出力はObjのnameです.この時、私達はcall方法でthisの方向を変えた時、thisの指向は再び変化しません.
    7、矢印関数
    矢印関数内部のthisは、この矢印関数のコンテキストでのthisを指します.
    obj = {
         
        name: '  ',
        say: () => {
         
            console.log(this)
        }
    }
    obj.say()
    
      
    window
    
    上記のコードは、obj.say thisを呼び出したのは元々objを指していたが、say方法は矢印関数を使用しているので、thisはこの矢印関数が置かれているコンテキストのthisを指していることが分かる.この矢印関数はグローバル環境にあるのではないですか?だからwindowを指します.もう一つの例を見ます
    var obj = {
         
        say: say
    }
    
    function say () {
         
        setTimeout(function () {
         
            console.log(this)
        }, 1000)
    
        setTimeout(() => {
         
            console.log(this)
        }, 2000)
    }
    
    obj.say()
    
      
    window
    obj
    
    setTimeout内のコールバック関数はデフォルトでは一般的に呼び出されていますので、最初の出力windowは矢印関数で使用されますが、彼のthisは関数外のコンテキストthisを指します.関数外はsay関数内のthisを指します.say関数内のthisはobjを指していますか?だからset Timeout内のthisもobjを指しています.
    thisはここで書きます.好きならいいです.