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

早过忘川 提交于 2020-04-06 10:06:11

写在前面

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();

这里说一下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();
发布了208 篇原创文章 · 获赞 124 · 访问量 8万+
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!