《前端面试手记》之常考的源码实现

? 内容速览 ?

  • 手动实现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

applycall实现类似,只是传入的参数形式是数组形式,而不是逗号分隔的参数序列。

因此,借助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
  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值