理解严格模式下JavaScript的this指向的变化

全局代码中的this

  • 全局中的代码无论是否处于严格模式下,它的this都执行Windowjavascript

    console.log(this) // Window
    复制代码

箭头函数的this

  • 箭头函数的this由上下文的词法做用域决定,即在哪定义的就指向哪里的this
() => {
      console.log(this) // window 或 global,在全局定义指向全局
  }
  obj = {
      fn: () => {
          console.log(this) // obj 在obj对象中定义,可是指向全局(箭头函数时,obj没法确认环境)
      }
  }
复制代码

普通函数中的this

  • 直接调用函数(在全局或者其余函数内)html

    • 在非严格模式下,this默认指向全局变量(window或global)java

      ```js
      // 在浏览器中,全局对象是window, 在NODE中是global
      function test() {
        console.log(this) // Window 或者 global
        (function(){
           console.log(this) // Window 或者 global
        })
      }
      test() 
      ```
      复制代码
      • 在严格模式下,this将保持进入执行环境的值,因此,若是没有指定环境,则默认undefined
      function test() {
        console.log(this) // undefined 
        (function(){
           console.log(this) // undefined
        })
      }
      test() 
      复制代码
      • 特殊点:当函数做为回调函数时,须要注意是否隐式绑定了所属对象,例如:看成为setTimeout的参数时,就默认将函数绑定了window对象
      // setTimeout是window的方法,可使用window.setTimeout调用
      // 调用函数时,对象访问大体路线:window -> setTimeout -> 获取参数中test的引用参数 -> 执行 test 函数
      function test() {
         console.log(this) 
      }
      setTimeout(test, 100); // window 或 global
      复制代码
  • 做为对象方法调用则指向当前对象es6

    • 注意:以下列代码中的将对象的方法赋值给其余变量在调用,this将按上面的普通方法直接调用函数规则处理
    var a = 'global'
    function name() {
         console.log('name', this.a) // 经过普通调用方法直接调用,在严格模式下this为undefined,运行报错,在非严格模式下global
    }
    var obj = {
     fn: function () {
         console.log('inner', this.a) // obj 经过对象obj调用,this指向该对象与模式没有关系
         name() 
     },
     a: 'obj'
    }
    obj.fn()
    var newFn = obj.fn()
    newFn() // 严格模式为undefined,非严格为window或者global,按普通方法直接调用的规则处理
    function test(fn){
       fn()  
    }
    test(obj.fn) // 至关于将fn=obj.fn, 严格模式为undefined,非严格为window或者global
    newObj = {fn: 2}
    test(newObj.fn=obj.fn) // 至关于 fn = newObj.fn = obj.fn, 严格模式为undefined,非严格为window或者global
    复制代码
  • 执行new操做时,构造函数的this指向正在构造的新对象浏览器

    function TEST(){
        this.a = 'obj';
        console.log(this) //new操做时 TEST { a: 'obj'} this指向正在构造的对象(返回的对象)
    }
    var o = new TEST();
    console.log(o); // TEST { a: 'obj'} this指向刚刚构造的对象
    复制代码
    • 对es6的class Person {} 使用new操做时,this执行它调用的环境
    class MyTest {
      constructor (callback) {
        this.callback = callback
        callback() // 指向window
      }
      func () {
        this.callback() // 指向MyTest
      }
    }
    // let的值不会绑定到window上,没法用window.name访问
    let name = 'global'
    function Test () {
      console.log(this, this.name)
    }
    new Test() // window 使用let输出 '', 使用var输出global
    let c = new MyTest(Test) // window 使用let输出 '', 使用var输出global
    c.func() // MyTest{} undefined
    复制代码
    • 其余状况下Constructor的执行与普通函数没有区别,谁调用它则指向谁
    // 当函数直接调用的时候,在非严格模式下,this指向window;严格模式为undefined
    // 当函数做为对象的属性调用的时候,this指向这个对象;
    // p1.constructor指向Person的构造函数(Person()函数自己),
    // 在p1.constructor()时,Person是做为p1的属性调用的,因此this指向p1;
    // 当调用p2 = p1.constructor;p2();时,其实就至关于直接调用Person();因此this指向window
    var name = 'global'
    function Person() {
        this.name = 'person';
        console.log(this);
    }
    var p1 = new Person();
    p1.constructor();        // Person {name: "person"}
    var p2 = p1.constructor;
    p2();   // window
    复制代码
  • 设置call/apply/bind后调用,则指向其第一个参数的this,若是为空则在严格模式下指向undefined,在非严格模式下指向window或globalbash

    // 语法
    // 一、函数.apply(对象, [参数列表]) 
    // 二、函数.call(对象, arg1,arg2,arg3…argn)
    // 三、函数.bind(对象)
    // 'use strict'
    var a = 'global'
     function name() {
         console.log('name', this.a)
     }
     function name2() {
         console.log('name2', this)
     }
     var obj = {
         a: 'obj'
     }
     name.call(obj) // obj this指向经过call绑定的obj对象
     // name2.call() // 严格模式为undefined,非严格模式为widow或global
    复制代码
  • 做为一个dom事件处理函数,它的this指向添加处理事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵照这个约定)闭包

    // html
    <div id="A">
      <div id="B"></div>
    </div>
    // javascript
    var a = document.getElementById('A');
    var b = document.getElementById('B');    
    function logs (e) {
        console.log(e.target, e.target===this); // 当e.target与e.currentTarget相等时为true
        console.log(e.currentTarget, e.currentTarget===this); // 老是true
    }
    a.addEventListener('click', logs, false);
    // 点击A时,
    // 输出 A节点信息,true \n A节点信息, true
    // 点击B时,
    // 输出 B节点信息,false \n A节点信息, true
    // currentTarget表示实际绑定处理事件的元素
    // target表示触发事件的元素(如点击B)
    // 因此处理事件中的this指向实际添加处理事件的元素
    复制代码
  • 做为一个内联事件处理函数,app

    • 当代码被内联on-event 处理函数调用时,它的this指向监听器所在的DOM元素,与模式没有关系
    <button onclick="alert(this.tagName.toLowerCase());">Show this</button>
    复制代码
    • 当代码包裹在内部函数中时,在非严格模式指向window或global对象(即非严格模式下调用的函数未设置this时指向的默认对象),在严格模式下为undefined
    <button onclick="alert((function(){return this})());">Show inner this</button>
    复制代码

闭包的this指向

闭包的执行至关因而返回一个函数,而后将这个返回的函数执行,所以和普通函数的直接调用相同dom

var box={
    user: 'zs',
    getThis:function(){
        return function(){
            return this;   
        };
    }
}
console.log(box.getThis()()); // 指向全局,非严格为window,严格为undefined
复制代码
相关文章
相关标签/搜索