共计 2526 个字符,预计需要花费 7 分钟才能阅读完成。
公众号【执鸢者】提前解锁 3 斩
写该系列文章的初衷是“让每位前端工程师把握高频知识点,为工作助力”。这是前端百题斩的第 15 斩,心愿敌人们关注公众号“执鸢者”,用常识武装本人的头脑。
在百题斩【014】中曾经简要概述了 call、apply、bind 三个办法,这三者作用是雷同的,均能够扭转 this 指向,从而让某对象能够调用本身不具备的办法,本节将深刻了解这三者的实现原理。
15.1 call()
15.1.1 根底
call()
办法应用一个指定的this
值和独自给出的一个或多个参数来调用一个函数。其返回值是应用调用者提供的 this 值和参数调用该函数的返回值,若该办法没有返回值,则返回 undefined。根本用法:
function.call(thisArg, arg1, arg2, ...)
小试牛刀
function method(val1, val2) {return this.a + this.b + val1 + val2;}
const obj = {
a: 1,
b: 2
};
console.log(method.call(obj, 3, 4)); // 10
15.1.2 实现
实现一个 call 函数,将通过以下几个步骤:
- 获取第一个参数(留神第一个参数为 null 或 undefined 时,this 指向 window),构建对象
- 将对应函数传入该对象中
- 获取参数并执行相应函数
- 删除该对象中函数,打消副作用
- 返回后果
Function.prototype.myCall = function (context, ...args) {
// 获取第一个参数(留神第一个参数为 null 或 undefined 时,this 指向 window),构建对象
context = context ? Object(context) : window;
// 将对应函数传入该对象中
context.fn = this;
// 获取参数并执行相应函数
let result = context.fn(...args);
// 打消副作用
delete context.fn;
// 返回后果
return result;
}
// ……
console.log(method.myCall(obj, 3, 4)); // 10
15.2 apply()
15.2.1 根底
apply()
办法调用一个具备给定this
值的函数,以及以一个数组(或类数组对象)的模式提供的参数。其返回值是指定 this 值和参数的函数的后果。call()
和apply()
的区别是call()
办法承受的是 参数列表 ,而apply()
办法承受的是 一个参数数组;根本用法
func.apply(thisArg, [argsArray])
小试牛刀
function method(val1, val2) {return this.a + this.b + val1 + val2;}
const obj = {
a: 1,
b: 2
};
console.log(method.apply(obj, [3, 4])); // 10
15.2.2 实现
apply 和 call 的区别次要是参数的不同,所以其实现步骤的 call 大体相似,如下所示:
Function.prototype.myApply = function (context, arr) {context = context ? Object(context) : window;
context.fn = this;
let result = arr ? context.fn(...arr) : context.fun();
delete context.fn;
return result;
}
// ……
console.log(method.myApply(obj, [3, 4])); // 10
15.3 bind()
15.3.1 根底
bind()
办法创立一个新的函数,在bind()
被调用时,这个新函数的this
被指定为bind()
的第一个参数,而其余参数将作为新函数的参数,供调用时应用。该函数的返回值是一个原函数的拷贝,并领有指定的 this 值和初始参数。根本用法
function.bind(thisArg[, arg1[, arg2[, ...]]])
小试牛刀
function method(val1, val2) {return this.a + this.b + val1 + val2;}
const obj = {
a: 1,
b: 2
};
const bindMethod = method.bind(obj, 3, 4);
console.log(bindMethod()); // 10
15.3.2 实现
实现一个 bind 函数绝对较简单一些,应该留神以下几点:
- 可能扭转 this 指向;
- 返回的是一个函数;
- 可能承受多个参数;
- 反对柯里化模式传参 fun(arg1)(arg2);
- 获取到调用 bind()返回值后,若应用 new 调用(当做构造函数),bind()传入的上下文 context 生效。
Function.prototype.myBind = function (context, ...args) {if (typeof(this) !== 'function') {throw new TypeError('The bound object needs to be a function');
}
const self = this;
// 定义一个中装函数
const fNOP = function() {};
const fBound = function(...fBoundArgs) {
// 利用 apply 扭转 this 指向
// 承受多个参数 + 反对柯里化模式传参
// 当返回值通过 new 调用时,this 指向以后实例(因为 this 是以后实例,实例的隐士原型上有 fNOP 的实例(fnop);fnop instanceof fNOP 为 true)return self.apply(this instanceof fNOP ? this : context, [...args, ...fBoundArgs]);
}
// 将调用函数的原型赋值到直达函数的原型上
if (this.prototype) {fNOP.prototype = this.prototype;}
// 通过原型的形式继承调用函数的原型
fBound.prototype = new fNOP();
return fBound;
}
1. 如果感觉这篇文章还不错,来个分享、点赞吧,让更多的人也看到
2. 关注公众号执鸢者,与号主一起斩杀前端百题