Function.prototype.call / apply / bind

Function.prototype.call

方法说明

call() 允许为不同的对象分配和调用属于一个对象的函数/方法。
call() 提供新的 this 值给当前调用的函数/方法。你可以使用 call 来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)

源码的关键点在于

在传递进来的上下文对象中构造一个需要执行的方法,比如:
ctx = { fn: test () { console.log(this.name) } },这样方法内this就会指向ctx对象,就达到了在指定的上下文对象上运行不属于它的方法

源码

Function.prototype.myCall = function (ctx, ...args) {
  // 非严格模式下,ctx为null、undefined时,默认为全局对象
  ctx = ctx || window
  // 就单纯为了生成一个ctx对象的key,当然写死也可以
  const fn = Symbol()
  // 这里的this是指调用myCall方法的函数对象,比如:test.myCall(obj, arg1, arg2)中的test函数
  ctx[fn] = this
  // 执行ctx对象里的fn方法
  const res = ctx[fn](...args)
  // 从ctx对象上删除fn属性,不然会改变传递进来的ctx对象
  delete ctx[fn]
  // 返回函数执行的结果
  return res
}

// 示例代码
const obj = {
  name: 'I am obj'
}
function test (arg1, arg2) {
  return `${this.name}, ${arg1} ${arg2}`
}
const res = test.myCall(obj, 'hello', 'world !!')
console.log(res)  // I am obj,hello world !!

Function.prototype.apply

方法说明

apply方法的作用和call方法一样,不同之处在于提供参数的方式,apply使用参数数组,而call使用一组参数列表

源码关键点在于

同Function.prototype.call方法的实现一致,还是要在传递进来的上下文对象中构建一个需要执行的方法

源码

Function.prototype.myApply = function (ctx, args) {
  ctx = ctx || window
  const fn = Symbol()
  ctx[fn] = this
  const res = ctx[fn](...args)
  delete ctx[fn]
  return res
}

// 示例代码
function test (arg1, arg2) {
  return `${this.name}, ${arg1} ${arg2}`
}
const obj = {
  name: 'I am obj'
}
const res = test.myApply(obj, ['hello', 'world !!'])
console.log(res)  // I am obj, hello world !!

Function.prototype.bind

方法说明

作用同call和apply一样,在指定对象上执行指定方法,不同点在于:
1、bind返回的是一个可执行函数
2、通过bind实现偏函数

源码关键点在于

1、闭包:缓存bind方法的参数(上下文对象和参数列表)
2、返回可执行函数
3、可执行函数的内部通过apply方法实现对象和方法的绑定
4、偏函数的关键在于闭包(缓存bind方法的参数)和第二次函数调用时参数的拼接

源码

Function.prototype.myBind = function (ctx, ...bindArgs) {
  // ctx、fnObj和args会形成闭包,fnObj是函数对象,即: test.bind(obj, arg1, arg2)中的test
  const fnObj = this
  return function (...fnArgs) {
    // 具体的函数绑定是通过apply方法实现的
    return fnObj.apply(ctx, [...bindArgs, ...fnArgs])
  }
}

// 示例
const obj = {
  name: 'I am obj'
}
function test (arg1, arg2) {
  return `${this.name}, ${arg1} ${arg2} !!`
}
// 绑定
const fn = test.bind(obj, 'hello', 'world')
const resFn = fn()
console.log(resFn)  // I am obj, hello world !!
// 偏函数
const pFn = test.bind(obj, 'hello')
const resPfn = pFn('world')
console.log(resPfn)    // I am obj, hello world !!
发布了14 篇原创文章 · 获赞 0 · 访问量 369
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览