深入理解call、apply、bind,并手写代码
2024-05-26 23:31:54
浏览:179
评论:0
前言
call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
bind() 方法创建一个新的函数,当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。
call, apply, bind 的异同
相同点
- 都能改变函数内部this关键字的指向,允许你以灵活的方式控制函数的执行环境。
- 调用函数时传递额外的参数,尽管传递方式有所不同。
不同点
- call() 和 apply() 直接调用目标函数,并立即执行。 bind() 不会立即调用函数,而是返回一个新的函数,这个新函数的this值被永久地绑定到了传入的值。
- call() 接受一个参数列表。apply() 接受两个参数:第一个是上下文,第二个是一个数组或类数组对象,它包含了要传递给函数的所有参数。bind() 可以预先设置一部分参数(这些参数在新函数调用时位于参数列表的开始位置),并且返回的新函数可以在调用时继续接收其他参数。
func.call(context, arg1, arg2, ...);
func.apply(context, [arg1, arg2, ...]);
var newFunc = func.bind(context, arg1, arg2);
// 后续调用
newFunc(arg3, arg4);
手写call, apply, bind
手写apply
Function.prototype._apply = function(context, args = []){
console.log(this, context, args);
// 首先判断this指向
if(typeof this !== 'function'){
throw new TypeError('this 指向必须是一个函数')
}
// 没有context,或者传递的是 null undefined,则重置为window或global
if(!context) context = window || global;
// 指定唯一属性,防止 delete 删除错误
const fn = Symbol();
// 将 this 添加到 context的属性上
context[fn] = this;
// 直接调用context 的 fn,上下文this就指向了context
const result = context[fn](...args);
// 删除掉context新增的symbol属性
delete context[fn];
return result;
}
const obj = {
name: 'vscing'
}
function getNameArr(...arr) {
console.log(arr, this.name); // [1, 2, 3, 4, 5] "vscing"
}
getNameArr._apply(obj, [1,2,3,4,5]);
手写bind
Function.prototype._bind = function(context, ...args){
console.log(this, context, args);
const that = this;
// 首先判断this指向
if(typeof that !== 'function'){
throw new TypeError('this 指向必须是一个函数')
}
// 没有context,或者传递的是 null undefined,则重置为window或global
if(!context) context = window || global;
return function(...param) {
// 指定唯一属性,防止 delete 删除错误
const fn = Symbol();
// 将 this 添加到 context的属性上
context[fn] = that;
// 直接调用context 的 fn,上下文this就指向了context
const result = context[fn](...args, ...param);
// 删除掉context新增的symbol属性
delete context[fn]
return result
}
}
const obj = {
name: 'vscing'
}
function getNameArr(...arr) {
console.log(arr, this.name); // [1, 2, 3, 4, 5] "vscing"
}
getNameArr._bind(obj, 1,2,3)(4, 5);
手写call
Function.prototype._call = function(context, ...args){
console.log(this, context, args);
// 首先判断this指向
if(typeof this !== 'function'){
throw new TypeError('this 指向必须是一个函数')
}
// 没有context,或者传递的是 null undefined,则重置为window或global
if(!context) context = window || global;
// 指定唯一属性,防止 delete 删除错误
const fn = Symbol();
// 将 this 添加到 context的属性上
context[fn] = this;
// 直接调用context 的 fn,上下文this就指向了context
const result = context[fn](...args);
// 删除掉context新增的symbol属性
delete context[fn];
return result;
}
const obj = {
name: 'vscing'
}
function getNameArr(...arr) {
console.log(arr, this.name); // [1, 2, 3, 4, 5] "vscing"
}
getNameArr._call(obj, 1,2,3,4,5);