一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
本题难度:⭐ ⭐ ⭐
答:
面试过关版
Function.prototype.myApply = function (context = window) {
context.fn = this
const args = arguments[1] || []
const res = context.fn(...args)
delete context.fn
return res
}
尽可能完善的版本
Function.prototype.myApply = function (context = window) {
if (context === undefined || context === null) {
context = window
} else {
context = Object(context)
}
const fn = Symbol('fn')
context[fn] = this
const args = arguments[1] || []
const res = context[fn](...args)
delete context[fn]
return res
}
卷王版本
Function.prototype.myApply = function (context = window) {
if (context === undefined || context === null) {
context = window
} else {
context = Object(context)
}
const fn = Symbol('fn')
context[fn] = this
let args = arguments[1]
if (args) { // 如果有第二个参数,就判断是不是数组或者类数组
if (!Array.isArray(args) && !isArrayLike(args)) {
throw new Error('apply函数第二个参数不是数组或类数组')
}
args = Array.from(args) // 将类数组转成数组
} else {
args = [] // 如果没有第二个参数,就不处理
}
const res = context[fn](...args)
delete context[fn]
return res
}
// 判断对象是否是类数组,摘自《JavaScript权威指南》
function isArrayLike(o) {
if (o && // o不是null、undefined等
typeof o === 'object' && // o是对象
isFinite(o.length) && // o.length是有限数值
o.length >= 0 && // o.length为非负值
o.length === Math.floor(o.length) && // o.length是整数
o.length < 4294967296) // o.length < 2^32
return true
else
return false
}
apply 和 call 的功能是差不多的,唯一的区别是传递函数参数的形式不同,call 是一个参数一个参数地传,apply 是把参数放到一个数组或者类数组集合里,只需要传递这个集合。
他们的实现是完全差不多的,面试过关版 和 尽可能完善版 的实现的细节请参考 call 的实现,就不赘述了。
至于卷王版本,只是一个戏称,其实一点也不卷,就是多加了类数组的判断,判断一个对象是否是类数组,参考了《JavaScript权威指南》中的 isArrayLike 方法。
关于类数组,可以参考我的这篇文章:
结尾
如果我的文章对你有帮助,你的👍就是对我的最大支持^_^
你也可以关注《前端每日一问》这个专栏,防止失联哦~
我是阿林,输出洞见技术,再会!
上一篇:
下一篇: