this

60 阅读3分钟

改变函数内部 this 指向

普通函数里的 this 指向window

JavaScript 为我们专门提供了一些函数方法来帮我们更优雅的处理函数内部 this 的指向问题,常用的有 bind()、call()、apply()三种方法。

call方法

call() 方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向。

语法:fun.call(this, arg, arg1, arg2, ...)

// 改变函数内 this 指向,js提供了三种方法 call() apply() bind()

// 1. call()
var o = {
  name: 'andy'
}

function fn() {
  console.log(this) // 普通函数,this指向的是window
}

fn.call(o) // 此时,this 指向的就是o这个对象

function fn(a, b) {
  console.log(this) // 普通函数,this指向的是window
  console.log(a + b) // 3
}
fn.call(o, 1, 2) // 可以传参数
// call 第一个可以调用函数,第二个可以改变函数内的 this 指向
// call 的主要作用可以实现继承
function Father(uname, age, sex) {
  this.uname = uname;
  this.age = age;
  this.sex = sex;
}
function Son(uname, age, sex) {
  Father.call(this, uname, age, sex)
}
var son = new Son('小明', 12, '男');

apply方法

// 2. apply() 应用 运用的意思
var o = { name: 'andy' };
function fn() {
  console.log(this)
}
fn.apply(o); // 输出 { name: 'andy' }
// 1. 也是调用函数 第二个可以改变函数内部的this指向
// 2. 但是他的参数必须是数组(伪数组)
// 3. apply 的主要应用,比如说我们可以利用 apply 借助于数学内置对象求最大值 Math.max()
function fn1(arr) {
  console.log(this);
  console.log(arr); // 'pink'
}
fn.apply(o, ['pink']);

// 求数组最大值
var arr = [1, 66, 3, 99, 4];
Math.max.apply(null, arr); // 99 此处不需要改变this指向,所以第一个参数写null
Math.max.apply(Math, arr); // 第一个参数Math,因为Math调用了apply,所以让this指向Math的调用者,这样比较合理
Math.min.apply(Math, arr); // 1

bind方法

bind() 方法不会调用函数,但是能改变函数内部 this 指向

fun.bind(thisArg, arg1, arg2, ...)

  • thisArg: 在 fun 函数运行时指定的this值
  • arg1, arg2: 传递的其他参数
  • 返回由指定的 this 值和初始化参数改造的原函数拷贝
// 3. bind() 绑定 捆绑的意思
var o = { name: 'andy' };
function fn() {
  console.log(this);
}
// fn.bind(o); // 只绑定不输出,所以没有任何输出
var f = fn.bind(o);
f(); // 输出 { name: 'andy' }
// 1. 不会调用原来的函数,可以改变原来函数内部的 this 指向
// 2. 返回的是原函数改变this之后产生的新函数

function fn1(a, b) {
  console.log(this);
  console.log(a + b);
}
var f = fn1.bind(o, 1, 2);
f(); // 3

// 3. 如果有的函数我们不需要立即调佣,但是又想改变这个函数内部的this指向此时用bind方法最合适了
// 4. 我们有一个按钮,当我们点击了之后,就禁用这个按钮,3秒之后开始这个按钮
var btn = document.querySelector('button');
btn.onclick = funtion() {
  this.disabled = true; // 这个this指向的是btn这个按钮的调用者
  setTimeout(function() {
    this.disabled = false; // 不会释放,因为定时器函数里面的this指向的是window,window对象没有disable这个属性,所以给它设置是不起效果的
  }, 3000)
}

// 传统方法
btn.onclick = funtion() {
  this.disabled = true; // 这个this指向的是btn这个按钮的调用者
  var that = this;
  setTimeout(function() {
    that.disabled = false; // 不会释放,因为定时器函数里面的this指向的是window,window对象没有disable这个属性,所以给它设置是不起效果的
  }, 3000)
}

// bind方法
btn.onclick = funtion() {
  this.disabled = true; // 这个this指向的是btn这个按钮
  setTimeout(function() {
    this.disabled = false; // 不会释放,因为定时器函数里面的this指向的是window,window对象没有disable这个属性,所以给它设置是不起效果的
  }.bind(this), 3000) // 这个this指向的是btn这个对象
}