美文网首页
JavaScript中this的指向问题

JavaScript中this的指向问题

作者: 椰果粒 | 来源:发表于2019-03-14 17:58 被阅读0次

    this是什么

    • this是JavaScript的一个关键字。
    • this是在函数运行时,在函数体内自动生成的一个对象。
    • this只能在函数体内使用。

    在JavaScript中,函数的几种调用方式

    • 普通函数调用
    • 作为方法调用
    • 构造函数调用
    • call/apply中
    • Function.prototype.bind中
    • 箭头函数中

    this的几种指向

    • 哪个对象调用这个函数/方法,this就指向谁
    • 箭头函数的this指向定义的时候离他最近的对象
    • 箭头函数不绑定this,不会自己创建this,只能从自己的作用域的上一层继承this
    • 外层普通函数的this,会在函数调用时发生变化,进而影响箭头函数的this变化

    示例一

    var x = 111
    var test = {
        x : 222
    }
    var temp = {
        x : 333,
        do : function(){
            alert(this.x)
        }
    }
    temp.do()   // 333
    test.do = temp.do
    test.do()   // 222
    var foo = test.do
    foo()       // 111
    

    示例二

    var name = 'window'
    var person1 = {
      name: 'person1',
      show1: function(){
        console.log(this.name)
      }
    }
    var person2 = {
      name: 'person2'
    }
    person1.show1();              // person,this指向person1对象
    person1.show1.call(person2);  // person2,this指向person2对象
    

    示例三

    var name = 'window'
    var person1 = {
      name: 'person1',
      show2: () => console.log(this.name)
    }
    var person2 = {
      name: 'person2'
    }
    person1.show2();            // window,箭头函数的this和最近的普通function相同,没有,指向window
    person1.show2.call(person2);// window,无法和person2绑定,所以也是window
    

    示例四

    var name = 'window'
    var person1 = {
      name: 'person1',
      show3: function(){
        return function(){
          console.log(this.name);
        }
      }
    }
    var person2 = {
      name: 'person2'
    }
    
    person1.show3()();              // window
    person1.show3().call(person2);  // person2 
    person1.show3.call(person2)();  // window
    
    
    // 此问题牵扯到闭包的问题
    
    /* 
    person1.show3()(); // window
    等价于:
    var fun = person1.show3();
    fun();            // window 
    
    里面的匿名函数被返回到person1外边,再调用这个函数时,this指向了window
    */
    
    /* 
    person1.show3().call(person2); 
    等价于:
    var fun = person1.show3();
    fun.call(person2);      // person2 
    
    将匿名函数的this和person2绑定了
    */
    
    /* 
    person1.show3.call(person2)();  // window
    等价于
    var fun = person2.show3()
    fun() 
    
    在第一阶段绑定了person2,这时候匿名函数还没执行,等再执行时,绑定到了window上
    */
    

    示例五

    var name = 'window'
    var person1 = {
      name: 'person1',
      show4: function(){
        return () => console.log(this.name)
      }
    }
    var person2 = {
      name: 'person2'
    }
    
    person1.show4()();              // person1
    person1.show4().call(person2);  // person1
    person1.show4.call(person2)();  // person2
    
    // 这里涉及了箭头函数this的指向:最近一层的普通函数绑定的this,且定义时this就被定义好了
    
    /* 
    person1.show4()(); 
    等价于:
    var fun = person1.show4(); // 定义时,this指向了person1
    fun();           
    */
    
    
    /* 
    person1.show4().call(person2); 
    等价于:
    var fun = person1.show4();  // 定义时指向person1,而call不起作用
    fun.call(person2); 
    */
    
    
    /* 
    person1.show4.call(person2)(); 
    等价于
    var fun = person2.show4()  // 将箭头函数最近的一层普通函数的this指向了person2,再执行时,this就指向了person2
    fun() 
    */
    

    示例六

    var name = 'window'
    function Person(name){
      this.name = name
      this.show5 = function(){
        return () => console.log(this.name)
      }
    }
    var personA = new Person("personA");
    var personB = new Person("personB");
    
    personA.show5()();              // personA
    personA.show5().call(personB);  // personA
    personA.show5.call(personB)();  // personB
    

    示例七

    var name = 'window'
    
    function Person(name) {
      this.name = name;
      this.show1 = function () {
        console.log(this.name)
      }
      this.show2 = () => console.log(this.name)
      this.show3 = function () {
        return function () {
          console.log(this.name)
        }
      }
      this.show4 = function () {
        return () => console.log(this.name)
      }
    }
    
    var personA = new Person('personA')
    var personB = new Person('personB')
    
    personA.show1()               // personA
    personA.show1.call(personB)   // personB
    
    personA.show2()               // personA
    personA.show2.call(personB)   // personA
    
    personA.show3()()             // window
    personA.show3().call(personB) // personB
    personA.show3.call(personB)() // window
    
    personA.show4()()             // personA
    personA.show4().call(personB) // personA
    personA.show4.call(personB)() // personB
    

    示例八

    var name = 'window'
    function foo(){
      var name = 'inner';
      console.log(this.name)
    }
    foo();  // window
    // foo在全局全局执行,this指向window
    _________________________________________
    
    var name = 'window'
    function foo(){
      'use strict'
      var name = 'inner';
      console.log(this)
    }
    foo();  // undefined
    // 这里this.name会报错,因为this是undefined
    // 在严格模式下
    

    示例九

    function foo(){
      setTimeout(() => {
        console.log("id:" + this.id)
        setTimeout( () => {
          console.log("id:" + this.id)
        },100)
      },100)
    }
    foo.call({id:'111'})  // 111 111
    
    function foo(){
      setTimeout(function(){
        console.log(this.id)
        setTimeout(function(){
          console.log(this.id)
        },100)
      },100)
    }
    foo.call({id:'111'})  //  undefined undefined
    
    
    function foo1(){
      setTimeout(() =>{
        console.log("id:", this.id)
          setTimeout(function (){
            console.log("id:", this.id)
          }, 100);
      }, 100);
    }
    foo1.call({ id: 111 });  // 111 undefined
    

    示例十

    // 嵌套箭头函数
    function foo(){
      return () => {
        return () => {
          return () => {
            console.log(this.id)
          }
        }
      }
    }
    
    var f = foo.call({id: 1});
    var t1 = f.call({id: 2})()();  // 1
    var t2 = f().call({id: 3})();  // 1
    var t3 = f()().call({id: 4});  // 1
    

    示例十一

    var number = 2;
    var obj = {
      number: 4,
      fn1: (function () { 
        console.log("定义obj的时候,立即执行函数就执行了"); 
        var number;
        this.number *= 2;
        number = number * 2;
        number = 3;
        return function () {
          var num = this.number;
          this.number *= 2;
          console.log(num);
          number *= 3;
          console.log(number);
        }
      })(),
      db2: function () {
        this.number *= 2;
      }
    }
    
    var fn1 = obj.fn1; 
    
    console.log(number); // 4
    
    fn1();  // 4 9
    obj.fn1();  // 4 27
    console.log(window.number); // 8
    console.log(obj.number);  // 8
    
    
    当定义obj的时候执行了匿名函数1,此时处于全局作用域内,因此上下文this是window。执行完语句(1)导致全局变量number的值变为4;执行语句(2)时临时变量number还没有被赋值,所以是NaN,但下一句会将其赋值为3;最后,匿名函数1返回了匿名函数2,因此obj.fn1=匿名函数2。(注意匿名函数2里面会用到临时变量number,老生常谈的闭包)
    
    
    来到语句(3),这句会把fn1这个变量赋值为obj.fn1,也就是匿名函数2
    
    
    由于全局变量number已经在语句(1)中变为了4,所以语句(4)弹出的对话框结果为4
    
    
    语句(5)执行的是fn1(),它与执行obj.fn1()的区别是两者this不一样。前者为null,而后者this为obj。但是又由于JS规定,this为null时相当于全局对象window,所以这句代码执行时函数的this为window。在匿名函数2里会将全局变量number更新为8,同时将匿名函数1中被闭包的临时变量number更新为9
    
    
    语句(6)的效果在上面已经分析过了,this是obj,所以obj.number更新为8,闭包的number更新为27
    

    相关文章

      网友评论

          本文标题:JavaScript中this的指向问题

          本文链接:https://www.haomeiwen.com/subject/xcfrmftx.html