也谈如何实现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 ...
随机推荐
- 为什么Mysql的常用引擎都默认使用B+树作为索引?
一.前言 为了讲清楚这个问题,我们要先了解什么是索引. 我记得刚刚学习数据库的时候,老师喜欢用书本的目录来类比数据库的索引,并告诉我们索引能够像目录一样,让我们更快地找到想要找到的数据. 如果是第一次 ...
- Java并发编程之支持并发的list集合你知道吗
Java并发编程之-list集合的并发. 我们都知道Java集合类中的arrayList是线程不安全的.那么怎么证明是线程不安全的呢?怎么解决在并发环境下使用安全的list集合类呢? 本篇是<凯 ...
- Ubuntu 18.04 将gcc版本降级为5.5版本
Remark: Polynomial algebra 程序由于版本问题只能在gcc 5.0 版本运行, 而ubuntu更新会将gcc 更新到7.0版本,出现冲突(报错:如下) collect2: er ...
- 曹工说Redis源码(1)-- redis debug环境搭建,使用clion,达到和调试java一样的效果
概要 最近写了spring系列,这个系列还在进行中,然后有些同学开始叫我大神,然后以为我各方面都比较厉害,当然了,我是有自知之明的,大佬大神什么的,当作一个称呼就好,如果真的以为自己就是大神,那可能就 ...
- Java 配 Shell 等于美酒加咖啡
化学中我们得知「氢气加氧气在点燃的情况下会生成水」. 生活中我们得知「良辰加美景的情况下会得到千金春宵一刻」. 技术上又何尝不是如此呢?先假设一个场景:BOSS 让你实现一个服务监控的指挥室,能看到每 ...
- Reface.NPI 方法名称解析规则详解
在上次的文章中简单介绍了 Reface.NPI 中的功能. 本期,将对这方法名称解析规则进行详细的解释和说明, 以便开发者可以完整的使用 Reface.NPI 中的各种功能. 基本规则 方法名称以 I ...
- 万字长文带你入门Zookeeper!!!
导读 文章首发于微信公众号[码猿技术专栏],原创不易,谢谢支持. Zookeeper 相信大家都听说过,最典型的使用就是作为服务注册中心.今天陈某带大家从零基础入门 Zookeeper,看了本文,你将 ...
- 使用 Nginx 实现 301 跳转至 https 的根域名
基于 SEO 和安全性的考量,需要进行 301 跳转,以下使用 Nginx 作通用处理 实现结果 需要将以下地址都统一跳转到 https 的根域名 https://chanvinxiao.com ht ...
- php人民币小写转大写函数,不限长度,精确到分
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://ustb80.blog.51cto.com/6139482/1035327 在打印 ...
- Ubuntu16.04默认Python3.5升级Python3.6踩坑
好久没更新博客了,每天还是踩坑中.今天遇到第一个问题“ImportError: No module named 'secrets'”,导包是常见问题.这次的问题导致我又重装了一次环境,不过这是一个新服 ...