浅谈apply、call、bind及其ES6手写实现

apply、call、bind

Function.prototype上包含apply()call()bind()方法。

也就是说每个函数都包含这三个由原型上获得的方法。

apply

apply()方法接收两个参数:一个是在其中运行函数的作用域,另一个是数组,

这个数组也可以是类数组,比如arguments对象。

用法不赘述,只讲它的手写实现。

首先我们要搞清楚apply的作用是什么:

它改变了函数中的this指针指向

先看看它的参数,

  1. 一个运行函数的作用域
  • 这个作用域,就是用来改变我原本函数内的this指针,
    如果我传入一个obj作为第一个参数,那么就是把this指针指向了obj
  1. 一个数组或arguments对象
  • 这个数组或者arguments对象,就是要传入原本函数的参数,是什么就填什么。



那么重点就要落到这个作用域了,我们要怎么改变函数中的this呢,那就是让它成为这个作用域(也就是传入的对象)的方法然后重新调用

比如传入的是对象我们作为context,在函数中this原本指向的是函数本身,

那我们为context增加一个和函数本身一样的方法再重新去调用,这时候函数里的this就会变成context了

同时要对参数进行处理
把 (obj, [argument1, argument2, ...])
也就是apply()方法的arguments,去掉第一个参数<kbd>obj</kbd>形成新的数组,

然后把这个数组直接传入临时函数作为参数就好了

重点代码:
context[fn] = this;
const args = [...arguments].slice(1);
const result = context[fn] (...args);

下面是完整代码:

Function.prototype.myApply = function(context){

    if(typeof context !== 'object'){
        //作用域对象应为一个object
        throw new TypeError('TypeError, Expected for object');
    }

    //防止传入对象为null或无传入对象
    context = context || window;

    //使用ES6的Symbol确保不会重写作用域的其他属性
    const fn = Symbol();

    //把当前函数传址给context[fn]指针
    context[fn] = this;

    //获取本应传入原函数的参数
    const args = [...arguments].slice(1);    //ES6的扩展运算符可以使arguments这样的类数组转换成数组

    //从目的作用域中调用函数并获取返回值
    const result = context[fn](args);
    
    //删除这个临时指针
    delete context[fn];
    
    return result;
}

call

call()apply()相似,都是改变函数的作用域(也就是this所指向),

但是不同的是它必须把传递给函数的参数逐个列举出来

比如apply()是这样用的

  • exampleFunction.apply(obj, [argument1, argument2, ...])
  • exampleFunction.apply(obj, arguments)

call()是这样的

  • exampleFunction.call(obj, argument1, argument2, ...)

实现也很简单,把 (obj, argument1, argument2, ...) 也就是bind()方法的arguments,去掉第一个参数<kbd>obj</kbd>形成新的数组,

然后把这个数组展开传入临时函数作为参数就好了

重点代码:

context[fn] = this;
const args = [...arguments].slice(1);
const result = context[fn] (...args);

下面是完整代码:

Function.prototype.myCall = function(context){

    if(typeof context !== 'object'){
        //作用域对象应为一个object
        throw new TypeError('TypeError, Expected for object');
    }

    //防止传入对象为null或无传入对象
    context = context || window;

    //使用ES6的Symbol确保不会重写作用域的其他属性
    const fn = Symbol();

    //把当前函数传址给context[fn]指针
    context[fn] = this;

    //获取本应传入原函数的参数
    const args = [...arguments].slice(1);    //ES6的扩展运算符可以使arguments这样的类数组转换成数组

    //从目的作用域中调用函数并获取返回值
    const result = context[fn](...args);    //还是用ES6的扩展运算符展开数组
    
    //删除这个临时指针
    delete context[fn];
    
    return result;
}

bind

bind()的作用更强大

  1. 它接受一个作用域,并且将函数绑定在这个作用域上,返回一个新的函数
  2. 接受多个参数
  3. 支持柯里化形式传参 如fn(1)(2)

下面是完整代码:

Function.prototype.myBind = function(context) {
    
    //保存函数本身
    let fn = this;
    
    // 可以支持柯里化传参,保存参数
    let arg = [...arguments].slice(1)
    
    // 返回一个函数
    return function() {
        
        //将原参数与返回函数的新参数拼接在一起
        //支持柯里化形式传参
        let newArg = arg.concat([...arguments])
        
        //返回函数
        return fn.myApply(context, newArg)
    }
}
  • 重用了上面写的myApply()方法
  • 将第一个参数和第二个参数拼接在了一起
  • 这里的柯里化形式传参只支持分两步传参

这是笔者学习别人经验结合自己想法总结的,可能漏洞百出

如有错误请指正,笔者会及时修改

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,295评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,928评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,682评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,209评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,237评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,965评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,586评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,487评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,016评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,136评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,271评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,948评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,619评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,139评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,252评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,598评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,267评论 2 358

推荐阅读更多精彩内容