最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • call, call.call, call.call.call, 你也许还不懂这疯狂的call

    正文概述 掘金(云的世界)   2021-08-24   623

    这是我参与8月更文挑战的第24天,活动详情查看:8月更文挑战。

    前言

    Function.prototype.call 我想大家都觉得自己很熟悉了,手写也没问题!!
    你确认这个问题之前, 首先看看 三千文字,也没写好 Function.prototype.call,

    看完,你感觉还OK,那么再看一道题:
    请问如下的输出结果

    function a(){ 
        console.log(this,'a')
    };
    function b(){
        console.log(this,'b')
    }
    a.call.call(b,'b')  
    

    如果,你也清晰的知道,结果,对不起,大佬, 打扰了,我错了!

    本文起源:
    一个掘友加我微信,私聊问我这个问题,研究后,又请教了 阿宝哥
    觉得甚有意思,遂与大家分享!

    结果

    结果如下: 惊喜还是意外,还是淡定呢?

    String {"b"} "b"
    

    再看看如下的代码:2个,3个,4个,更多个的call,输出都会是String {"b"} "b"

    function a(){ 
        console.log(this,'a')
    };
    function b(){
        console.log(this,'b')
    }
    a.call.call(b,'b')  // String {"b"} "b"
    a.call.call.call(b,'b')   // String {"b"} "b"
    a.call.call.call.call(b,'b')  // String {"b"} "b"
    

    看完上面,应该有三个疑问?

    1. 为什么被调用的是b函数
    2. 为什么thisString {"b"}
    3. 为什么 2, 3, 4个call的结果一样

    结论:
    两个以上的call,比如call.call(b, 'b'),你就简单理解为用 b.call('b')

    分析

    为什么 2, 3, 4个call的结果一样

    a.call(b) 最终被调用的是a,
    a.call.call(b), 最终被调用的 a.call
    a.call.call.call(b), 最终被执行的 a.call.call

    看一下引用关系

    a.call === Function.protype.call  // true
    a.call === a.call.call  // true
    a.call === a.call.call.call  // true
    

    基于上述执行分析:
    a.call 被调用的是a
    a.call.calla.call.call.call 本质没啥区别, 被调用的都是Function.prototype.call

    为什么 2, 3, 4个call的结果一样,到此已经真相

    为什么被调用的是b函数

    看本质就要返璞归真,ES 标准对 Funtion.prototye.call 的描述

    中文翻译一下

    1. 如果不可调用,抛出异常
    2. 准备一个argList空数组变量
    3. 把第一个之后的变量按照顺序添加到argList
    4. 返回 Call(functhisArgargList)的结果

    这里的Call只不是是一个抽象的定义, 实际上是调用函数内部 [[Call]] 的方法, 其也没有暴露更多的有用的信息。

    实际上在这里,我已经停止了思考:

    a is a function, then what a.call.call really do? 一文的解释,有提到 Bound Function Exotic Objects , MDN的 Function.prototype.bind 也有提到:

    Function.prototype.call 相反,并没有提及!!! 但不排查在调用过程中有生成。

    Difference between Function.call, Function.prototype.call, Function.prototype.call.call and Function.prototype.call.call.call 一文的解释,我觉得是比较合理的

    function my(p) { console.log(p) }
    Function.prototype.call.call(my, this, "Hello"); // output 'Hello'
    

    重点标出:
    So, Function.prototype.call would be called with my as its context. Which basically means - it would be the function to be invoked.

    It would be called with the following arguments: (this, "Hello"), where this is the context to be set inside the function to be called (in this case it's my), and the only argument to be passed is "Hello" string

    翻译一下:
    Function.prototype.call.call(my, this, "Hello")表示: 用my作为上下文调用Function.prototype.call,也就是说my是最终被调用的函数。

    my带着这些 (this, "Hello") 被调用, this 作为被调用函数的上下文,此处是作为my函数的上下文, 唯一被传递的参数是 "hello"字符串。

    基于这个理解, 我们简单验证一下, 确实是这样的表象

    // case 1:
    function my(p) { console.log(p) }
    Function.prototype.call.call(my, this, "Hello"); // output 'Hello'
    
    // case 2:
    function a(){ 
        console.log(this,'a')
    };
    function b(){
        console.log(this,'b')
    }
    a.call.call(b,'b')  // String {"b"} "b"
    

    为什么被调用的是b函数, 到此也真相了。

    其实我依旧不能太释怀, 但是这个解释可以接受,表象也是正确的, 期望掘友们有更合理,更详细的解答。

    为什么thisString {"b"}

    在上一节的分析中,我故意遗漏了Function.prototype.call的两个note

    注意这一句:

    两点:

    1. 如果thisArgundefined 或者null, 会用global object替换

    这里的前提是 非严格模式

    "use strict"
    
    function a(m){
        console.log(this, m);  // undefined, 1
    }
    
    a.call(undefined, 1)
    
    1. 其他的所有类型,都会调用 ToObject进行转换

    所以非严格模式下, this肯定是个对象, 看下面的代码:

    Object('b') // String {"b"}
    

    note2的 ToObject 就是答案

    到此, 为什么thisSting(b) 这个也真相了

    万能的函数调用方法

    基于Function.prototype.call.call的特性,我们可以封装一个万能函数调用方法

    var call = Function.prototype.call.call.bind(Function.prototype.call);
    

    示例

    var person = {
        hello() { 
            console.log('hello', this.name) 
        }
    }
    
    call(person.hello, {"name": "tom"})  // hello tom
    

    写在最后

    如果你觉得不错,你的一赞一评就是我前行的最大动力。

    技术交流群请到 这里来。 或者添加我的微信 dirge-cloud,一起学习。

    引用


    起源地下载网 » call, call.call, call.call.call, 你也许还不懂这疯狂的call

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元