前言
一说到js中的call、apply、bind方法,就一定会和this联系起来,百分之九十以上的问题都是有关这三个函数方法中this的指向问题,在前端面试题中非常的常见,掌握了这三个方法的this指向问题,不仅可以在面试官前侃侃而谈,加深面试官对你的印象,而且可以提高我们js代码的编码水平和编码水平,作为一个前端这是我们必须掌握的基本知识。 再说他们三个之前,我们先来说下this吧,懂了this的指向问题,也就掌握了这三个方法的精髓。
this
this是函数内部的一个特殊的对象,,this引用的是函数据以执行的环境对象——或者也可以说是this值(当在网页的全局作用域调用函数时,this 对象引用的就是 window )。简单的说this指向调用该函数的环境对象。再简单一点就是谁调用它就指向谁,下面具体的说说this的调用指向
1.纯函数调用
var x = 1;
function test() {
console.log(this.x);
}
test(); // 1 this指向全局对象
复制代码
2.作为对象的方法调用
var obj = {
n:'1',
m:function test() {
console.log(this.n);
}
};
obj.m()//1 this指向obj
复制代码
3.作为构造函数调用
var x = 2;
function Test() {
this.x = 1;
}
var obj = new Test();
obj.x // 1 this 指向obj
x=2 //说明this并不是指向的是window
复制代码
4.事件绑定中的this
备注:下面的两个this指向参考了这个作者的文章,在通读之后觉得写的很透彻明了,就直接节选了部分,自己也就不在罗嗦了。
链接:zhuanlan.zhihu.com/p/42145138
事件绑定共有三种方式:行内绑定、动态绑定、事件监听;行内绑定的两种情况:
type="button" value="按钮" onclick="clickFun()">
type="button" value="按钮" onclick="this">
复制代码
行内绑定事件的语法是在html节点内,以节点属性的方式绑定,属性名是事件名称前面加'on',属性的值则是一段可执行的 JS 代码段;而属性值最常见的就是一个函数调用;当事件触发时,属性值就会作为JS代码被执行,当前运行环境下没有clickFun函数,因此浏览器就需要跳出当前运行环境,在整个环境中寻找一个叫clickFun的函数并执行这个函数,所以函数内部的this就指向了全局对象window;如果不是一个函数调用,直接在当前节点对象环境下使用this,那么显然this就会指向当前节点对象;动态绑定与事件监听:
type="button" value="按钮" id="btn">
复制代码
因为动态绑定的事件本就是为节点对象的属性(事件名称前面加'on')重新赋值为一个匿名函数,因此函数在执行时就是在节点对象的环境下,this自然就指向了本节点对象;
5.window定时器的this
var obj = {
fun:function(){
this ;
}
}
setInterval(obj.fun,1000); // this指向window对象
setInterval('obj.fun()',1000); // this指向obj对象
复制代码
setInterval()
是window对象下内置的一个方法,接受两个参数,第一个参数允许是一个函数或者是一段可执行的 JS 代码,第二个参数则是执行前面函数或者代码的时间间隔;
在上面的代码中,setInterval(obj.fun,1000)
的第一个参数是obj对象的fun ,因为 JS 中函数可以被当做值来做引用传递,实际就是将这个函数的地址当做参数传递给了 setInterval
方法,换句话说就是setInterval
的第一参数接受了一个函数,那么此时1000毫秒后,函数的运行就已经是在window对象下了,也就是函数的调用者已经变成了window对象,所以其中的this则指向的全局window对象;
而在 setInterval('obj.fun()',1000)
中的第一个参数,实际则是传入的一段可执行的 JS 代码;1000毫秒后当 JS 引擎来执行这段代码时,则是通过 obj 对象来找到 fun 函数并调用执行,那么函数的运行环境依然在 对象 obj 内,所以函数内部的this也就指向了 obj 对象;
6.apply、call调用
apply方法和call方法都是函数非继承而来的方法,这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的this对象的值。apply() 方法接收两个参数:一个是在其中运行函数的作用域,另一个是参数数组。其中,第二个参数可以是 Array 的实例,也可以是arguments对象。
call()方法与apply()方法的作用相同,区别是第二个传递给函数的参数必须是一一列举出来。(对于this的指向问题,只要记住一点,this值指向该方法的第一个参数就可以了,语法就这样规定)
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
test.apply(obj,[0])//this指向obj
复制代码
var x = 0;
function test() {
console.log(this.x);
}
var obj = {};
obj.x = 1;
test.call(obj,0,1,2)//this指向obj
复制代码
7.bind调用
这个方法会创建一个函数的实例,其 this 值会被绑定到传给 bind() 函数的值。也就是他会返回一个函数。
window.color = "red";
var o = { color: "blue" };
function test(){
alert(this.color);
}
var obj = test.bind(o);//this指向o
obj(); //blue
复制代码
apply、call、bind 的区别
apply、call的作用一样,只是第二个参数传递方式不同,apply要求是数组形式,call要求是将参数一一列举出来, apply和call都是改变this的指向后就执行函数,而bind是改变this指向后返回一个函数,您得手动再执行这个函数
结尾
本文参考阮一峰的this指向文章,以及通读了数篇关于this指向的问题,形成自己的理解,对于有关摘录部分也做了原文链接说明,如有纰漏,欢迎指正。