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. 强大的display:grid

    自从用习惯flex布局我基本已经不怎么使用float了. 现在又出现了grid布局,就像flex的升级版,布局上十分强大. 主要属性: grid-template-columns://竖向排列 gri ...

  2. PostgreSQL SERIAL创建自增列

    PostgreSQL SERIAL创建自增列 本文我们介绍PostgreSQL SERIAL,并展示如何使用serial类型创建表自增列. PostgreSQL SERIAL伪类型 PostgreSQ ...

  3. [AIR] NativeExtension在IOS下的开发实例 --- 新建项目测试ANE(四)

    来源:http://bbs.9ria.com/thread-102043-1-1.html 通过前面的努力,好了,我们终于得到了一个ANE文件了.下面我们开始新建一个Flex Mobile项目做一下测 ...

  4. python中的debug

    python中有很多的debug方法,大部分新人忽略了Python debugger(pdb)的重要性. 1.命令行运行 在终端中输入命令行   python -m pdb helloword.py ...

  5. MySQL Hardware--RAID卡BBU Learn Cycle

    RAID卡缓存策略 不同的RAID卡缓存策略对IO的性能影响较大,常见的策略有: 1.写操作策略,可设置为WriteBack或WriteThrough WriteBack:进行写操作时,将数据写入RA ...

  6. 迷你商城后台管理系统————stage2核心代码实现

    应用程序主函数接口 @SpringBootApplication(scanBasePackages = {"org.linlinjava.litemall.db", "o ...

  7. SHELL脚本编程基础知识

    SHELL脚本编程基础知识 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. Linux之父Linus有一句话很经典:"Talk is cheap, show me the ...

  8. typescript 参数类型

    1.参数类型:在参数名称后面使用冒号来指定参数的类型 var myname:string = 'wzn' => "use strict"; var myname = 'wzn ...

  9. IDEA实用教程(十)—— 配置Maven的全局设置

    使用之前需要提前安装好Maven 第一步 第二步

  10. bcb中TParamter传NULL值

    if (status_Desc.IsEmpty()) Queue_Status->Value = Null(); else Queue_Status->Value = status_Des ...