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!的更多相关文章

  1. 手写简单call,apply,bind

    分析一下call的使用方法:call是显示绑定this指向,然后第一个参数是你所指向的this对象,后面跟着多个参数,以逗号隔开 function sum(num1,num2){ return num ...

  2. 手写call、apply、bind

    区别&联系 三者都是指定函数执行时的上下文,第一个参数都是上下文: call从第二个参数开始,后续所有的参数传递给函数执行: apply第二个参数是一个数组,传递给函数执行: bind返回一个 ...

  3. 前端面试 js 你有多了解call,apply,bind?

    函数原型链中的 apply,call 和 bind 方法是 JavaScript 中相当重要的概念,与 this 关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础 ...

  4. 手写系列:call、apply、bind、函数柯里化

    少废话,show my code call 原理都在注释里了 // 不覆盖原生call方法,起个别名叫myCall,接收this上下文context和参数params Function.prototy ...

  5. 前端面试手写代码——call、apply、bind

    1 call.apply.bind 用法及对比 1.1 Function.prototype 三者都是Function原型上的方法,所有函数都能调用它们 Function.prototype.call ...

  6. 源码来袭:bind手写实现

    JavaScript中的this指向规则 源码来袭:call.apply手写实现与应用 理解建议:如果对this指向规则不了解的话,建议先了解this指向规则,最好还能对call和apply的使用和内 ...

  7. 源码来袭:call、apply手写实现与应用

    关于this指向可以了解我的另一篇博客:JavaScript中的this指向规则. 一.call与apply的使用 回顾call与apply的this指向: var value = "win ...

  8. 依据ECMA规范,手写一个bind函数

    Function.prototype.bind 函数,参见ECMA规范地址 如题,这次来实现一个boundFunction函数,不挂载在Function.prototype上,而是一个单独声明的函数. ...

  9. 别真以为JavaScript中func.call/apply/bind是万能的!

    自从学会call/apply/bind这三个方法后我就各种场合各种使用各种得心应手至今还没踩过什么坑,怎么用?说直白点就是我自己的对象没有某个方法但别人有,我就可以通过call/apply/bind去 ...

  10. js call apply bind

    call.apply.bindcat.call(dog, a, b) == cat.apply(dog, [a, b]) == (cat.bind(dog, a, b))() 1.作用 改变函数内的t ...

随机推荐

  1. 第01课 OpenGL窗口(4)

    下面的代码处理所有的窗口消息.当我们注册好窗口类之后,程序跳转到这部分代码处理窗口消息. LRESULT CALLBACK WndProc( HWND hWnd, // 窗口的句柄 UINT uMsg ...

  2. Harbor仓库搭建及使用

    目录 一.docker配置 二.安装docker-compose 三.安装harbor 四.管理harbor 五.springboot项目配置docker 六.linux服务器上打包并推送至harbo ...

  3. 『动善时』JMeter基础 — 57、Linux系统中运行JMeter脚本

    目录 1.Linux系统中安装Java环境 (1)解压Java安装包 (2)配置Java环境变量 (3)验证Java环境是否配置成功 2.Linux系统中安装JMeter (1)下载JMeter (2 ...

  4. 自定义 axios

    自定义 axios function axios({ url, method = 'GET', params = {}, data = {} }) { // 返回一个 promise 对象 retur ...

  5. Apache Shiro 反序列化漏洞分析

    Shiro550 环境搭建 参考:https://www.cnblogs.com/twosmi1e/p/14279403.html 使用Docker vulhub中的环境 docker cp 将容器内 ...

  6. mysql: 看不见的空符号 char(9) char(10) char(13)

    在统计年度销售额时,总觉得哪里不对劲.于是找了找,对了对,试了trim,消除前后的空格,也没反应. 在崩溃的边缘,终于发现了错的原因. 原来我在录入的时候,粘贴多了其他空白符号,看不见,摸不着,啊~ ...

  7. 动手写一个简单的Web框架(Werkzeug路由问题)

    动手写一个简单的Web框架(Werkzeug路由问题) 继承上一篇博客,实现了HelloWorld,但是这并不是一个Web框架,只是自己手写的一个程序,别人是无法通过自己定义路由和返回文本,来使用的, ...

  8. Swift-技巧(五)设置圆角的代码

    摘要 实现控件圆角的代码时,会不假思索的写 cornerRadius 和 masksToBounds,因为搜索得到的设置圆角的代码就是这样.今天突发奇想,为什么要写 masksToBounds? 打个 ...

  9. Excel 读取写入数据库

    // Excel 读取写入数据库 // 3.8版本的poi  4.0 可以不用写  parseCell  这个方法,可以直接赋值 STRING 类型 import org.apache.poi.hss ...

  10. 理解PHP的运行机制

    PHP是一种纯解释型在服务端执行的可以内嵌HTML的脚本语言,尤其适合开发Web应用程序.请求一个 PHP 脚本时,PHP 会读取该脚本,并将其编译为 Zend 操作码,这是要执行的代码的一种二进制表 ...