javascript 中经典的call 、apply、bind方法以及this指向详解

前言

一说到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指向的问题,形成自己的理解,对于有关摘录部分也做了原文链接说明,如有纰漏,欢迎指正。

转载于:https://juejin.im/post/5cb1ef0b6fb9a068646c098f

你可能感兴趣的:(javascript 中经典的call 、apply、bind方法以及this指向详解)