Skip to content

实现call方法

js
Function.prototype.myCall = function (context, ...args) {
  if (!context || context === null) {
    context = window
  }
  // 创建唯一的key值,作为我们构造的context内部方法名
  let fn = Symbol()
  // this指向调用call的函数
  context[fn] = this
  // 执行函数并返回结果,相当于把自身作为传入的context的方法进行调用了
  return context[fn](...args)
}
js
// 第一版
Function.prototype.myCall1 = function (context) {
  context.fn = this
  context.fn()
  delete context.fn
}

// 第二版
Function.prototype.myCall2 = function (context) {
  context.fn = this
  var args = []
  for (i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']')
  }
  eval('context.fn(' + args + ')')
  delete context.fn
}

// 第三版
Function.prototype.myCall3 = function (context) {
  var context = context || window
  context.fn = this
  var args = []
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']')
  }
  var result = eval('context.fn(' + args + ')')
  delete context.fn
  return result
}

// 最终版
Function.prototype.myCall = function (context) {
  var context = context || window
  context.fn = this
  var args = []
  for (var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']')
  }
  var result = eval('context.fn(' + args + ')')
  delete context.fn
  return result
}

var foo = {
  value: 1,
}

function bar(name, age) {
  console.log(name)
  console.log(age)
  console.log(this.value)
}
// bar.myCall1(foo);
bar.myCall2(foo, 'name', 18)

// bar.myCall(foo, 'kevin', 18);
js
Function.prototype.myCall = function (context, ...args) {
  let ctx = context || window
  // 将当前被调用的方法定义在ctx.func上
  // 新建一个唯一的Symbol变量避免重复
  let func = Symbol()
  ctx[func] = this
  args = args ? args : []
  // 以对象调用形式调用func,此时this指向ctx也就是传入的需要绑定的this指向
  const res = args.length > 0 ? ctx[func](...args) : ctx[func]()
  // 删除该方法,不然会对传入对象造成污染
  delete ctx[func]
  return res
}
js
// call做了什么
// - 将函数设为对象的属性
// - 执行和删除这个函数
// - 指定this到函数并传入给定参数执行函数
// - 如果不传入参数,默认指向为window

// 模拟call bar.mycall(null)
// 实现一个call方法
// 原理:利用context.xxx = self obj.xx = func --> obj.xx()

Function.prototype.myCall = function (context = window, ...args) {
  // this --> func    context --> obj  args --> 传递过来的参数
  // 在context上加一个唯一值不影响context上的属性
  let key = Symbol('key')
  // context为调用的上下文,this此处为函数,将这个函数作为context的方法
  context[key] = this
  let result = context[key](...args)
  delete context[key]
  return result
}

如有转载或 CV 的请标注本站原文地址