jsにおけるthisの使い方

12865 ワード

nodejsとbrowserの中でthisの比較
nodejsのグローバルオブジェクトはglobalで、jsファイルはモジュールであり、モジュール内部にモジュールの役割領域を形成し、定義された変数はこのモジュールでのみ使用できます.globalオブジェクトまたはmodule.exportを使用して、複数のモジュール間で変数を共有できます.
//     this    module.exports
this === module.exports     // true
this === exports    // true
this    // {}

// x.js  
this.a = 1
exports.b = 2
module.exports.c = 3

// y.js
const {a, b, c} = require('./x.js')
browser環境のグローバルオブジェクトはwindowで、nodejsのglobalに相当します.モジュールの役割領域が存在しないため、nodejsとbrowserでthisの値が異なります.
//     (global context) this    window
this === window     // true
変数宣言
var a = 1
let b = 2
const c = 3
d = 4

// nodejs ,a b c        
global.a    // undefined
global.b    // undefined
global.c    // undefined
global.d    // 4, d         ,    global   

// browser ,         var     ,    window   ,    (legacy)  
this.a  // 1
this.d  // 4

// es6  let const,           window   
this.b  // undefined
this.c  // undefined
nodejsとbrowserのいずれもthisに対して直接値を割り当てることができません.
this = 1    // Invalid left-hand side in assignment
関数コンテキスト(function context)でthisの使い方
関数文脈では、nodejsとbrowserでは、thisの指し示す原理は基本的に同じで、以下のnodejsでテストします.
  • thisが明確にされていない場合、デフォルトはグローバルオブジェクト
  • を指す.
    function foo() {
         
      return this
    }
    
    //       ,   this  ,        
    foo() === global    // true in node
    foo() === window    // true in browser
    
    function foo() {
         
      'use strict'
      return this
    }
    
    //      ,   this      
    foo()   // undefined
  • 矢印関数(arrow function)矢印関数のthisは、参照関数が定義される場合のコンテキストを指し、クローズドが形成される.
  • this.a = 1
    let foo = (b) => this.a + b
    
    foo(2)      // 3
    foo.call({a: 2}, 2)     // 3,call     this   
    
    let f1 = foo.bind({a: 3})
    f1(2)       // 3,bind     this   
    
    this.a = 2
    foo()       // 4,    
  • オブジェクトの方法関数をオブジェクトとして呼び出す場合、thisは、この方法を呼び出すオブジェクトを指す.
  • let obj = {
      x: 1,
      f: getX,
      y: {
        x: 2,
        g: getX
      }
    }
    
    // getX   obj    ,        
    function getX() {
         
      return this.x
    }
    
    obj.f()     // 1
    getX.call(obj)  // 1
    obj.y.g()   // 2
    getX.call(obj.y)    // 2
  • 構築関数
  • newキーワードはデフォルトでfunctionのthisオブジェクトに戻ります.
    function Foo() {
         
      this.a = 1
    }
    
    // new  {a: 1}
    let f = new Foo()
    構築関数がオブジェクトに戻ると、newはオブジェクトに戻り、定義されたthisオブジェクトを返さない.
    function Foo() {
         
      this.a = 1
      return {b: 2}    //   {b: 2}
      return [1, 2]    //   [1, 2]
      return new Number(2)    //       [Number 2]
    
      return null    //   {a: 1}
      return undefined    //   {a: 1}
      return    //   {a: 1}
      return 1    //   {a: 1}
      return 'abc'    //   {a: 1}
    }
  • オブジェクトのプロトタイプに
  • オブジェクトはprototype上のメソッドを呼び出すことができます.thisは現在のオブジェクトを指しています.オブジェクト自体の方法と似ています.これはjsプロトタイプチェーン継承の特性です.
    function Foo(a, b) {
         
      this.a = a
      this.b = b
    }
    
    Foo.prototype.add = function () {
         
      console.log(this.a + this.b)
    }
    
    Foo.prototype.delayAdd = function () {
         
      setTimeout(this.add, 500)
    }
    
    let foo = new Foo(1, 2)
    foo.add()       // 3,     ,this   foo
    一つの方法を追加します
    Foo.prototype.delayAdd = function () {
         
      setTimeout(this.add, 500)
    }
    
    let foo = new Foo(1, 2)
    foo.delayAdd()  // undefined,     
    
    //   :delayAdd        
    Foo.prototype.delayAdd = function () {
         
      // this  foo
      setTimeout(function () {
         
        //   :  nodejs  Timeout  , setTimeout()    
        // browse this   window
        return this.a + this.b
      }, 500)
    }
    
    //   bind       this   
    Foo.prototype.delayAdd = function () {
         
      setTimeout(this.add.bind(this), 500)
    }
    
    foo.delayAdd()  // 3,  
    実例分析
    主に対象法、一般関数、矢印関数におけるthisの指向を考慮します.オブジェクトメソッドによって呼び出しと呼び出しは異なる場合があります.
    let o = {
      foo: () => this,
      bar: function () {
         
        return this
      },
      baz: function () {
         
        return () => this
      },
      qux: () => {
        return () => this
      },
      one: function () {
         
        return function () {
         
          return this
        }
      },
      two: () => {
        return function () {
         
          return this
        }
      }
    }
    fooは矢印関数を用いて定義されるオブジェクト方法であり、文脈ではthisがmodule.exportsを指し、クローズドされている.
    o.foo() === module.exports  // true
    o.qux() === module.exports  // true
    
    //         
    let foo = () => {
      return () => {
        return () => this
      }
    }
    foo()()() === exports   // true
    barは、一般関数で定義されたオブジェクト方法で、内部thisは現在のオブジェクトoを指します.矢印関数が定義されているときは、閉じられたパケットが形成されます.thisはコンテキストのthisを指します.
    o.bar() === o       // true
    o.baz()() === o     // true
    oneとtwoの中でthisは直接的に対象の方法の中に位置していません.他の方法でthisの指向を変えて、globalを指します.
    o.one()() === global    // true
    o.two()() === global    // true
    先に値を割り当ててから呼び出すと、結果が違ってきます.
    let b = o.baz
    b()() === global    // true
    //    
    let b = function(){
         
      return () => this
    }
    参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this