JavaScript 之this的使用场景和理解

JavaScript 的 this 总是指向一个对象,而具体指向哪个对象是在 运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。而在 es6 中 箭头函数 中得到来改善,在定义的时候确定,多数情况是一个比较灵活,还是需要依据执行的环境推理判断

从四个大的方向去推理this指向的具体对象

  1. 作为对象的方法调用
  2. 作为普通函数调用
  3. 作为构造函数调用
  4. 函数的 call 或 apply 方法调用

1. 作为对象的方法调用

当函数作为对象的方法被调用时,this 指向该对象

let obj={
    a:'a',
    getName:function(){
      console.log(this); // obj
      console.log(this.a); // a
    }
  }
  obj.getName() // 函数作为对象的方法,并且被当前对象调用

2. 作为普通函数调用

此时的 this 总是指 向全局对象,window

2.1 情况一 全局变量全局函数

let name = 'globName';
  let getName=function(){
    return this.name;
  }
  console.log(getName()); // globName

2.2 情况二 对象方法变为普通函数

let name = 'globName';
let obj={
    name:'obj',
    getName:function(){
      return this.name;
    }
  }
  // 普通函数
  let getName2=obj.getName;
  console.log(getName2()); // 输出:globName  而不是:期待的obj

同样this是window对象全局

2.3 情况三 局部函数

比如在一个对象函数内部,有一个局部的 callback 方法, callback 被作为普通函数调用时,callback 内部的 this 指向了 window,但我们往往是想让它指向 该obj对象本身,

window.name = 'globName';
  let obj={
    name:'obj',
    getName:function(){
      console.log(this.name); // obj
      let callback =function(){
        console.log(this.name); //globName
      }
      callback(); // 变成普通函数被调用
    }
  }
  obj.getName();
2.3.1 解决方法一

定一个变量保存this的引用,通过上面的代码修改一下

... 省略
getName:function(){
      console.log(this.name); // obj
      let _this=this; // obj 对象的引用
      let callback =function(){
        console.log(_this.name); // 输出:obj
      }
      callback(); // 变成普通函数被调用
    }
 ... 省略   
2.3.1 解决方法二

箭头函数,箭头函数的this 在定义的时候确定

getName:function(){
      console.log(this.name); // obj
      // 局部函数改造为箭头函数
      let callback =()=>{
        console.log(this.name); // 输出:obj
      }
      callback(); // 变成普通函数被调用
    }

3. 作为构造函数调用

当用 new 运算符调用函数时,该函数就是一个构造函数,总会返回一个对象,通常情况下,构造函数里的 this 就指向返回的这个对象,构造函数和普通函数是一模一样,唯一的区别是调用的时候

function myClass(){
   this.name='LI';
 }
 let myName= new myClass(); // new 返回一个对象
 console.log(myName.name); // LI 指向特定对象 而不是普通函数的window对象 

有一种情况需要注意 当构造函数有返回值当时候,情况有所不同

3.1 构造函数 返回一个显式对象

如果返回一个显式的对象,那么this是该返回对象而不是之前期待的this;

 function myClass2 (){
   this.name='LI';
   return{  // 显式的返回一个对象
     name:'zhang'
   }
 }
 let myName2= new myClass2();
 console.log(myName2.name); // zhang

返回的是‘zhang’ 而不是期待的‘ LI’
如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会造成上述 问题;

3.2 构造函数 返回一个非对象类型

 function myClass3 (){
   this.name='LI';
   return 'zhangs';
 }
 let myName3= new myClass3();
 console.log(myName3.name); // LI

返回一个非对象类型 就是正常的this指向 new 的对象

4. 函数的 call 或 apply 方法调用

call 和 apply 都是函数的方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象,即动态的改变this

 let obj1={
   name:'li',
   getName:function(){
     return this.name;
   }
 }
 let obj2={
   name:'zh'
 }
 console.log(obj1.getName()); // li
 console.log(obj1.getName.apply(obj2)); // zh

obj1.getName.apply(obj2) 改变来obj1 的原来this 指向,变为来obj2,
详细的apply 方法使用介绍可以参考
《javascript 之 apply()、call() 探索》

消失this

看下面的代码

let obj={
    name:'objName',
    getName:function(){
      return this.name;
    }
  }
  // 对象的方法
  console.log(obj.getName()); // objName 
  let getName2=obj.getName;
  // 普通函数的的方法
  console.log(getName2()); // 返回空 什么都没有

getName2 普通函数调用,this 访问都是window对象。这个时候没有找到window对象的 name属性,理论上应该是undefined 实际在最新Chrome中为空,而 firfox 为

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值