JS的this指向及改变this指向的方法

写在前面

call、apply与bind都可以用来修改this的指向,但是他们之前有什么区别呢?下面我们来举例子说明一下。

this指向

请说出下面这个函数的输出结果:

var o = {hobby: 'abc'}
function test(){
    console.log(this.hobby);
}
test()

这个题考查的就是this指向的问题,在本题中,test函数是由window调用的,所有this指向window对象,但是在window对象中,并没有hobby属性,所以输出是undefined。

在看一道题:

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name);
  },
  func2: function() {
    setTimeout(function() {
      this.func1()  
    }, 100);
  }
};
a.func2();

这也是this指向的问题,我调用a.func2,在setTimeout中调用this.func1,但是setTimeout也是由window对象调用的,所以this指向window,但是在window中并没有func1函数,所以此时会报错:

Uncaught TypeError: this.func1 is not a function

这里补充一下this指向的问题:

函数this指向
普通函数window
对象的方法对象
构造函数构造函数new出来的实例对象
绑定事件函数函数的调用者
定时器函数window
立即执行函数window

那上面的那个函数想要成功运行,应该如何做呢?这个时候就需要修改this的指向了。

方案一:this替换

在func2函数中,this指向对象a,把this指向赋值给_this,在setTimeout中使用_this来访问func1。

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name); // cherry
  },
  func2: function() {
    var _this = this;
    setTimeout(function() {
      console.log(_this); // _this指向对象a
      _this.func1();
    }, 100);
  }
};
a.func2();

方案二:箭头函数

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name); // cherry
  },
  func2: function() {
    setTimeout(() => {
      console.log(this); // this指向对象a
      this.func1();
    }, 100);
  }
};
a.func2();

方案三:call

call执行一个函数:函数名.call(作用域对象),将函数放到特定的作用域对象中执行。下面这个例子中通过call将setTimeout函数的作用域对象从window改成了a。

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name); // cherry
  },
  func2: function() {
    setTimeout(function() {
      console.log(this); // this指向对象a
      this.func1();
    }.call(a), 100);
  }
};
a.func2();

方案四:apply

apply执行一个函数,函数名.apply(作用域对象)

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name); // cherry
  },
  func2: function() {
    setTimeout(function() {
      console.log(this); // this指向对象a
      this.func1();
    }.apply(a), 100);
  }
};
a.func2();

方案五:bind

var name = "windowName";
var a = {
  name: "cherry",
  func1: function() {
    console.log(this.name); // cherry
  },
  func2: function() {
    setTimeout(function() {
      console.log(this); // this指向对象a
      this.func1();
    }.bind(a), 100);
  }
};
a.func2();

三者区别

1.相同点

都可以改变函数内部的this指向

2.不同点

①call和apply会调用函数,并且改变函数内部的this指向,区别在于传的参数不同,如下面这个例子:

var a = {
  name: "cherry",
  fn: function(a, b) {
    console.log(a + b);
  }
};
var b = a.fn;
b.apply(a, [1, 2]);  // 对象 参数---数组
b.call(a, 1, 2)  // 对象 参数多个

apply中可以传递数组,call中需要将数组展开,传递具体值。如果使用bind的话:

var c = b.bind(a, 1, 2); // 绑定
c();

②bind不会调用函数

3.应用场景

①call经常做继承
②apply经常跟数组有关系,比如借助数学对象实现数组最大值最小值
③bind不调用函数,但是还想改变this指向,比如改变定时器内部的this指向

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值