this绑定与call、apply以及bind详解

        在JavaScript中this的概念较为抽象,一共可以分为五种场景:

  1. 默认绑定
  2. 隐式绑定
  3. 显式绑定
  4. new绑定
  5. 箭头函数绑定

        先讲一下this的概念吧,this实际上是在函数被调用的时候才发生的绑定,也就是说this具体指向什么,取决于你怎么调用函数

        而apply和call是属于函数应用,指定this的同时也执行方法,bind则不同,它只是负责绑定this并返回一个新的方法,不会执行,所以我们经常看到bind后面会加一个()。

        先就解释这么多,正文开始。


this的默认绑定

        这么说,在函数调用没有任何前缀的时候,就属于this默认绑定。

        在非严格模式时,默认绑定this指向全局对象。

function fn3() {
    console.log(this); //window
};

f3();

        在这段代码中,函数调用没有任何前缀,没有指定任何对象,那么this指向全局对象window。

        注意:在严格模式下,默认绑定的this指向undefined,一试便知:

function fn1() {
    console.log(this); //window
};
function fn2() {
    "use strict";
    console.log(this); //undefined
};
fn1(); 
fn2();

        上面这个例子是在fn2的本地执行上下文里面使用"use strict",如果说是fn2函数外面使用严格模式将函数包裹住,那么与使用在里面的效果是相同的。

        但是要注意,比如一个函数里是设置了严格模式,另外一个函数没有设置,在已经设置了严格模式的函数里面调用了没有严格化的函数,那么并不会影响这个被调用函数的this指向。


this的隐式绑定

        在函数被调用之前,如果前面存在调用它的对象,那么this就会隐式绑定到这个对象上。

function fo() {
    console.log(this.name);
};
let obj = {
    name: 'henu_GM',
    fo: fo
};
obj.fo();

        如果函数调用前存在多个对象,那么this指向距离自己调用最近的对象,采取就近原则

function fo() { 
    console.log( this.a );
}
var a = 7;
var obj1 = { 
    a: 4,
    fo: fo
};
var obj2 = { 
    a: 3,
    obj1: obj1
};
obj2.obj1.fo(); //4

        注意,在特定情况下会发生隐式绑定丢失的问题,其中最主要的两个问题,一,将含this的函数作为参数传递给了另一个函数,这里的this并没有与之前那个函数绑定,而是与调用之前那个函数的对象隐式绑定,所以这里this脱离了绑定对象,this指向window;二,对已经隐式绑定了的函数进行变量赋值,在用新的变量调用这个函数,也会造成this指向window。

        就这么说吧,把函数作为参数进行传递给其他函数或者对象,如果接收的是一个新的对象,那么这个函数的this就指向新的对象,如果接收的是函数一类的,那么就直接指向window,很清楚了吧。


this的显式绑定

        显式绑定不同于隐式,显式绑定是指我们通过call,apply以及bind方法改变this的行为。

        通俗来讲,call和appply让函数从被调用变为主动选择自己的上下文,称为函数应用。

        需要注意的是,无论是call还是apply,亦或是bind,如果选择的参数是undefined或者null那么this将指向全局变量。

        下文将具体讨论call,apply以及bind对于this指向的作用。


this的new绑定

        JavaScript中的构造函数相信都不陌生,它只是使用new调用的一个普通函数,而并不是一个类,最终返回的对象也不是一个实例。

        那么new一个函数究竟发生了什么:

  1. 以构造器的prototype属性为原型,创建对象。
  2. 将this和调用参数传给构造器。
  3. 如果构造器没有手动返回对象,则返回第一步创建的对象。

        则叫做,构造调用

        那么就可以这么理解,this的new绑定无非是创建一个对象是要调用的一个函数,而这个要使用到的构造函数的this在调用的过程中指向发起这次构造的对象,这就是this的new绑定了。


箭头函数的this绑定

        箭头函数ES6新增的属性,箭头函数中没有this,箭头函数的this指向外层作用域中的this,外层作用域或者函数的this指向谁,箭头函数中的this就指向谁

        这一点就很方便了,一般来说,在内层的函数我们并不希望它拥有自己的this,直接指向外侧作用域极其方便。

        有一点要注意,this的绑定类似于bind的硬绑定(call和apply失效),就是说,一旦箭头函数的this绑定成功,就无法被再次改变,不过如果我们曲线救国的话,我们可以直接改变箭头函数的外层作用域的this指向,也成。


this五种绑定方法的优先级

        显式绑定 > 隐式绑定 > 默认绑定

        new绑定 > 隐式绑定 > 默认绑定

        据说new绑定是优先于显示绑定的,我试了一下,发现new的使用和显示绑定完全不在一个场景,不能判断它俩的优先级。


call与apply

        上文我说过了,call和apply的应用属于函数应用,为函数较为主动的行为。

        在call方法中,第一个参数是选择的上下文,用来绑定this,其他的参数在函数执行时都会作为函数的形参传入函数。

        而apply与call不同,除了第一个this绑定的参数以外,其他的参数都被包裹在一个数组中,在函数执行时作为一个数组整体传入。

        除此之外,效果完全相同。


bind

        call与apply在改变this指向的同时就会立即执行函数,而bind绑定this后不会立马执行,而是返回一个新的绑定函数。

let o = {
    a: 1
};
function fn(b, c) {
    console.log(this.a + b + c);
};
let fn1 = fn.bind(o, 2, 3);
fn1();//6

        除此之外,bind属于硬绑定,也就是说,this指向与传进去的形参在bind方法执行的时候就已经确定了,无法再次改变,再运行这个函数,就相当于无参。


        这三种方法用处很大,比如,我们知道的Math.max函数是无法传入数组的,而如果使用apply,则可以变相将数组作为形参传入这个方法里面去,岂不妙。

        好了,this的绑定基本就是这些,还有就是作用域链和原型链不太清楚,call,apply和bind也都是很好理解,那么,完结撒花。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

henuGM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值