我们知道,JavaScript的bind、apply、call是三个非常重要的方法。bind可以返回固定this、固定参数的函数包装;apply和call可以修改成员函数this的指向。实现bind、apply、call是前端面试的高频问题,也能让我们更好地理解和掌握JavaScript的函数的相关知识。本文将介绍如何自行实现bind、apply和call。

前情提要

本文先给出如下类定义和实例定义。

// Person类,每个人有姓名,有打印姓名的方法
function Person(_name) {
this.name = _name
this.sayMyName = function (postfix) {
console.log(this.name + postfix)
}
}
// 两个实例
let alex = new Person('Alex')
let bob = new Person('Bob')

实现bind

不妨先回顾一下bind的使用方法:

let sayBobName = alex.sayMyName.bind(bob, '?')
sayBobName() // Bob?

可见:

  • bind返回一个函数副本(包装过的函数),固定this和实参。this可不指向调用者
  • bind是函数原型上的一个方法

了解了这两点,就不难写出实现:

function MyBind(context, ...args) {
let that = this // this是调用者,也就是被包装的函数(alex.sayMyName)
return function () { // 返回一个包装过的函数
return that.call(context, ...args) // 其返回值是以context为this的执行结果
}
}
Function.prototype.bind = MyBind

实现call

在实现bind的过程中我们用到了call。那么如何实现一个call?不妨也回顾一下call的使用方法:

alex.sayMyName.call(bob, '!') // Bob!

可见:

  • bind修改当前函数的this,可使其不指向调用者
  • 参数以...rest形式传入

了解了这两点,也不难写出实现:

function MyCall(context, ...args) {
context._fn = this // this是调用者,也就是当前函数。此步给context绑上该函数
// 有个细节问题是,可能需要备份原先的context._fn,避免意外覆盖
let ret = context._fn(..args) // 模仿context自己调用_fn
delete context._fn // 移除绑的函数
return ret
}
Function.prototype.call = MyCall

实现apply

apply和call的作用相同,使用方法基本类似,唯一的不同是:

  • 参数以数组形式传入

故可写出实现:

function MyApply(context, args) {
return MyCall(context, ...args)
}
Function.prototype.apply = MyApply

稳定的三角

从上面我们看出,apply和call可以实现bind,那么怎么用bind实现apply和call,从而打造这一铁三角关系呢?

    bind
/ \ 两两都可互相实现的三角形!
call -- apply

简单!立即执行这个函数副本就可以了!

function AnotherMyCall(context, ...args) {
return (this.bind(context, ...args))()
}

也谈如何实现bind、apply、call的更多相关文章

  1. javascript中bind,apply,call的相同和不同之处

    javasctipt中bind,apply,call的相同点是: 1,都是用来改变this的指向; 2,都可以通过后续参数进行传参; 3,第一个参数都是指定this要指向的对象; 不同点: 1,调用方 ...

  2. javascript 的bind/apply/call性能

    javascript有两种使用频率非常高的三个内置的功能:bind/apply/call.许多技术是基于高点,这些功能实现.这三个功能被用来改变的功能运行环境.从而达到代码复用的目的. 先来所说bin ...

  3. .bind.apply() 解决 new 操作符不能用与 apply 或 call 同时使用

    背景: 小明想要用数组的形式为 Cls.func 传入多个参数,他想到了以下的写法: var a = new Cls.func.apply(null, [1, 2, 3]); 然而浏览器却报错Cls. ...

  4. bind,apply,call的区别

    在Javascript中,bind, apply, call方法都可以显式绑定上下文this,这三者有何不同呢? bind只绑定this不马上执行 var person = { firstname: ...

  5. 箭头函数表达式和声名式函数表达式的区别以及 Function.prototype的bind, apply,call方法

    箭头函数不能用做构造函数 箭头函数没有arguments参数 箭头函数没有自己的this,是从作用域链上取this,是与箭头函数定义的位置有关的,与执行时谁调用无关,所以用call,apply,bin ...

  6. 浅谈JavaScript中的apply,call和bind

    apply,call,bine 这三兄弟经常让初学者感到疑惑.前两天准备面试时特地做了个比较,其实理解起来也不会太难. apply MDN上的定义: The apply() method calls ...

  7. JavaScript: bind apply call

    var foo = function(age,sex){ console.log(this.name,age,sex); }; //call将改变函数运行的context foo.call({name ...

  8. bind,apply,call区别总结

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  9. this bind apply call

    this 是当前函数运行时所属的对象bind 是指定一个函数运行时的上下文,也就是说把这个函数的this指向绑定到相应对象上,默认的暴露在全局御中的函数this指向widow对象, 严格模式下全局的t ...

随机推荐

  1. 目标检测 | 经典算法 Cascade R-CNN: Delving into High Quality Object Detection

    作者从detector的overfitting at training/quality mismatch at inference问题入手,提出了基于multi-stage的Cascade R-CNN ...

  2. Burpsuite被动扫描流量转发插件:Passive Scan Client

    编译成品:链接: https://pan.baidu.com/s/1E0vsPGgPgB9bXCW-8Yl1gw 提取码: 49eq Passive Scan Client Burpsuite被动扫描 ...

  3. Nginx.pid打开失败以及失效的解决方案

    在启动nginx的时候报了如下的错误: 其意思是没有该文件或者是目录,通过查看之后发现确实没有该目录   cd /var/run/nginx 于是重新创建了这个文件,使用如下命令:   mkdir / ...

  4. ASP.NET MVC升级到ASP.NET Core MVC踩坑小结

    写在前面 ASP.NET Core是微软新推出的支持跨平台.高性能.开源的开发框架,它的优势不必多说,因为已经说得太多了.当然,现在依然有着数量庞大的系统运行于.NET Framework上,由于有大 ...

  5. 文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于肽段鉴定中错误发生率估计的能体现重复性的诱饵数据库)

    文献名:Repeat-Preserving Decoy Database for False Discovery Rate Estimation in Peptide Identication (用于 ...

  6. nodejs使用express中静态资源托管(express.static())时遇到的bug

    如下:将test.html的页面挂载在服务器上, const express= require('express') const fs= require('fs') let app = express ...

  7. 二、【Docker笔记】Docker的核心概念及安装

    Docker主要有三大核心的概念,分别为镜像(Image).容器(Container)及仓库(Repository). 一.核心概念 1.Docker镜像 ​ Docker镜像其实与虚拟机镜像很类似, ...

  8. iOS 启动时间优化

    在 WWDC 2016 上首次提到了关于 App 应用启动速度优化的话题:Session 406 Optimizing App Startup Time. 一.冷启动与热启动 热启动是,APP会恢复之 ...

  9. linux 访问windows 共享文件

    用到的方法是 CIFS (Common Internet File System)windows自己的网络文件系统 操作系统: Linux为 debian. Windows 为 windows 8   ...

  10. A - Jessica's Reading Problem POJ - 3320 尺取

    A - Jessica's Reading Problem POJ - 3320 Jessica's a very lovely girl wooed by lots of boys. Recentl ...