zoukankan      html  css  js  c++  java
  • Function.apply.bind()与Function.apply.bind()

    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

  • 相关阅读:
    【自动化学习】自动化误区
    【uwsgi】Mac下python dyld :Library not loaded 问题解决
    【Mysql】Mac版本navicat premium彻底卸载的终端命令:
    【Mysql学习】锁
    【Pytest学习】重复执行用例插件之pytestrepeat的详细使用
    【Python学习】异常传递
    【Jenkins学习】gitlab自动化触发jenkins任务
    一封程序员的情书
    UNION的使用
    为生成的新行添加默认值
  • 原文地址:https://www.cnblogs.com/cangqinglang/p/11351251.html
Copyright © 2011-2022 走看看