理解 call、apply、bind 原理,手写简单的 call、apply、bind 方法

call 原理及实现

MDN定义:call()方法使用给定的 this 值和单独提供的参数调用函数。

用自己的话说就是:改变调用 call 方法的 this 指向。

使用语法:function.call(target, arg1, arg2, arg3)

  • 上菜说明:
// 全局的name
var name = "全局的name";// obj对象
const obj = {name: "obj对象的name",
};// 方法
function printName(a) {console.log(this.name + a);
}printName(); // 直接调用this指向全局
// 全局的nameprintName.call(obj, "附加"); // 改变this指向为obj
// obj对象的name附加

理解了 call 是做什么事情的,接下来根据理解的思路自己写一个 myCall 方法出来。

须知:1. call 实际上是 Function.prototype 上面的方法;2. 任何函数都可以访问自己的 prototype 上面的方法

  • 上 DIY 的菜:
Function.prototype.myCall = function (targetObj = {}, ...args) {const fn = Symbol("fn"); // 定义一个唯一的 Symbol 避免意外污染替换 targetObj 的属性targetObj[fn] = this; // this 就是调用 myCall 方法的“函数本身”const result = targetObj[fn](...args); // 通过 targetObj 执行方法,并传入额外参数delete targetObj[fn]; // 删除添加的属性return result; // 返回执行结果
};const obj = {name: "alice",
};
// 方法
function printName(a) {console.log(this.name + a);
}
printName.myCall(obj, " is a beauty");
// alice is a beauty

搞定!根据思路自己写出来后是不是很 nice,感觉很简单


apply 原理及实现

apply 的效果与 call 功效相同,都是改变 this 指向的问题。不同点:apply 接收的参数是目标对象、参数数组两个参数

  • 直接 DIY 菜
Function.prototype.myApply = function (target, argList) {const targetObj = target || {};const fn = Symbol("fn");targetObj[fn] = this;const result = targetObj[fn](...argList);delete targetObj[fn];return result;
};// 测试一下
const obj = {name: "crk",
};
function print(...arr) {console.log(this.name + arr);
}print.myApply(obj, [1, 2, 3]);

bind 的实现与原理

用法与前二者类似,被指定 this 指向后不立即执行,会返回一个可以执行的新函数,不会自动执行。

  • 注意点:
    1、bind() 除了 this 外还接收其他参数,其返回的函数也可以接收参数(意思是执行返回的函数的时候可以传参)。并且这两部分参数都需要传给返回的函数
    2、bind() 返回的方法如果被 new 执行了,那么内部的 this 指向又会被更改
    3、需要保留“元方法”在原型链上的属性和方法

简单的 bind 实现:

Function.prototype.myBind = function () {const args = Array.prototype.slice.call(arguments); // myBind 接口的所有参数const targetObj = args.shift(); // 第一个参数是 this 的目标对象,args剩下的是绑定时的参数const self = this; // 调用 myBind 的"元方法"// new 优先改变 thisconst cbFn = function () {// 当是new的时候,this instanceof self 的值为true,这个时候this应该指向被new的函数自己self.apply(this instanceof self ? this : targetObj,args.concat(Array.prototype.slice.call(arguments)));};// 被bind后生产的函数可以多次调用,是持久的。所以需要保留原型链上的方法和属性。这里使用原型继承cbFn.prototype = Object.create(self.prototype);return cbFn;
};

测试一下基础功能:

const obj = {name: "小强",
};function foo() {console.log(this.name, ...arguments);
}foo.myBind(obj, 1, 2, 3)(); // 小强 1 2 3
foo.myBind(obj, 1, 2, 3)(4); // 小强 1 2 3 4

测试bind之后的函数 new 的功能

function factory(name) {this.name = name;this.fn = function () {return this.name;};
}const newObj = {name: "大强",
};const bindF = factory.myBind(newObj);
const f = new bindF("大枪");
console.log(f.fn()); // 大枪
  • 虽然myBind的时候指定了this,但是new的使用改变了this的指向

至此,毕

理解 call、apply、bind 原理,手写简单的 call、apply、bind 方法相关推荐

  1. python 反卷积(DeConv) tensorflow反卷积(DeConv)(实现原理+手写)

    Tensorflow反卷积(DeConv)实现原理+手写python代码实现反卷积(DeConv) 理解: https://www.zhihu.com/question/43609045/answer ...

  2. 手写简单版 Promise

    Promise作为ES6新增的函数,帮助我们解决了回调地狱的难题,让我们的异步代码可以更加清晰简洁,作为一名前端程序员,手写简单版Promise应该是必备的技能.接下来不多说,直接上代码了. clas ...

  3. 手写简单的HashMap(jdk1.7)

    手写简单的HashMap(jdk1.7) public class MyHashMap<K, V> { //创建一个节点数组 private Entry1<K, V>[] ta ...

  4. 使用代理模式手写简单的数据库连接池

    使用代理模式手写简单的数据库连接池 JDBC直连数据库 思考 改造 ConnectionProxy ConnectionPool ProxyMain 运行结果 代理模式 与装饰器的区别 JDBC直连数 ...

  5. Dubbo——手写简单版Dubbo框架

    摘要 本博文将详细的介绍的一个手写简单版本的dubbo的实现. 项目架构原理图 项目源码实现 https://github.com/2462612540/DubboPrinciple/tree/mas ...

  6. 数字识别实例两种实现方式(tensorflow2.x):1.调用高级API 2.手写简单神经网络 3.手写深度神经网络(DNN)

    MNIST手写数字数据库的训练集为60,000个示例,而测试集为10,000个示例. 一共4个文件,训练集.训练集标签.测试集.测试集标签,这些数据直接可以用mnist = tf.keras.data ...

  7. 面试官:手写一个call、apply、bind?

    前言 相信不少面试中涉及this的问题不少.而在JavaScript中this的绑定有四种类型,优先级分别为 new绑定>显式绑定>隐式绑定>默认绑定,这里我们也浅浅提及一下这四种的 ...

  8. 手写简单的双向数据绑定

    github.com/logictuLuoq- 简单介绍一下MVVM MVVM是Model-View-ViewModel的简写 MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI ...

  9. Mobx原理: 手写mobx

    手写状态管理库: Mobx mobx是一个状态管理库,类似于redux或者vuex完成状态观察相应相关的处理.mobx使得状态管理更加的简单和透明.由于这篇文章时mobx原理解析,所以关于mobx的使 ...

最新文章

  1. Mysql高级调优篇——第二章:Explain执行计划深度剖析
  2. python 写入excel_使用python将数据写入excel
  3. linux c 文件操作
  4. ConfigParser模块简明教程
  5. 趣链 BitXHub跨链平台 (7)应用链插件
  6. 系统目录结构,文件类型
  7. nvidia.dali:深度学习加速神器!
  8. Linux命令:wget、unzip、cmake、make、vim
  9. windows最常用的快捷键(windows10 )
  10. 软件工程:状态,行为,事件
  11. spring session过期时间设置
  12. 免费下载深度操作系统(deepin),三步快捷体验优秀国产操作系统
  13. java oracle 建表语句_oracle得到建表语句
  14. 决策支持系统和专家系统有什么不同
  15. 雨滴win7计算机路径,win7雨滴桌面秀 Raindrop Desktop Show教程_计算机软件和应用程序_IT /计算机_信息...
  16. idea 安装uml 画图工具
  17. 一键打开常用软件(bat/vbs)
  18. [Python黑帽] 二.Python能做什么攻击?正则表达式、网络爬虫和套接字通信入门
  19. Facebook受邀者的邮箱地址披露
  20. 《深入学习VMware vSphere 6》——2.3 在VMware Workstation虚拟机中安装ESXi 6

热门文章

  1. 苹果手机邮箱怎么设置_企业邮箱怎么设置别名
  2. 咱当爹的人, 有啥不一样
  3. oppoReno4se和华为麦芒9 哪个好
  4. 微信小程序开发之从“跳伞”到“吃鸡”
  5. windows和linux双系统安装MBR+BIOS方法
  6. 遥感图像卫星概述--海洋卫星,资源卫星,商用卫星
  7. vue父组件如何调用子组件里面的方法
  8. 课堂上最搞笑的问题答案
  9. W7500如何使用KEIL通过SWD调试下载程序?
  10. SimpleDateFormat性能优化