深入call apply bind

栏目: JavaScript · 发布时间: 5年前

内容简介:稍微翻了一下call,apply, bind 的各种论坛上的文章, 发现讲的都太浅了,大部分都只讲了个用法, 对于实现的原理却都没有提,因此,在这里,我写下这篇文章, 希望能让大家认识到原理所在。众所周知, 这三个函数都是改变执行上下文的 , 那么我们来捋一捋,这些函数内部到底做了什么。Function是函数对象的构造方法,call,apply,bind 都是函数原型上的方法 作为实例 他自身也有这三个方法

前言

稍微翻了一下call,apply, bind 的各种论坛上的文章, 发现讲的都太浅了,大部分都只讲了个用法, 对于实现的原理却都没有提,因此,在这里,我写下这篇文章, 希望能让大家认识到原理所在。

众所周知, 这三个函数都是改变执行上下文的 , 那么我们来捋一捋,这些函数内部到底做了什么。

call

Function是函数对象的构造方法,call,apply,bind 都是函数原型上的方法 作为实例 他自身也有这三个方法

深入call apply bind

圈中的为原型方法, 方块的为实例方法,另外length属性就是argument的长度,我们通常调用一个函数

function a(){ console.log(this,'a')};
function b(b){console.log(b)}
a.call(b,'我是B的参数')

深入call apply bind

执行a, 并把context指向b, 这里大家都没有疑问, 那么问题来了

function a(){ console.log(this,'a')};
function b(){console.log(this,'b')}
a.call.call.call(b,'b')  // 这个结果是什么呢?
答案是

深入call apply bind

傻眼了吧 ? 怎么执行了B 并且this指向了这个 b字符串

我们来分析一下 call是原型上的方法 那么a.call 他本身也是一个函数 所以a.call.call.call 不就是a.call.call的原型上的call方法么?

所以不就是执行call.call 并改变 call.call的上下文

我们来撸一遍call的源码,

深入call apply bind

第一个参数是上下文, 当我们call(null),this指向了window 当我们传入字符串 会把字符串包装成对象

a.call 执行 this是指向a的(谁调用this 指向谁) 然后又执行了a方法,所以内部是

Function.prototype.call = function(context){
    context = context ? Object(context):window
    this()   // 因为调用的都是函数 所以this是一个函数 也就是a
}

那这样并未改变this指向啊,咋办? 上句话不是说((谁调用this 指向谁)),所以我们要在内部改变掉this,做如下修改

Function.prototype.call = function(context){
    context = context ? Object(context):window
    context.fn = this  
    context.fn() // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
}

那么参数怎么传呢,我们首先要拿到call的里的参数

Function.prototype.call = function(context,...args){
    context = context ? Object(context):window
    context.fn = this  
    let r = context.fn(...args) // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
    delete context.fn   //删除属性
    return r  // 返回执行的结果 
}

现在我们回头分析一下a.call.call.call(b,'b')

a.call.call是个函数,它调用call方法 执行它 我们进入函数里面看看

首先把context 也就是b转为字符串对象 它的属性上赋予fn 也就是a.call.call ,然后执行context.fn(...args), 也就是a.call.call('b') 接着删除fn 返回执行结果 宏观来看 是a.call.call这个函数去执行并传入('b') a.call.call 也就是Function.prototype.call 所以就是call('b') 所以啊, 结果才是this是指向string的b 并且参数是undefined

Function.prototype.call = function(context,...args){
    context = context ? Object(context):window 
    context.fn = this  //a.call.call('b')
    var r = context.fn(...args) // 通过调用context.fn 来改变调用者 实现fn的this指向context 即改变a内部的this
    delete context.fn
    return r
}


function a(){ console.log(this,'a')};
function b(args){console.log('我是this:' + this,'我是b的参数args:' + args)}
a.call.call.call(b,'我到底是参数呢还是this')

深入call apply bind

结论!

一个函数call2次或者2次以上 执行的永远是b, 并且call的第二个参数成为当前context

apply

apply 就是参数不同 直接上代码

Function.prototype.apply = function(context,...args){
    context = context ? Object(context):window 
    context.fn = this;
    var r; 
    if(args.length){
        r = context.fn(...args) 
        delete context.fn
    }else{
        r = context.fn()
    }
    return r
}


function a(args){ console.log(this,args)};
function b(){console.log('我是this:' + this)}
a.apply(b,[1,2,3,4])

深入call apply bind

bind 明天写 累了


以上所述就是小编给大家介绍的《深入call apply bind》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

当下的启蒙

当下的启蒙

[美] 史迪芬·平克 / 侯新智、欧阳明亮、魏薇 / 浙江人民出版社 / 2018-12 / 159.90

[编辑推荐] ● 比尔•盖茨最喜爱的一本书。理查德·道金斯心中的诺贝尔文学奖作品。尤瓦尔•赫拉利2018年最爱的书之一。 ● 当代最伟大思想家史蒂芬·平克全面超越自我的巅峰之作,一部关于人类进步的英雄史诗。 ●《当下的启蒙》用数据和事实揭示出世界的真相:不是黑暗,而是光明;不是丧,而是燃;我们没有退步,而是一直在进步,还将继续进步。用这本书点燃生活的勇气,亲手创造更美好的未来。 ......一起来看看 《当下的启蒙》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具