Bootstrap

JavaScript 手写 bind apply call

文章目录

call

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

语法:function.call(thisArg, arg1, arg2, ...)

注意:该方法的语法和作用与 apply() 方法类似,只有一个区别,就是 call() 方法接受的是一个参数列表,而 apply() 方法接受的是一个包含多个参数的数组

// 核心思想
// 将fn做为对象的一个属性,然后对象打点调用函数,这样函数中的this就会指向对象

// 注意点:
// 1.原生的call函数,如果处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
// 2. globalThis 是 ES10 的语法,如果在node环境下,则指向global,如果在浏览器环境下则指向windows

function call(fn, obj, ...args) {
 if (obj == undefined || typeof obj !== 'object') {
 obj = globalThis;
 }
 // 将fn做为obj的属性
 obj.temp = fn;
 // 展开剩余参数
 const result = obj.temp(...args);
 delete obj.temp;
 // 一定要记得将函数的执行结果进行返回 虽然可能函数并没有返回值
 return result;
}

测试

let testObj = { c: 5 };
global.c =7
function add(a, b) {
 console.log(a+b+this.c);
}
call(add,null,2,4) //13
call(add,testObj,2,4) //11

apply

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个 length 属性和(0..length-1)范围的整数属性。例如现在可以使用 NodeList 或一个自己定义的类似 {'length': 2, '0': 'eat', '1': 'bananas'} 形式的对象。

function apply(fn,obj,arr) {
 if (obj == null || typeof obj !== 'object') {
 obj = globalThis;
 }
 obj.temp = fn;

 // 注意这里还是需要用到展开运算符
 // 尽管给apply传的是一个数组,但实际函数运行中还是单个的参数
 let result = obj.temp(...arr);
 delete obj.temp;
 return result;
}

测试

function add(a, b) {
 return a + b + this.c;
}
let obj = { c: 5 };
console.log(apply(add, obj, [1, 2])); // 8
console.log(add.apply(obj,[1,2])); //8

bind

bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

我觉得是最复杂的一个!

function call(fn, obj, ...arg) {
 if (obj == null) {
 obj = globalThis;
 }
 obj.temp = fn;
 let result = obj.temp(...arg);
 delete obj.temp;
 return result;
}

function bind(fn, obj, ...arg) {
 // 会返回一个函数,返回的函数被调用的时候还是可以接收参数
 return function (...arg1) {
 // 执行call
 return call(fn,obj,...arg,...arg1)
 }
}

测试

function add(a, b) {
 return a + b + this.c;
}
  

let obj = {
 c: 11
}

// 原生bind
// 可见bind由下面两种传参方式
let fn = add.bind(obj, 1, 2);
console.log(fn()); //14
let fn1 = add.bind(obj);
console.log(fn1(1,2)); //14

//自己写的bind
let fn2 = bind(add, obj, 1, 2);
console.log(fn2()); //14
let fn3 = bind(add, obj);
console.log(fn3(1,2)); //14
;