一起手写吧!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 ... 
随机推荐
- UVA 10004 Bicoloring(DFS染色)
			题意: 给N个点构成的无环无向图,并且保证所有点对都是连通的. 给每个点染色,要么染成黑要么染成白.问是否存在染色方案使得所有有边相连的点对颜色一定不一样. 是输出 BICOLORABLE 否则输出 ... 
- UVA1104 Chips Challenge
			一.题目 有一个 \(n\times n\) 的矩阵,每个元素可能是 ..C./ 的其中一种,分别表示可以放置芯片.已经放置了芯片.不能放置芯片,你可以分别决定是否可以放置芯片的位置放置芯片. 最后需 ... 
- FastJson 解析、序列化及反序列化
			一.环境准备:使用maven特性在pom.xml中导入fastjson的依赖包 <!-- https://mvnrepository.com/artifact/com.alibaba/fastj ... 
- Mysql教程:(一)数据库常用基础命令
			数据库常用命令 1.登录 进入数据库,在win系统下,打开cmd,切换用户权限,进入root: 沒权限,用root登录: mysql -uroot 如果root有密码: mysql -uroot -p ... 
- SpringCloud升级之路2020.0.x版-30. FeignClient 实现重试
			本系列代码地址:https://github.com/JoJoTec/spring-cloud-parent 需要重试的场景 微服务系统中,会遇到在线发布,一般的发布更新策略是:启动一个新的,启动成功 ... 
- redis 内存划分
			1.数据:作为数据库,数据是最主要的部分,这部分占用的内存会被统计在used_memory中 2.进程内存:redis主进程本身运行需要占用的内存,这部分内存会被统计在used_memory_rss中 ... 
- 如何系统学习C 语言(中)之 结构体篇
			1,结构体 在前面我们知道变量和数组都可以用来存储数据,变量用来存储单个数据,数组可以用来存储一组同类型的数据,但你有没有发现--它们都只适合单一属性的数据.那现实生活中,很多对象都是具有多属性的.例 ... 
- Spark中资源调度和任务调度
			Spark比MR快的原因 1.Spark基于内存的计算 2.粗粒度资源调度 3.DAG有向无环图:可以根据宽窄依赖划分出可以并行计算的task 细粒度资源调度 MR是属于细粒度资源调度 优点:每个ta ... 
- PowerDotNet平台化软件架构设计与实现系列(03):系统应用平台
			为了复用和解耦,快速开发更多的系统和应用,我们对自己经常说的"系统"和"应用"进行更高级的提取和抽象. 十多年前入行,辗转至今,写过很多很多应用,个人喜欢分门别 ... 
- pytest框架+conftest.py配置公共数据的准备和清理
			1.pytest介绍:1.自动发现测试模块和测试方法 2.断言使用 assert+表达式即可 3.可以设置会话级.模块级.类级.函数级的fixture 数据准备+清理工作 4.丰富的插件库,==all ... 
