详解JavaScript中的this硬绑定

 更新时间:2022年10月08日 15:34:26   作者:墨戈  
这篇文章主要为大家详细介绍了JavaScript中的this显示绑定和硬绑定,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以了解一下

一、this显示绑定

this显示绑定,顾名思义,它有别于this的隐式绑定,而隐式绑定必须要求一个对象内部包含一个指向某个函数的属性(或者某个对象或者上下文包含一个函数调用位置),并通过这个属性间接调用这个函数,从而把this简介/隐式绑定到这个对象上。但是this的隐式绑定存在一个绑定对象丢失问题,如下面代码所示:

function afun() {
    console.log(this.a);
}

var obj = {
    a: 1,
    afun: afun
};

var a = "hello";

setTimeout(obj.afun, 100);//"hello"

出人意料的是,控制台打印出来的结果是全局变量a的结果,而不是拥有指向函数属性的对象的a的值,这就是隐式绑定的对象丢失,回调函数丢失绑定对象是非常常见的。

但是,显示绑定仍然不能解决绑定对象丢失的问题,但是显示绑定的一个变种,即硬绑定可以解决绑定对象丢失。

在此之前,我们先来看看什么是显示绑定。

我们可以通过使用函数的call()和apply()方法实现this显示绑定,绝大多数内置函数和自定义函数都可以调用这两种方法。他们均接收两个参数

参数:

thisArg: 要绑定到调用者this的对象。

arg1, arg2, ...(call):指定的参数列表,即要传给调用者的参数。比如a.call(obj, args)/a.apply(obj, args),args为参数传给调用者函数a作为该函数的实参。

argsArray(apply):一个数组或者类数组对象,如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。

返回值:调用者函数若有返回值则返回该值,没有返回值则返回undefined。

来看下面的代码:

function bfun() {
    return this.a;
}

var obj1 = {
    a: "hello"
};

console.log(bfun.apply(obj1), bfun.call(obj1));//"hello" "hello"

若传入的第一个参数时一个原始值呢?来看下面的代码:

function bfun() {
    return this;
}


console.log(bfun.apply(3));//[Number: 2]

没错,原始值被转换成了它的对象形式,也就是new Number(),这被成为"装箱"。

但是,我们前面提到过,this显示绑定虽然强大,但是仍然不能解决this绑定丢失问题。下面我们来解释硬绑定,即显示绑定的一个变种,它能完美解决this绑定丢失问题。

二、硬绑定

先来看看下面的代码:

function cfun() {
    console.log(this.a)//"hello"
    return this.a;
}

var obj2 = {
    a: "hello"
};

var fn = function() {
    return cfun.apply(obj2);
};
console.log(fn());//"hello"

setTimeout(fn, 100);//"hello"

可以看到,硬绑定确实解决了this绑定丢失,但值得注意的是,通过apply()绑定的this对象,无法二次更改绑定对象:

function f() {
console.log( this.a );
}
var obj = {
a:2
};
var b = function() {
f.call( obj );
};
b(); // 2

b.call( window ); // 2

硬绑定的一个典型应用场景是创建一个包裹函数,传入所有的参数给调用者函数并返回接收到的所有值。

function dfun(v) {
    return (v[0] + this.a);
}

var obj3 = {
    a: 10
};

var fn1 = function() {
    return dfun.call(obj3, arguments);
}

var result = fn1(6);
console.log(result);//16

对于arguments而言,call()和apply()的不同之处在于他们的参数类型不同:

function efun(v) {
    console.log(..v)//6 10 11
    return (v);
}

var obj4 = {
    a: 10
};

var fn1 = function() {
    return efun.apply(obj3, arguments);
}

var result = fn1([6, 10, 11]);
console.log(result);//[6, 10, 11]

也就是说call()的参数类型是Object,它传入的参数列表会被转换为键为'0'(随传入参数数量递增),值为传入参数的对象;而apply()的参数类型则是数组或者类数组。

function dfun(v) {
    return (v);
}

var obj3 = {
    a: 10
};

var fn1 = function() {
    return dfun.call(obj3, arguments);
}

var result = fn1(6, 19, 1, 1);
console.log(result);//[Arguments]{'0':6,'1':19,2':1,3':1}
console.log(typeof result);//'object'

最强大的一种方法是将包裹函数创建为可以重复使用的辅助函数,封装可重复使用的硬绑定。

function ffun(v) {
    return this.a * v;
}

var obj5 = {
    a: 5,
};

var fn2 = function(fn, obj) {
    return function() {
        return fn.apply(obj, arguments);
    }
}

var bind = fn2(ffun, obj5);
console.log(bind(10));//50

由于硬绑定十分常用,但通过包裹函数创建可重复使用的硬绑定比较麻烦,所以ES5提供了一个实现相同功能的方法bind()。用法如下:

function hfun(v) {
    return this.a * v;
}

var obj6 = {
    a: 6
};

var bind = hfun.bind(obj6);
console.log(bind(4));//24

可以看到,我们再无需构建一个包裹函数来手动调用call或apply方法,只需要提供调用者和绑定到调用者this的对象即可。

我们可能发现了一个奇怪的现象,通过apply()和call()方法绑定的对象在传参给调用者时,需要设置一个参数占位,但bind()方法则不用,这是因为他们的返回值不同,bind()方法会返回一个经过硬编码的新函数,它会把传入参数设置为this的上下文并调用原始函数。可以理解bind使用方法为bind(obj)(args)。而对于call()和apply()方法而言,一旦调用此方法,就会立刻返回调用者函数的返回值,所以此时就需要同时传入参数给方法的参数占用符,然后被函数参数读取。值得注意的是,bind方法的参数和call方法类似。

到此这篇关于详解JavaScript中的this硬绑定 的文章就介绍到这了,更多相关JavaScript this硬绑定 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JS 中使用Promise 实现红绿灯实例代码(demo)

    JS 中使用Promise 实现红绿灯实例代码(demo)

    本文通过实例代码给大家介绍了JS 中使用Promise 实现红绿灯效果,在文中给大家介绍了一个promise用法例子,需要的朋友可以参考下
    2017-10-10
  • 在IE8上JS实现combobox支持拼音检索功能

    在IE8上JS实现combobox支持拼音检索功能

    这篇文章主要介绍了在IE8上JS实现combobox支持拼音检索功能的相关资料,本文介绍的非常详细,具有参考借鉴价值,需要的朋友可以参考下
    2016-05-05
  • js实现无缝轮播图特效

    js实现无缝轮播图特效

    这篇文章主要为大家详细介绍了js实现无缝轮播图,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • 使用Echarts绘制动态排序折线图

    使用Echarts绘制动态排序折线图

    Echarts,作为一个使用广泛的JavaScript图表库,提供了创建动态排序折线图的强大功能,下面就跟随小编一起学习一下如何使用Echarts绘制动态排序折线图吧
    2023-12-12
  • webpack学习笔记之优化缓存、合并、懒加载

    webpack学习笔记之优化缓存、合并、懒加载

    这篇文章主要介绍了webpack学习笔记之优化缓存、合并、懒加载,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-08-08
  • 常用JS代码实例小结

    常用JS代码实例小结

    跟网上的一些常用的不太一样,个人都有个人常用的代码,大家看到好东西,不一定什么都会,起码要知道有这么个东西。方便以后用也方便找。
    2009-04-04
  • javascript 随机展示头像实现代码

    javascript 随机展示头像实现代码

    随机展示小头像,随机数包括 位置、层级、大小、透明度 等
    2011-12-12
  • JavaScript中函数(Function)的apply与call理解

    JavaScript中函数(Function)的apply与call理解

    这篇文章主要介绍了JavaScript中函数(Function)的apply与call理解,本文讲解了JavaScript函数调用分为4中模式以及通过apply和call实现扩展和继承两方面,需要的朋友可以参考下
    2015-07-07
  • Javascript中的奇葩知识,你知道吗?

    Javascript中的奇葩知识,你知道吗?

    这篇文章主要介绍了一些Javascript中的奇葩知识,帮助大家更好的理解和使用JavaScript,感兴趣的朋友可以了解下
    2021-01-01
  • js校验开始时间和结束时间

    js校验开始时间和结束时间

    这篇文章主要为大家详细介绍了js校验开始结束时间,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05

最新评论