前言
好久没有更新过博客了,最近项目进度比较紧张,每天都在加班,学习的时间少之又少,目前这家公司的技术栈以尤大大的Vue+饿了吗的elementui为主导,项目中很少会用到 call & bind,昨天复习了一下原型链的知识,感觉比之前的理解又深入了一个层次,两大基类(Function & Object)的概念愈发强烈,今天抛开原型链,来说一说,call & bind。
Call
首先我们先来了解一下他分别干了什么事儿:
- 参数: context params
- 将 this 指向 context,params传递给当前调用 call 的函数
- 函数执行
- 注意:call 的context不穿值或者传递null,都指向window
知道了他做了什么事儿,那么我们实现起来就很简单了:
// 先将我们自己定义的myCall绑定到 Js的内置类 Function的原型上
Function.prototype.myCall = function( context, ...params ) {
// 校验context是否是undefined || null
context == null ? context = window : null;
// 校验如果 context是基本数据类型的话转化成引用 栗子:context = 1; 那么 Object(context) = Number { 1 },此时 typeof context === 'object'
!/^(object|function)$/.test( typeof context) ? context = Object(context) : null;
// 定义形参,除了context是一个以外,后面的参数是不固定的,直接rest运算符一步到位
let _this = this, // 养成习惯...保留this指向
result = null, // 接收函数执行的返回结果
KEY = Symbol('KEY') // 使用Symbol定义 KEY,防止与context原有的属性冲突
context[KEY] = _this; // 将当前函数挂载到context中
result = context[KEY](...params); //当前函数作为context中的一个属性的值被调用
delete context[KEY] // 删除context上自己添加的属性,保持与之前的context一直
return result // 返回函数执行的结果
}
Bind
知道call方法的原理以后,bind就很简单了,无外乎不立即执行
Function.ptototype.myBind = function( context, ...outParams ) {
// outerParams主要是形参集合
let _this = this;
return function( ...innerParams ) { //innerParams 主要是ev对象
this.call(context, ...outParams.concat(...innerParams))
}
}
doucument.body.onclick = fn.myBind(obj, 10, 20);
function fn(x, y, ev) {
this.x = 3;
this.y = 4;
}
var obj = {
x: 1,
y: 2
}