关于javascript:关于js-中this指向问题

5次阅读

共计 2880 个字符,预计需要花费 8 分钟才能阅读完成。

以下内容为自己浏览《你不晓得的 Javascript》中 this 局部的读书小结,有趣味的话能够间接看原著。

前言

  • 初步理解 this
    1.this 不指向函数本身
    2.this 不指向函数的词法作用域(箭头函数除外)
    3.this 实际上切实函数调用时产生的绑定,它指向什么齐全取决于函数在哪里调用,也就是函数的调用地位。

绑定规定

默认绑定

  • 默认绑定中,this 指向全局对象
  • 如果判断是否是默认绑定?
    察看函数的调用地位,不带任何润饰的函数援用进行调用,实用默认绑定。留神严格模式下,不能将全局对象用于默认绑定,this 会绑定到 undefined。

    fucntion foo() {console.log(this.a) 
    }
    var a = 2;
    foo()  // 2

    隐式绑定

  • 隐式绑定规定会把函数调用中的 this 绑定到这个上下文对象。
  • 察看调用地位是否有上下文对象,或者被某个对象领有或者蕴含,如下:

    fucntion foo() {console.log(this.a) 
    }
    var obj = {
        a: 2,
        foo: foo
    }
    obj.foo()  // 2
  • 对象属性援用链上只有最初一层在调用地位中起作用。

    function foo() {console.log(this.a)
    }
    var obj1 = {
        a: 2,
        foo: foo
    }
    var obj2 = {
        a: 42,
        obj1: obj1
    }
    obj2.obj1.foo()   //2
  • 函数援用导致隐式绑定失落

    1. 函数援用

  var a = 'global'
  function foo() {console.log(this.a)
  }
  var obj1 = {
      a: 2,
      foo: foo
  }
  var bar = obj1.foo
  bar()   // 'global'
  

​ 2. 参数传递或者回调函数(实质是隐式赋值)

    var a = 'global'
  function foo() {console.log(this.a)
  }
  var obj1 = {
      a: 2,
      foo: foo
  }
  var bar = obj1.foo
  function bar(fn) {fn()
  }
  bar(obj1.foo)   // 'global'
  
  setTimeout(obj1.foo, 500) //'global'

显式绑定

  • call(obj, …args)
  • apply(obj, args)
  • bind(obj, …args)es5 硬绑定

New 绑定

  • 应用 new 来调用函数时,咱们会结构一个新对象并把它绑定到函数调用中的 this 上。
    function foo(val) {this.a = val}
    let bar = new foo(2)
    console.log(bar.a)   // 2 
    // 此时函数中的 this => bar。// 简略理解一下应用 new 来调用函数,会产生什么
    // 1.创立(或者说结构)一个全新的对象。// 2.这个新对象会被执行 [[Prototype]] 连贯。// 3.这个新对象会绑定到函数调用的 this。// 4.如果函数没有返回其余对象,那么 new 表达式中的函数调用会主动返回这个新对象。// 也就是在第 3 步的时候才会进行 this 绑定,更体现了 this 绑定是产生在函数调用的时候。

优先级比拟

隐式绑定和默认绑定(不言而喻)

    不言而喻,隐式绑定优先级高于默认绑定

显示绑定和隐式绑定

        function foo() {console.log(this.name)
    }
    let obj1 = {
        name: 'obj1',
        foo
    }
    let obj2 = {name: 'obj2',}
        obj1.foo.call(obj2)  // 'obj2'

显式绑定优先级高于隐式绑定

new 绑定和隐式绑定

        function foo(name) {this.name = name}
    let obj1 = {
        name: 'obj1',
        foo
    }
    obj1.foo('new name') 
    console.log(obj1.name)          // new name
    var bar = new obj1.foo('bar')   
    console.log(bar.name)          // bar
    console.log(obj1.name)         // new name

new 绑定优先级高于隐式绑定

new 绑定和显示绑定

  • ES5 中内置的 Function.prototype.bind(..)

           function foo(name) {this.name = name}
      let obj1 = {
          name: 'obj1',
          foo
      }
      var newFoo = foo.bind(obj1)
      newFoo('new name')
      console.log(obj1.name)         // new name
      var bar = new newFoo('bar')   
      console.log(bar.name)          // bar
      console.log(obj1.name)         // new name

如和判断 this(个别状况下(非箭头函数),判断流程)

1.函数是否在 new 中调用(new 绑定)?如果是的话 this 绑定的是新创建的对象。
2.函数是否通过 call、apply(显式绑定)或者硬绑定调用?如果是的话,this 绑定的是指定的对象。
3.函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this 绑定的是那个上下文对象。
4.如果都不是的话,应用默认绑定。如果在严格模式下,就绑定到 undefined,否则绑定到全局对象。
(例外:如果你把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值在调用时会被疏忽,理论利用的是默认绑定规定)

箭头函数

1. 箭头函数不应用 this 的四种规范规定,而是依据外层(函数或者全局)作用域来决定 this。
2. 箭头函数的绑定无奈被批改
3. 箭头函数用更常见的词法作用域取代了传统的 this 机制。
4. 在没有箭头函数之前,咱们通常应用 that 或者 self,去代替函数外部的 this

    this.a = 'global'
    var obj1 = {a: 1}
    function foo() {setTimeout_(() => {console.log(this.a)
        })
    }
    
    function bar() {setTimeout_(function() {console.log(this.a)
        })
    }
    function setTimeout_(fn) {fn()
    }
    foo.call(obj1) // 1       箭头函数,须要察看箭头函数被创立时的词法作用域,this 取决于外层作用域
    bar.call(obj1) // global  一般函数应用四条规定,次要察看函数被调用时的状况
    

总结

  • 如果要判断一个运行中函数的 this 绑定,就须要找到这个函数的间接调用地位。找到之后就能够程序利用上面这四条规定来判断 this 的绑定对象。
    1.由 new 调用?绑定到新创建的对象。
    2.由 call 或者 apply(或者 bind)调用?绑定到指定的对象。
    3.由上下文对象调用?绑定到那个上下文对象。
    4.默认:在严格模式下绑定到 undefined,否则绑定到全局对象。肯定要留神,有些调用可能在无心中应用默认绑定规定。
  • ES6 中的箭头函数并不会应用四条规范的绑定规定,而是依据以后的词法作用域来决定 this,具体来说,箭头函数会继承外层函数调用的 this 绑定(无论 this 绑定到什么)。这其实和 ES6 之前代码中的 self = this 机制一样。
正文完
 0