手写原生call, apply,bind方法

1. call

call方法的作用

call方法使用一个指定的this值和单独给出的一个或多个参数来调用一个函数

call方法第一个参数为指定的this值,剩余的参数作为函数的参数传递给函数进行调用.call方法是为改变函数的执行上下文.

  1. 由于call方法可以被所有方法调用, 所以方法得定义在Function的原型上
  2. 绑定函数被调用时只传入第二个参数及以后的参数
  3. 将调用函数绑定到指定的上下文的方法上, 那么在该函数在调用时,内部的this指向该对象

明白了上面的思路我们就可以手写call了

下面是es5 实现方法

Function.prototype.Call = function (content) {
    content = content || window;// 给执行上下文 添加默认值 
    content.fn = this//给 content 添加一个方法指向this;
    var args = [];//保存参数集合
    for (let i = 1; i < arguments.length; i++) {
        args.push(arguments[i])
    }
    var res = args.length > 1 ? eval('content.fn(' + args + ')') : content.fn() ;//执行fn;
    delete content.fn;// 删除fn方法
    return res
}

下面是Es6的代码实现

Function.prototype.Call = function(content=window){// 给执行上下文 添加默认值
    content.fn = this//给 content 添加一个方法指向this;显示绑定this
    // 获取第一个参数以后的所有参数
    const args = Array.from(arguments).slice(1);
    // 调用上下文的fn属性, 此时函数的this指向上下文, 也就是我们传入的content
    const res = arguments.length > 1 ? content.fn(...args) : content.fn();
    // 删除上下文的content的fn方法, 避免污染上下文
    delete content.fn;
    return res
} 

2. apply

​ apply方法和call方法类似,都是Function原型上的方法, 每一个函数作为Function的实例都能调用这两个方法, 都是为了改变调用函数的执行上下文this指向.

​ 区别在于: call传参的时候接受的是一个参数列表,而apply方法的要传的参数接受的是一个参数列表数组, apply实现了思路和call基本相同, 我们只需要对参数进行不同的处理即可.

因为原生的apply第二个参数接受的是一个数组或者类数组对象, 所以我们得对第二个参数类型进行判断

下面是es6的实现代码

Function.prototype._Apply = function (content = window, args = []) {//给content和args添加默认值
    if (!(args instanceof Object)) {// 如果第二个参数不是对象的实例,就返回一个错误
        throw new TypeError('Create List From Array Like called on non-object');
    }
    // 显示绑定函数this
    content.fn = this;
    // 执行fn方法,并接受返回值
    const res = arguments[1] ? content.fn(...arguments[1]) : content.fn()
    delete content.fn;// 删除fn方法
    return res
}

3. bind

bind()方法创建一个新函数, 在bind()被调用时, 这个新函数的this被指定为 bind()的第一个参数, 而其余参数将作为新函数的参数,供调用时使用.

下面是bind的es6的简易实现

Function.prototype._bind = function(content=window){
    const slice = Array.prototype.slice;
    // 保存调用函数的this, 也就是原函数
    const thatFunc = this;
    // 获取第一个参数之后剩余的参数数组
    const args = [].slice.call(arguments,1);
    return function(){
        // 合并返回的新函数的参数
        const funcArgs = args.concat(slice.call(arguments))
        // 返回新函数调用的结果
        return thatFunc.call(content,...funcArgs)
    }
}

上面的代码只是对bind的一个简易实现, 没有考虑new运算符的实现,之后会更新对new运算符的实现.

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