this指向

JavaScript中的this指向问题

在JS中,this属于一个关键字,也就是可以理解为,它是一个系统自带命令通常,我们把它的含义解释为:当前对象

  • 语法

    this

  • 当前执行代码的环境对象


  • 那么问题来了: 当前对象到底是指谁呢?

  1. 全局环境

    无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

    // 在浏览器中, window 对象同时也是全局对象:
    console.log(this === window); // true
    
    a = 37;
    console.log(window.a); // 37
    
    this.b = "MDN";
    console.log(window.b)  // "MDN"
    console.log(b)         // "MDN"
    
  • 函数(运行内)环境

    在函数内部,this的值取决于函数被调用的方式。

  • 简单调用

    • 因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象。

      function f1(){
      return this;
      }
      //在浏览器中:
      f1() === window;   //在浏览器中,全局对象是window
      
      

      然而,在严格模式下,this将保持他进入执行环境时的值,所以下面的this将会默认为undefined

      function f2(){
          "use strict"; // 这里是严格模式
          return this;
      }
      f2() === undefined; // true
      

      所以,在严格模式下,如果 this 没有被执行环境(execution context)定义,那它将保持为 undefined

  • 如果要想把 this 的值从一个环境传到另一个,就要用 call 或者apply 方法

    var obj = {a: 1};
    var a = 2;
    function whatsThis(arg) {
      return this.a;  // this的值取决于函数的调用方式
    }
    
    whatsThis();          //  2
    whatsThis.call(obj);  //  1
    whatsThis.apply(obj); //  1
    
  • 当一个函数在其主体中使用 this 关键字时,可以通过使用函数继承自Function.prototypecallapply 方法将 this 值绑定到调用中的特定对象。

     function add(c, d) {
       return this.a + this.b + c + d;
     }
     
     var arr = {a: 1, b: 3};
     
     // 第一个参数是作为‘this’使用的对象
     // 后续参数作为参数传递给函数调用
     add.call(arr, 5, 7); // 1 + 3 + 5 + 7 = 16
     
     // 第一个参数也是作为‘this’使用的对象
     // 第二个参数是一个数组,数组里的元素用作函数调用中的参数
     add.apply(arr, [10, 20]); // 1 + 3 + 10 + 20 = 34
    
  • bind方法

    • ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的。
       function f(){
              return this.a;
            }
            var g = f.bind({a:"azerty"});
            console.log(g()); // azerty
            
            var h = g.bind({a:'yoo'}); // bind只生效一次!
            console.log(h()); // azerty
            
            var o = {a:37, f:f, g:g, h:h};
            console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
      
  • 箭头函数

    • 在[箭头函数]中,this与封闭词法环境的this保持一致。在全局代码中,它将被设置为全局对象:

      var obj = {
          show :function(){
              setTimeout(() => {
                  console.log(this)
              },0)
          }
      }
      obj.show();  //this指向 show
      
    • 箭头函数可以用call,apply,bind来改变this指向吗?

    • 不能!! 试图改变箭头函数的this是徒劳的。

      var a = 10;
      var arr ={
         a : 12
      }
      var fn =() =>{
         console.log(this.a)
      }
      var fn2= function(){
         console.log(this.a)
      }
      fn()                         // 10
      fn2()						 // 10
      fn.call(arr)				 // 10
      fn.apply(arr)				 // 10
      var bound1 = fn.bind(arr);   // 10
      bound1();					 // 10		
      fn2.call(arr)				 // 12
      fn2.apply(arr)				 // 12
      var bound2 = fn2.bind(arr);  // 12
      bound2();					 // 12
      
  • 作为对象的方法

    • 当函数作为对象里的方法被调用时,它们的 this 是调用该函数的对象。

      var o = {
       prop: 37,
       f: function() {
         return this.prop;
       }
      };
      
      console.log(o.f()); //  37
      
    • 请注意,这样的行为,根本不受函数定义方式或位置的影响。在前面的例子中,我们在定义对象o的同时,将函数内联定义为成员 f 。但是,我们也可以先定义函数,然后再将其附属到o.f。这样做会导致相同的行为:

      var o = {prop: 37};
      
      function independent() {
        return this.prop;
      }
      
      o.f = independent;
      
      console.log(o.f()); //  37
      

    这表明函数是从of成员调用的才是重点。

  • 作为构造函数

    • 当一个函数用作构造函数时(使用[new]关键字),它的this被绑定到正在构造的新对象。

      虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回this对象)。

      function C(){
          this.a = 37;
      }
      
      var o = new C();
      console.log(o.a); // 37 
      function C2(){
          this.a = 37;
          return {a:38};
      }
      
      o = new C2();
      console.log(o.a); //  38     
      
  • 原本的构造函数是window对象的方法,如果不用new操作符而直接调用,那么构造函数的执行对象就 是window,即this指向了window。现在用new操作符后,this就指向了新生成的对象

  • 普通函数与构造函数的区别

    function Person1(){
        this.name = "小红";
        var age = 22;
        window.height = 180;
        //普通函数this 指向window
        console.log(this)     // window
    }
    function Person2(){
        this.name = "小明";
        var age = 21;
        window.height = 181;
        //构造函数里的 this指向新生成的person2 对象
        console.log(this)  //Person2 {name: "小明"}
    }
    var person = Person1();     
    var person2 =new Person2()
    // console.log 里的 this指向 window
    console.log(this.name)       // 小红
    console.log(this.age)        // undefined
    console.log(this.height)     // 181
    // console.log(person.name)  // 报错
    // console.log(person.age)   // 报错
    console.log(person2.name)    // 小明
    console.log(person2.age)	 // undefined
    console.log(person2.height)	 // undefined
    

  • 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。prototype将会作为一个指向原型对象的指针。

  • 使用原型模式创建的实例对象,该对象通过this是可以相互访问的。

    	function Animal(name,age){
        this.name=name;
        this.age=age;   // 把 name ,age 放进实例对象之中
        consloe.log(this)    // Animal {name: "小苏", age: 20}
    } 
    //在实例对象中添加方法 eat()
    Animal.prototype.eat=function(){
        console.log(this.name +"吃");
        this.play();      //  this指向实例对象
    };
    //在实例对象中添加方法 play()
    Animal.prototype.play=function(){
        console.log("玩");
        this.sleep();
    };
    //在实例对象中添加方法 sleep()
    Animal.prototype.sleep=function(){
        console.log("睡");
    };
    
    //该实例对象通过this相互访问
    var dog=new Animal("小刘",20);  //创建 Animal {name: "小苏", age: 20} 实例对象
    dog.eat();    // 小刘吃 玩 睡
    

最后的结论
  1. 所有的this关键字,在函数运行时,才能确定它的指向
  2. this所在的函数由哪个对象调用,this就会指向谁
  3. 当函数执行时,没有明确的调用对象时,则this指向window
  4. 当函数是构造函数时,this指向实例对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值