【JS010】bind、call和apply浅谈

日期:2021年8月18日
作者:Commas
注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方,还望各位大佬不吝赐教,谢谢^ - ^
(ง •_•)ง 积跬步以致千里,js的学习笔记
1.01365 = 37.7834;0.99365 = 0.0255
1.02365 = 1377.4083;0.98365 = 0.0006



一、bind、call和apply比较

作用:bindcallapply都是用于改变函数体内this的指向,即它们都是为了改变某个函数运行时的上下文而存在的;

比较内容bindcallapply
语法fn.bind(thisArg[, arg1[, arg2[, ...]]])fn.call(thisArg[, arg1[, arg2[, ...]]])fn.apply(thisArg, [argsArray])
第一个参数函数上下文的对象thisArg函数上下文的对象thisArg函数上下文的对象thisArg
剩下的参数可选,一个参数列表,而不是单个数组可选,一个参数列表,而不是单个数组可选,函数参数所组成的数组(Array)或伪数组(E6支持,ArrayLike类数组,)
执行情况返回新函数绑定函数返回函数执行结果返回函数执行结果

二、bind与call的比较

比较bindcall
语法fn.bind(thisArg[, arg1[, arg2[, ...]]])fn.call(thisArg[, arg1[, arg2[, ...]]])
相同点thisArg+参数列表(非数组)thisArg+参数列表(非数组)
不同点返回新函数体(绑定函数)返回函数执行结果

(2-1)bind

语法:fn.bind(thisArg[, arg1[, arg2[, ...]]])

  • bind方法第一个参数作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组,并且返回一个新的函数(绑定函数);

一个参数:

let walk = function(){
    return(`${this.name}:I can walk`);
};

//(1)dog
let dog = {name:"dog"};
let dogWalk = walk.bind(dog);
console.log(dogWalk);
//ƒ(){return(`${this.name}:I can walk`);}
console.log(dogWalk());
//控制台输出:dog:I can walk

//(2)cat
let cat = {name:"cat"};
let catWalk = walk.bind(cat);
console.log(catWalk);
//ƒ(){return(`${this.name}:I can walk`);}
console.log(catWalk());
//控制台输出:cat:I can walk

多个参数:

let add = function(x,y,z){
    console.log(arguments);
    return x+y+z;
};

//x,y,z三个参数,x的萝卜坑已经被bind中的10给占了
//剩余参数位置只有y,z
let sum = add.bind(null,10);

//(1)萝卜坑刚好填满;
console.log(sum(20,30));
//控制台输出:
//Arguments(3) [10, 20, 30, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

//(2)萝卜坑填满,多出的40只加入到arguments;
console.log(sum(20,30,40));
//控制台输出:
//Arguments(4) [10, 20, 30, 40, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

(2-2)call

语法:fn.call(thisArg[, arg1[, arg2[, ...]]])

  • call方法第一个参数作为函数上下文的对象,但是后面传入的是一个参数列表,而不是单个数组,并且返回函数的执行结果
  • 另一个值得注意的是,后面参数个数要与原函数个数一致,所谓的萝卜坑要一致,不然会出问题的

一个参数:

let walk = function(){
    return(`${this.name}:I can walk`);
};

//(1)dog
let dog = {name:"dog"};
let dogWalk = walk.call(dog);
console.log(dogWalk);
//控制台输出:dog:I can walk

//(2)cat
let cat = {name:"cat"};
let catWalk = walk.call(cat);
console.log(catWalk);
//控制台输出:cat:I can walk

多个参数:

let add = function(x,y,z){
    console.log(arguments);
    return x+y+z;
};

//(1)参数刚好
let sum1 = add.call(null,10,20,30);
console.log(sum1);
//控制台输出:
//Arguments(3) [10, 20, 30, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

//(2)多参数
let sum2 = add.call(null,10,20,30,40);
console.log(sum2);
//控制台输出:
//Arguments(4) [10, 20, 30, 40, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

//(3)少参数
let sum3 = add.call(null,10);
console.log(sum3);
//控制台输出:
//Arguments [10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//NaN

小结:当传递的参数较少的时候,
如果需要返回一个新函数,那么用bind
如果需要立即返回执行结果就,那么用call

三、call与apply的比较

比较callapply
语法fn.call(thisArg[, arg1[, arg2[, ...]]])fn.apply(thisArg, [argsArray])
相同点返回函数执行结果返回函数执行结果
不同点thisArg+参数列表(非数组)thisArg+数组(或类数组)

(3-1)call

语法:fn.call(thisArg[, arg1[, arg2[, ...]]])

  • 描述与示例等详情,可见上述的 (2-2)call 小节,此处不再赘述;

(3-2)apply

语法:fn.apply(thisArg, [argsArray])

  • apply方法传入两个参数:一个也是作为函数上下文的对象,另外一个是作为函数参数所组成的数组(ES6也支持伪代码,又称类数组,ArrayLike),并且返回函数的执行结果

一个参数:

//(1)dog
let dog = {name:"dog"};
let dogWalk = walk.apply(dog);
console.log(dogWalk);
//控制台输出:dog:I can walk

//(2)cat
let cat = {name:"cat"};
let catWalk = walk.apply(cat);
console.log(catWalk);
//控制台输出:cat:I can walk

多个参数:

let add = function(x,y,z){
    console.log(arguments);
    return x+y+z;
};

//(1)数组元素个数=原参数个数
let sum1 = add.apply(null,[10,20,30]);
console.log(sum1);
//控制台输出:
//Arguments(3) [10, 20, 30, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

//(2)数组元素个数>原参数个数
let sum2 = add.apply(null,[10,20,30,40]);
console.log(sum2);
//控制台输出:
//Arguments(4) [10, 20, 30, 40, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//60

//(3)数组元素个数<原参数个数
let sum3 = add.apply(null,[10]);
console.log(sum3);
//控制台输出:
//Arguments [10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
//NaN

小结:当需要立即返回函数执行结果的时候,
如果传递的参数少,那么用call
如果传递的参数多,或者已有对应的数组,那么用apply

四、解决低版本浏览器中未定义bind函数问题

if (!Function.prototype.bind) {
    Function.prototype.bind = function () {
        var self = this,                        // 保存原函数
            context = [].shift.call(arguments), // 保存需要绑定的this上下文
            args = [].slice.call(arguments);    // 剩余的参数转为数组

        // 返回一个新函数
		return function () {
            self.apply(context,
            	[].concat.call(args, [].slice.call(arguments))
            );
        };
    };
};

参考文章:
1、《JavaScript 中 apply 、call 的详解》
2、《call、apply、bind三者的用法和区别》
3、《bind、call、apply的区别与实现原理》
4、《javascript中call()、apply()、bind()的用法终于理解》


版权声明:本文为博主原创文章,如需转载,请给出:
原文链接:https://blog.csdn.net/qq_35844043/article/details/119778163

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Commas.KM

码路共同进步,感恩一路有您

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

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

打赏作者

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

抵扣说明:

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

余额充值