1.Function.apply.bind(…)

我在学习promise部分的时候遇到了这样的代码:

Promise.resolve([10,20]).then(Function.apply.bind(function(x, y){
console.log(x, y);
}, null)); // 10,20

看到这里我已经蒙圈了,Function.apply.bind(…)是个什么操作?可能很多人和我一样之前只接触过Function.bind.apply(…)。

于是查了一下文档,大致明白了其中的含义。先撇开Promise不谈,直接来看Function.apply.bind(…):

var sum = function(x, y) {
console.log(x, y);
}
var foo = Function.apply.bind(sum, null);
foo([10, 20]); // 10, 20

这里我们有一个函数sum,通过Function.apply.bind(sum, null)我们创建了一个新的函数foo(…)。

我们一步步分析Function.apply.bind(sum, null)这段代码。
sum.apply(null, [10, 20])这句代码将第一个参数置为null,第二个参数是一个数组,用于拆开后作为sum的最终参数。
熟悉sum.apply(…)方法的朋友一定知道,如果将sum.apply(…)的第一个参数设置为null,那么就意味着我们并不关心sum在执行时其内部的this指向谁。而Function.apply.bind(sum, null)目的就是将sum.apply(…)的第一个参数固定为null(其中,Function.apply.bind(sum, null)等价于sum.apply.bind(sum, null))。

所以最终我们得到的foo函数就是sum.apply(null, [10, 20]); [10,20]会拆开成10和20传递给sum(…)。

那么我们再回到最开始的那个Promise的例子,传递给.then()的Promise决议值就是数组[10,20],.then函数的第一个参数(通常我们称之为fulfilled(…)函数)就相当于我们刚才创建的foo(…),执行foo([10, 20])输出结果就是10,20。

2.Function.bind.apply(…)
那么类似的问题就还剩Function.bind.apply(…)。

我第一次见到这样的代码是在《你不知道的JS》中卷的2.4小节。讲回调的时候。针对回调的调用过早的问题,有经验的开发者们给出了这样的解决方式(当然ES6之后解决回调函数调用过早的问题还是倾向于借助Promise机制):

function asyncify(fn) {
var orig_fn = fn,
intv = setTimeout( function(){
intv = null;
if (fn) fn();
}, 0 )
; fn = null; return function() {
// 触发太快,在定时器intv触发指示异步转换发生之前?
if (intv) {
fn = orig_fn.bind.apply(
orig_fn,
// 将包装函数的`this`加入`bind(..)`调用的
// 参数,同时currying其他所有的传入参数
[this].concat( [].slice.call( arguments ) )
);
}
// 说明没有过早触发,这里已经是异步
else {
// 调用原来的函数
orig_fn.apply( this, arguments );
}
};
}

和前面类似,我们将orig_fn.bind.apply(orig_fn, args)拆成两部分来看:函数orig_fn.bind(…)和.apply(orig_fn, args)。根据.apply(…)的定义,orig_fn.bind.apply(orig_fn, args)其实就意味着我们将orig_fn.bind(…)函数的this指向orig_fn,然后.apply(orig_fn, args)的第二个参数会将剩下的参数传递给orig_fn.bind(…)函数。

那么我们现在分析一下剩下的参数([this].concat( [].slice.call( arguments ))都是什么吧,首先arguments是外界传入的其余参数(return function(…)这个函数传入的参数),接下来我们借助[].slice.call( arguments )将其转化为一个参数数组,备用。由于.bind(…)的第一个参数为在 origin_fn 调用中用到的 this (我们在前一段就已经提到过,这个this其实就指向orig_fn),所以使用 [this] 将构造的参数数组中的第一个参数设置为 this 。[this]再与我们前面的备用数组拼接起来,一同传递给.bind(…)。

此时,.bind(…)的第一个参数就是this,剩余参数就是外界传入的参数。所以,除了传递给orig_fn.bind(…)的第一个参数this,其余的参数都会作为柯里化参数(预设值)。

在这里的关键点是:.bind(…) 函数是通过 .apply(…) 调用的,所以 .bind(…) 自身所需要的 this 对象是一个函数(函数也是对象,在这里即 origin_fn)。
---------------------
版权声明:本文为CSDN博主「Typhoonnnnn」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_37787381/article/details/81509361

Function.apply.bind()与Function.apply.bind()的更多相关文章

  1. JavaScript的函数call和apply的区别、以及bind方法

    1.call和apply的定义和区别 call和apply的作用一样,唯一不同的是:接受的参数不同. apply:方法能够劫持另一个对象的方法,继承另一个对象的属性. Funciton.apply(o ...

  2. JavaScript中的bind,call和apply函数的用法和区别

    一直没怎么使用过JavaScript中的bind,call和apply, 今天看到一篇比较好的文章,觉得讲的比较透彻,所以记录和总结如下 首先要理解的第一个概念,JavaScript中函数调用的方式, ...

  3. Function.prototype.call 和 Function.prototype.apply 的区别

    call和apply函数是function函数的基本属性,都可以用于更改函数对象和传递参数,是前端工程师常用的函数.具体使用方法请参考以下案列: 例如: 申明函数: var fn = function ...

  4. jquery阻止冒泡事件:$('span').bind("click",function(event){event.stopPropagation();})(有用源)

    冒泡事件就是点击子节点,会向上触发父节点,祖先节点的点击事件. <body> <div id="content"> 外层div元素 <span> ...

  5. boost bind及function的简单实现

    前面在做 http server 的时候,需要做一个回调的接口,要求能够绑定类的函数以及普通的函数到这个回调里,对于这种应用要求,选择 boost 的 bind 和 function 是最合适不过了, ...

  6. bind(),call(), apply()方法的区别是什么?

    bind(),call(), apply()方法的区别是什么? 共同点:改变this指向,任何调用都不在起作用 bind() 改变this的指向,不会调用函数,返回一个新的函数 var o ={a:' ...

  7. C++11 bind和function用法

    function是一个template,定义于头文件functional中.通过function<int(int, int)> 声明一个function类型,它是“接受两个int参数.返回 ...

  8. 基于boost的bind与function的一个简单示例消息处理框架

    前两年开始接触boost,boost库真是博大精深:今天简单介绍一下boost中之前用到的的bind与function,感觉挺实用的,分享给大家,我对boost用的也不多,让大家见笑了. 上次文发了一 ...

  9. C++11绑定器bind及function机制

    前言 之前在学muduo网络库时,看到陈硕以基于对象编程的方式,大量使用boost库中的bind和function机制,如今,这些概念都已引入至C++11,包含在头文件<functional&g ...

随机推荐

  1. 【转载】使用Winrar对压缩文件进行加密,并且给定解压密码

    有时候我们从网上下载的压缩包文件,如.rar文件.zip文件等,解压的时候需要输入解压密码才可顺利解压,否则解压失败.其实像这种情况,是压缩包制作者在压缩文件的时候对压缩文件进行了加密,输入了压缩包解 ...

  2. 二十二、mysql索引原理详解

    背景 使用mysql最多的就是查询,我们迫切的希望mysql能查询的更快一些,我们经常用到的查询有: 按照id查询唯一一条记录 按照某些个字段查询对应的记录 查找某个范围的所有记录(between a ...

  3. Python学习日记(五) 编码基础

    初始编码 ASCII最开始为7位,一共128字符.最后确定8位,一共256个字符,最左边的为拓展位,为以后的开发做准备. ASCII码的最左边的一位为0. 基本换算:8位(bit) = 1字节(byt ...

  4. Python学习日记(二) list操作

    l = ['a','b','c','d',1,2,[3,'e',4]] 1.list.append() 在list的结尾新增一个新的元素,没有返回值,但会修改原列表 l.append(5) print ...

  5. Spring Boot 笔记 (8) - H2 数据库

    Maven 依赖 <dependency> <groupId>com.h2database</groupId> <artifactId>h2</a ...

  6. error 106: Can't Access ASP.NET\ClientFiles\

    Error 1606 Can’t access ASP.NET\ClientFiles\ when installing Crystal Reports Support Pack 10     Sea ...

  7. linux 的常用命令(1)

    1.关于ls [选项][目录名] -a  列出包括.a开头的隐藏文件的所有文件-A  通-a,但不列出"."和".."-l  列出文件的详细信息-c  根据ct ...

  8. python中的logging日志模块

    日志是程序不可或缺的一部分.它可以记录程序的运行情况,帮助我们更便捷地发现问题,而python中的logging日志模块给我们提供了这个机会. logging给我们提供了五种函数用来输出日志:debu ...

  9. jquery手机触屏滑动拼音字母城市选择器代码

    今天用到城市选择,直接用拼音滑动方式来选择,用的时候引入jquery(个别样式需要自己修改) <div class="yp_indz"><img src=&quo ...

  10. IList<> IEnumerable<> ReadOnlyCollection<> 使用方向

    无论你把它声明为IList<string>,IEnumerable<string>,ReadOnlyCollection<string>或别的东西,是你...... ...