一起手写吧!call、apply、bind!
apply,call,bind都是js给函数内置的一些api,调用他们可以为函数指定this的执行,同时也可以传参。
call
call 接收多个参数,第一个为函数上下文也就是this,后边参数为函数本身的参数。
let obj = {
name: "一个"
}
function allName(firstName, lastName) {
console.log(this)
console.log(`我的全名是“${firstName}${this.name}${lastName}”`)
}
// 很明显此时allName函数是没有name属性的
allName('我是', '前端') //我的全名是“我是前端” this指向window
allName.call(obj, '我是', '前端') //我的全名是“我是一个前端” this指向obj

apply
apply接收两个参数,第一个参数为函数上下文this,第二个参数为函数参数只不过是通过一个数组的形式传入的。
allName.apply(obj, ['我是', '前端'])//我的全名是“我是一个前端” this指向obj
bind
bind 接收多个参数,第一个是bind返回值是一个函数上下文的this,不会立即执行。
let obj = {
name: "一个"
}
function allName(firstName, lastName, flag) {
console.log(this)
console.log(`我的全名是"${firstName}${this.name}${lastName}"我的座右铭是"${flag}"`)
}
allName.bind(obj) //不会执行
let fn = allName.bind(obj)
fn('我是', '前端', '好好学习天天向上')
// 也可以这样用,参数可以分开传。bind后的函数参数默认排列在原函数参数后边
fn = allName.bind(obj, "你是")
fn('前端', '好好学习天天向上')
实现call
1.call主要都做了些什么。
- 更改this指向
- 函数立刻执行
2.简单实现
Function.prototype.myCall = function(context) {
context.fn = this;
context.fn();
}
const obj = {
value: 'hdove'
}
function fn() {
console.log(this.value);
}
fn.myCall(obj); // hdove
3.出现的问题
- 1.无法传值
- 2.如果fn()有返回值的话,myCall 之后获取不到
Function.prototype.myCall = function (context) {
context.fn = this;
context.fn();
}
const obj = {
value: 'hdove'
}
function fn() {
return this.value;
}
console.log(fn.myCall(obj));
- 3.call其实就是更改this指向,指向一个Object,如果用户传的是基本类型又或者干脆就不传呢?
- 4.myCall执行之后,obj会一直绑着fn()
4.统统解决
Function.prototype.myCall = function(context) {
// 1.判断有没有传入要绑定的对象,没有默认是window,如果是基本类型的话通过Object()方法进行转换(解决问题3)
var context = Object(context) || window;
/**
在指向的对象obj上新建一个fn属性,值为this,也就是fn()
相当于obj变成了
{
value: 'hdove',
fn: function fn() {
console.log(this.value);
}
}
*/
context.fn = this;
// 2.保存返回值
let result = '';
// 3.取出传递的参数 第一个参数是this, 下面是三种截取除第一个参数之外剩余参数的方法(解决问题1)
const args = [...arguments].slice(1);
//const args = Array.prototype.slice.call(arguments, 1);
//const args = Array.from(arguments).slice(1);
// 4.执行这个方法,并传入参数 ...是es6的语法用来展开数组
result = context.fn(...args);
//5.删除该属性(解决问题4)
delete context.fn;
//6.返回 (解决问题2)
return result;
}
const obj = {
value: 'hdove'
}
function fn(name, age) {
return {
value: this.value,
name,
age
}
}
fn.myCall(obj, 'LJ', 25); // {value: "hdove", name: "LJ", age: 25}
二、手动实现Apply
实现了call其实也就间接实现了apply,只不过就是传递的参数不同
Function.prototype.myApply = function (context, args) {
var context = Object(context) || window;
context.fn = this;
let result = '';
//4. 判断有没有传入args
if (!args) {
result = context.fn();
} else {
result = context.fn(...args);
}
delete context.fn;
return result;
}
const obj = {
value: 'hdove'
}
function fn(name, age) {
return {
value: this.value,
name,
age
}
}
fn.myApply(obj, ['LJ', 25]); // {value: "hdove", name: "LJ", age: 25}
三、实现Bind
bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用(MDN)
bind和apply的区别在于,bind是返回一个绑定好的函数,apply是直接调用.其实想一想实现也很简单,就是返回一个函数,里面执行了apply上述的操作而已.
不过有一个需要判断的点,因为返回新的函数,要考虑到使用new去调用,并且new的优先级比较高,所以需要判断new的调用,还有一个特点就是bind调用的时候可以传参,调用之后生成的新的函数也可以传参,效果是一样的,所以这一块也要做处理
因为上面已经实现了apply,这里就借用一下,实际上借用就是把代码copy过来
Function.prototype.myBind = function (context, ...args) {
const fn = this
args = args ? args : []
return function newFn(...newFnArgs) {
if (this instanceof newFn) {
return new fn(...args, ...newFnArgs)
}
return fn.apply(context, [...args,...newFnArgs])
}
}
一起手写吧!call、apply、bind!的更多相关文章
- 手写简单call,apply,bind
分析一下call的使用方法:call是显示绑定this指向,然后第一个参数是你所指向的this对象,后面跟着多个参数,以逗号隔开 function sum(num1,num2){ return num ...
- 手写call、apply、bind
区别&联系 三者都是指定函数执行时的上下文,第一个参数都是上下文: call从第二个参数开始,后续所有的参数传递给函数执行: apply第二个参数是一个数组,传递给函数执行: bind返回一个 ...
- 前端面试 js 你有多了解call,apply,bind?
函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础 ...
- 手写系列:call、apply、bind、函数柯里化
少废话,show my code call 原理都在注释里了 // 不覆盖原生call方法,起个别名叫myCall,接收this上下文context和参数params Function.prototy ...
- 前端面试手写代码——call、apply、bind
1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...
- 源码来袭:bind手写实现
JavaScript中的this指向规则 源码来袭:call.apply手写实现与应用 理解建议:如果对this指向规则不了解的话,建议先了解this指向规则,最好还能对call和apply的使用和内 ...
- 源码来袭:call、apply手写实现与应用
关于this指向可以了解我的另一篇博客:JavaScript中的this指向规则. 一.call与apply的使用 回顾call与apply的this指向: var value = "win ...
- 依据ECMA规范,手写一个bind函数
Function.prototype.bind 函数,参见ECMA规范地址 如题,这次来实现一个boundFunction函数,不挂载在Function.prototype上,而是一个单独声明的函数. ...
- 别真以为JavaScript中func.call/apply/bind是万能的!
自从学会call/apply/bind这三个方法后我就各种场合各种使用各种得心应手至今还没踩过什么坑,怎么用?说直白点就是我自己的对象没有某个方法但别人有,我就可以通过call/apply/bind去 ...
- js call apply bind
call.apply.bindcat.call(dog, a, b) == cat.apply(dog, [a, b]) == (cat.bind(dog, a, b))() 1.作用 改变函数内的t ...
随机推荐
- uni-app使用wx-canvas实现微信小程序上显示地图map和坐标geo
源码 <template> <view class="echart-box"> <canvas class="ec-canvas" ...
- kail入侵win2003 sp2 中文版系统
攻击机:kail -- IP:192.168.74.132 目标靶机:win2003 sp2 中文版系统-- IP:192.168.74.128 一.扫描漏洞 1. 在kail中运行 namp 192 ...
- IDM使用教程:利用IDM下载百度网盘文件
IDM是什么 其实我使用IDM下载器只是为了方便网页版百度网盘直接下载大于40M文件而已,大家知道文件过大必须打开客户端才能下载,这点对于我的破电脑感觉很烦躁,每次要等待它慢悠悠打开,然后动用我的超级 ...
- 动态sql & 抽取可重用sql
抽取可重用的sql片段 抽取:<sql id="xx"></sql> 使用:<include refid="xx">< ...
- [python]pytest实现WEB UI自动化
前言:其实这篇写的是pytest的测试框架运用,实现自动化和https://www.cnblogs.com/Jack-cx/p/9357658.html 原理一致 1.为啥不用unittest Pyt ...
- C# | VS2019连接MySQL的三种方法以及使用MySQL数据库教程
本文将介绍3种添加MySQL引用的方法,以及连接MySQL和使用MySQL的教程 前篇:Visual Studio 2019连接MySQL数据库详细教程 \[QAQ \] 第一种方法 下载 Mysql ...
- 日志框架-logtube
Logtube 是什么 logtube 框架是基于 slf4j的一个日志框架封装, 源码地址: https://github.com/logtube 基于 SLF4J框架, 扩展了日志输出格式 (兼容 ...
- 大一C语言学习笔记(10)---编程篇--制作简易计算器,支持加,减,乘,除,取余运算,要求 0 bug
博主自开学初就一直在努力为自己的未来寻找学习方向,学习编程嘛,尽量还是要抱大腿的,所以我就加入了我们学校的智能设备研究所,别的不说,那的学长们看起来是真的很靠谱,学长们的学习氛围也超级浓厚,所以我就打 ...
- 我罗斯方块最终篇(Interface类)
负责的任务 游戏过场及界面设计 Interface类的基础实现 根据队友需求完善Interface类功能 Interface类的本地测试 辅助队友改良游戏操作 代码要点 我们主要是通过控制台进行界面渲 ...
- [cf1479D]Odd Mineral Resource
先考虑判定是否有解,注意到无解即每一个数都出现偶数次,根据异或的性质,只需要随机$V_{i}$,假设$u$到$v$路径上所有节点构成集合$S$,若$\bigoplus_{x\in S,l\le a_{ ...