深入理解call、apply、bind,并手写代码
前言
call()
方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。
apply()
方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。
bind()
方法创建一个新的函数,当这个新函数被调用时其this
置为提供的值,其参数列表前几项置为创建时指定的参数序列。
call, apply, bind 的异同
相同点
特性 | 描述 |
---|---|
修改 this 指向 | 都能改变函数内部 this 关键字的指向,允许你以灵活的方式控制函数的执行环境。 |
传递参数 | 调用函数时传递额外的参数,尽管传递方式有所不同。 |
不同点
方法 | 执行时机 | 参数传递方式 |
---|---|---|
call() | 直接调用目标函数,并立即执行。 | 接受一个参数列表。 |
apply() | 直接调用目标函数,并立即执行。 | 接受两个参数:第一个是上下文,第二个是一个数组或类数组对象,它包含了要传递给函数的所有参数。 |
bind() | 不会立即调用函数,而是返回一个新的函数,这个新函数的 this 值被永久地绑定到了传入的值。 | 可以预先设置一部分参数(这些参数在新函数调用时位于参数列表的开始位置),并且返回的新函数可以在调用时继续接收其他参数。 |
javascript
func.call(context, arg1, arg2, ...);
func.apply(context, [arg1, arg2, ...]);
var newFunc = func.bind(context, arg1, arg2);
// 后续调用
newFunc(arg3, arg4);
手写call, apply, bind
手写apply
javascript
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
javascript
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
javascript
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);
本文标签:
本文链接:
https://www.vscing.com/article/61.html
版权声明:
本文由vscing原创发布,转载请遵循《署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)》许可协议授权
目录
标签
文章榜