Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(javascript)实现call和apply #22

Open
Zhengy1995 opened this issue Mar 17, 2020 · 0 comments
Open

(javascript)实现call和apply #22

Zhengy1995 opened this issue Mar 17, 2020 · 0 comments

Comments

@Zhengy1995
Copy link
Owner

Zhengy1995 commented Mar 17, 2020

call和apply

熟悉js的应该对这两个函数都不陌生,日常开发很多地方会用到,先来看看两个使用的例子

const obj = {a: 1, b: 2}
const fn = function(a) { console.log(a + this.a) }
fn(1) // NaN
fn.call(obj, 2) // 3
fn.apply(obj, [3]) // 4

可以看到,如果不用callapply,函数体中的this会指向window导致this.a = undefined,为了解决这个指向问题,聪明的歪果仁就发明了callapply这样的黑科技

区别

从上面两个函数调用的形式就可以看出call传入this的指向后,直接传入函数需要的参数,而apply则需要将参数包裹在一个Array中传入,除此之外,并无太大区别(其实还是有点的,call性能比apply高一些),下面来看看怎么实现

part1 实现深拷贝

callapply是需要将this重新指向的,我的思路则是将函数绑定到对象中,从而改变this的指向,但是又不能改变原有对象,因此,必须先深拷贝原始对象,之后再进行绑定,废话不多说,直接上代码

const deepClone = obj => {
  let result
  if(obj instanceof Array) {
    result = obj.map(item => deepClone(item))
  }
  else if(typeof obj == 'object') {
    result = {}
    for(let key in obj) {
      result[key] = deepClone(obj[key])
    }
  }
  else result = obj
  return result
}

part2 实现call

直接贴代码,apply的实现步骤与call类似,不单独写了

const call = (fn, thisArg, ...args) => {
  if(!thisArg || thisArg == window) return fn(...args)
  else {
    const _this = deepClone(thisArg)
    // __fn的定义需要注意
    const __fn = Symbol('__fn')
    _this[__fn] = fn
    _this[__fn](...args)
  }
} 

总结

总体需要考虑几个因素

  1. 原始对象的深拷贝
  2. 使用Symbol命名,以避免__fn的命名与原始对象中的原有属性冲突
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant