也谈如何实现bind、apply、call
我们知道,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的更多相关文章
- javascript中bind,apply,call的相同和不同之处
javasctipt中bind,apply,call的相同点是: 1,都是用来改变this的指向; 2,都可以通过后续参数进行传参; 3,第一个参数都是指定this要指向的对象; 不同点: 1,调用方 ...
- javascript 的bind/apply/call性能
javascript有两种使用频率非常高的三个内置的功能:bind/apply/call.许多技术是基于高点,这些功能实现.这三个功能被用来改变的功能运行环境.从而达到代码复用的目的. 先来所说bin ...
- .bind.apply() 解决 new 操作符不能用与 apply 或 call 同时使用
背景: 小明想要用数组的形式为 Cls.func 传入多个参数,他想到了以下的写法: var a = new Cls.func.apply(null, [1, 2, 3]); 然而浏览器却报错Cls. ...
- bind,apply,call的区别
在Javascript中,bind, apply, call方法都可以显式绑定上下文this,这三者有何不同呢? bind只绑定this不马上执行 var person = { firstname: ...
- 箭头函数表达式和声名式函数表达式的区别以及 Function.prototype的bind, apply,call方法
箭头函数不能用做构造函数 箭头函数没有arguments参数 箭头函数没有自己的this,是从作用域链上取this,是与箭头函数定义的位置有关的,与执行时谁调用无关,所以用call,apply,bin ...
- 浅谈JavaScript中的apply,call和bind
apply,call,bine 这三兄弟经常让初学者感到疑惑.前两天准备面试时特地做了个比较,其实理解起来也不会太难. apply MDN上的定义: The apply() method calls ...
- JavaScript: bind apply call
var foo = function(age,sex){ console.log(this.name,age,sex); }; //call将改变函数运行的context foo.call({name ...
- bind,apply,call区别总结
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- this bind apply call
this 是当前函数运行时所属的对象bind 是指定一个函数运行时的上下文,也就是说把这个函数的this指向绑定到相应对象上,默认的暴露在全局御中的函数this指向widow对象, 严格模式下全局的t ...
随机推荐
- eNSP 交换机 路由器 PC 互连设计/实现
0.实验目的 1.掌握网络设计的原理与步骤: 2.掌握IP分配.网关设置原则: 3.了解路由协议的作用,掌握网络互联设备的作用和配置. 1.实验环境 环境:eNSP模拟器 版本信息:1.3.00.10 ...
- DNS提供的服务
DNS提供的服务 DNS是:1.一个由分层的DNS服务器实现的分布式数据库:2. 一个使主机能够查询分布式数据库的应用协议.DNS协议运行在UDP上,使用53号端口. 与http,FTP,SMTP协议 ...
- C 2012年笔试题
1指出程序段中的错误:分析错误的原因,并进行修改 1.1函数 swap 将两个字符串(字符数组作实参,长度不超过 100)的内容进行交换 void swap(char *pa,char *pb) { ...
- UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数
UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数 gethostname() getppername() getsockname() gethostbyname() ...
- TensorFlow 卷积神经网络手写数字识别数据集介绍
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 手写数字识别 接下来将会以 MNIST 数据集为例,使用卷积层和池 ...
- 8 个出没在 Linux 终端的诡异家伙
这篇文章,我们一起来到 Linux 的诡异的一面-- 你知道吗?在我们日常使用的 Unix(和 Linux )及其各种各样的分支系统中,存在着一些诡异的命令或进程,它们让人毛骨悚然,有些确实是有害,但 ...
- 编译原理:非确定的自动机NFA确定化为DFA
1.设有 NFA M=( {0,1,2,3}, {a,b},f,0,{3} ),其中 f(0,a)={0,1} f(0,b)={0} f(1,b)={2} f(2,b)={3} 画出状态转换矩阵 ...
- FME中矢量裁剪
- 双剑合璧的开源项目Kitty-Cloud
项目地址 https://github.com/yinjihuan/kitty-cloud 背景 做这个项目主要是想将个人的一些经验通过开源的形式进行输出,不一定能帮到所有人,有感兴趣的朋友可以关注学 ...
- ICPC训练周赛 Benelux Algorithm Programming Contest 2019
D. Wildest Dreams 这道题的意思是Ayna和Arup两人会同时在车上一段时间,在Ayna在的时候,必须单曲循环Ayna喜欢的歌,偶数段Ayna下车,若此时已经放了她喜欢的那首歌,就要将 ...