跳至主要內容

call 、apply 和 bind 的模拟实现

fxss原创javascriptcallapplybind大约 1 分钟

call

Function.prototype.myCall = function(context = window, ...args) {
  if (this === Function.prototype) {
    return undefined  // 用于防止 Function.prototype.myCall() 直接调用
  }
  context = context || window // 用于防止传入 null
  const fn = Symbol()
  context[fn] = this
  const result = context[fn](...args)
  delete context[fn]
  return result
}

验证:

let person = {
  name: 'fxss',
  age: 26,
  introduce: function(...args) {
    return `My name is ${this.name}, I'm ${this.age}${args.length ? `, I like ${args.join('/')}` : ''}.`
  }
}
let persom1 = {
  name: 'fxss1',
  age: 27,
}

var name = 'fxss2'
var age = '28'
let name1 = 'fxss3'
let age1 = '29'
console.log(window.name)
console.log(window.name1)

function introduce (...args) {
  return `My name is ${this.name}, I'm ${this.age}${args.length ? `, I like ${args.join('/')}` : ''}.`
}

console.log('person.introduce()', person.introduce())
console.log('introduce()', introduce())
console.log("person.introduce.call(persom1, 'reading', 'eat')", person.introduce.call(persom1, 'reading', 'eat'))
console.log("person.introduce.myCall(persom1, 'reading', 'eat')", person.introduce.myCall(persom1, 'reading', 'eat'))
console.log("introduce.call(null, 'reading', 'eat')", introduce.call(null, 'reading', 'eat'))
console.log("introduce.myCall(null, 'reading', 'eat')", introduce.myCall(null, 'reading', 'eat'))
console.log("introduce.call(undefined, 'reading', 'eat')", introduce.call(undefined, 'reading', 'eat'))
console.log("introduce.myCall(undefined, 'reading', 'eat')", introduce.myCall(undefined, 'reading', 'eat'))

apply

Function.prototype.myApply = function(context = window, args) {
  if (this === Function.prototype) {
    return undefined  // 用于防止 Function.prototype.myApply() 直接调用
  }
  context = context || window // 用于防止传入 null
  const fn = Symbol()
  context[fn] = this
  let result;
  if (Array.isArray(args)) {
    result = context[fn](...args);
  } else {
    result = context[fn]();
  }
  delete context[fn]
  return result
}

验证:

let person = {
  name: 'fxss',
  age: 26,
  introduce: function(...args) {
    return `My name is ${this.name}, I'm ${this.age}${args.length ? `, I like ${args.join('/')}` : ''}.`
  }
}
let persom1 = {
  name: 'fxss1',
  age: 27,
}

var name = 'fxss2'
var age = '28'
let name1 = 'fxss3'
let age1 = '29'
console.log(window.name)
console.log(window.name1)

function introduce (...args) {
  return `My name is ${this.name}, I'm ${this.age}${args.length ? `, I like ${args.join('/')}` : ''}.`
}

console.log('person.introduce()', person.introduce())
console.log('introduce()', introduce())
console.log("person.introduce.apply(persom1, ['reading', 'eat'])", person.introduce.apply(persom1, ['reading', 'eat']))
console.log("person.introduce.myApply(persom1, ['reading', 'eat'])", person.introduce.myApply(persom1, ['reading', 'eat']))
console.log("introduce.apply(null, ['reading', 'eat'])", introduce.apply(null, ['reading', 'eat']))
console.log("introduce.myApply(null, ['reading', 'eat'])", introduce.myApply(null, ['reading', 'eat']))
console.log("introduce.apply(undefined, ['reading', 'eat'])", introduce.apply(undefined, ['reading', 'eat']))
console.log("introduce.myApply(undefined, ['reading', 'eat'])", introduce.myApply(undefined, ['reading', 'eat']))

bind

Function.prototype.myBind = function(context, ...args) {
  if (this === Function.prototype) {
    throw new TypeError('Error')
  }
  const _this = this
  return function F(...args2) {
    if (this instanceof F) {
      return new _this(...args, ...args2)
    }
    return _this.bind(context, args.concat(args2))
  }
}

文中部分代码段引用自 https://github.com/ConardLi/awesome-coding-js/blob/master/JavaScript/手动实现call、apply、bind.mdopen in new window