? 内容速览 ?
- 手动实现
call
/apply
/bind
- 实现一个完美的深拷贝函数
- 基于
ES5
/ES6
实现双向绑定 instanceof
原理与实现
关注微信公众号 「心谭博客」,前往 「xin-tan.com」
专注前端与算法的系列干货分享,欢迎关注(¬‿¬)
手动撸个call/apply/bind
实现call
来看下call
的原生表现形式:
function test(arg1, arg2) {
console.log(arg1, arg2)
console.log(this.a, this.b)
}
run.call({
a: 'a',
b: 'b'
}, 1, 2)
好了,开始手动实现我们的call2
。在实现的过程有个关键:
如果一个函数作为一个对象的属性,那么通过对象的.
运算符调用此函数,this
就是此对象
let obj = {
a: 'a',
b: 'b',
test: function (arg1, arg2) {
console.log(arg1, arg2)
// this.a 就是 a; this.b 就是 b
console.log(this.a, this.b)
}
}
obj.test(1, 2)
知道了实现关键,下面就是我们模拟的call
:
Function.prototype.call2 = function(context) {
if(typeof this !== 'function') {
throw new TypeError('Error')
}
// 默认上下文是window
context = context || window
// 保存默认的fn
const {
fn } = context
// 前面讲的关键,将函数本身作为对象context的属性调用,自动绑定this
context.fn = this
const args = [...arguments].slice(1)
const result = context.fn(...args)
// 恢复默认的fn
context.fn = fn
return result
}
// 以下是测试代码
function test(arg1, arg2) {
console.log(arg1, arg2)
console.log(this.a, this.b)
}
test.call2({
a: 'a',
b: 'b'
}, 1, 2)
实现apply
apply
和call
实现类似,只是传入的参数形式是数组形式,而不是逗号分隔的参数序列。
因此,借助es6提供的...
运算符,就可以很方便的实现数组和参数序列的转化。
Function.prototype.apply2 = function(context) {
if(typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
const {
fn } = context
context.fn = this
let result