call实现

思路:

(1)判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。 (2)判断传入上下文对象是否存在,如果不存在,则设置为 window 。 (3)处理传入的参数,截取第一个参数后的所有参数。 (4)将函数作为上下文对象的一个属性。 (5)使用上下文对象来调用这个方法,并保存返回结果。 (6)删除刚才新增的属性。 (7)返回结果。

代码:

  1. Function.prototype._call = function (context) {
  2. if(typeof this !== "function"){
  3. return
  4. }
  5. let args = [...arguments].slice(1)
  6. context = context || window
  7. context.fn = this
  8. // 由于[...arguments].slice(1),
  9. // 所以就算不传第二个参数,args也是一个空数组,可以被解构
  10. let res = context.fn(...args)
  11. delete context.fn
  12. return res
  13. }

apply实现

思路:

(1)判断调用对象是否为函数,即使我们是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。 (2)判断传入上下文对象是否存在,如果不存在,则设置为 window 。 (3)处理传入的参数,截取第一个参数后的所有参数。 (4)将函数作为上下文对象的一个属性。 (5)使用上下文对象来调用这个方法,并保存返回结果。 (6)删除刚才新增的属性。 (7)返回结果。

代码:

  1. Function.prototype._apply = function (context) {
  2. if (typeof this !== "function") {
  3. console.error("type error");
  4. return
  5. }
  6. let args = arguments[1]
  7. context = context || window
  8. context.fn = this
  9. let res = null
  10. // 当没有传入第二个参数时,
  11. // 由于args不能迭代,也就是不能解构,所以要判断一下
  12. if (args) {
  13. res = context.fn(...args)
  14. } else {
  15. res = context.fn()
  16. }
  17. return res
  18. }

测试:

  1. let obj = {
  2. name: "mikasa"
  3. }
  4. let user = {
  5. getName(value) {
  6. console.log(value);
  7. console.log(this.name);
  8. }
  9. }
  10. // 成功输出
  11. user.getName._call(obj, 111)
  12. user.getName._apply(obj, [111])

image.png