不使用 ES6+ 实现 call apply bind 方法

使用 ES6+ 实现这三个方法其实非常简单,本文就来挑战一下,如果不适用 ES6+ 的情况下如何实现这三个方法

难点: 不能使用扩展运算符(…)该如何接收参数和传入参数

至于这三个方法有什么区别可以阅读我之前的这篇文章 call()-apply()-bind()方法有什么不同?

apply

就不多说废话了,直接看代码

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Function.prototype.myApply = function (_this, args) {
try {
_this = _this || window
_this['#function#'] = this
if (!args) {
return _this['#function#']()
} else {
var params = JSON.stringify(args)
// 当 JSON.stringify 把一个数组解析成字符串是会多套一层 ‘[]’ ,所以需要裁切掉
params = params.slice(1, params.length - 1)
// 由于 Function 无法访问上级作用域,由于上层以及裁掉了首尾部分
// 所以得到 _this["#function#"](1,2) 这样就能实现扩展运算符(...)的操作了,关于 new Function 请自行查阅
return new Function('_this', 'return _this["#function#"](' + params + ')')(_this)

// ------ 上面这坨你也可以改为 eval() ------

var params = []
// 注意,这里的 i 初始值是 1 主要目的是为了去除第一个参数(也就是 _this)
for (var i = 1; i < arguments.length; i++) {
params.push('arguments[' + i + ']')
}
// 这里解释一下,当引用类型与字符串拼接的时候会隐式调用 toString() ,数组调用 toString() 会返回如下结果
// _this["#function#"](arguments[1],arguments[2],arguments[3])
// eval 执行后可以访问上级作用域的变量,这里就可以实现扩展运算符(...)的操作了
return eval('_this["#function#"](' + params + ')')
}
} finally {
delete _this['#function#']
}
}

call

由于前面以及实现了 myApply 方法,再 myCall 即可直接调用,如果要完整写一个 myCall 也只是增加代码冗余而已

COPY
1
2
3
4
5
6
7
8
9
Function.prototype.myCall = function (_this) {
_this = _this || window
var params = []
// 注意,这里的 i 初始值是 1 主要目的是为了去除第一个参数(也就是 _this)
for (var i = 1; i < arguments.length; i++) {
params.push(arguments[i])
}
return this.myApply(_this, params)
}

bind

如上,可以继续复用已经封装好的

COPY
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Function.prototype.myBind = function (_this) {
_this = _this || window
var self = this
var params = []
// 注意,这里的 i 初始值是 1 主要目的是为了去除第一个参数(也就是 _this)
for (var i = 1; i < arguments.length; i++) {
params.push(arguments[i])
}
return function () {
// 注意这里的 i 初始值是 0 ,因为它不需要移除 _this ,可能这有点乱,希望读者多多思考
for (var i = 0; i < arguments.length; i++) {
params.push(arguments[i])
}
return self.myApply(_this, params)
}
}

总结

以上就是本文的全部内容,可能会存在一些小瑕疵,希望各位读者留言评论或优化

Authorship: Lete乐特
Article Link: https://blog.imlete.cn/article/nonuse-es6+-implements-call-apply-bind.html
Copyright: All posts on this blog are licensed under the CC BY-NC-SA 4.0 license unless otherwise stated. Please cite Lete乐特 's Blog !