title: 函数柯里化
categories: Javascript
tag:

  • 实现apply,call,bind
    date: 2021-11-16 09:16:34

实现call, apply,bind

实现 call

  1. Function.prototype.Dhcall = function (thisArg, ...args) {
  2. //获取需要被执行的函数
  3. var fn = this
  4. //对thisArg转换为对象类型,防止传入的是非对象类型
  5. thisArg = thisArg != null && thisArg != undefined ? Object(thisArg) : window
  6. thisArg.fn = fn
  7. var result = thisArg.fn(...args)
  8. //会多出来属性,所以要删掉
  9. delete thisArg.fn
  10. return result
  11. }
  12. //测试代码======================================
  13. function foo() {
  14. console.log('foo被执行', this)
  15. }
  16. function bar(num1, num2, num3) {
  17. console.log('bar被执行', this, num1, num2, num3)
  18. return num1 + num2 + num3
  19. }
  20. foo.Dhcall({ name: 'why' })
  21. var result = bar.Dhcall('abc', 10, 20, 30)
  22. console.log(result)

实现 apply

  1. Function.prototype.Dhapply = function (thisArg, argsArray) {
  2. //获取到要执行的函数,也就是this
  3. var fn = this
  4. //处理绑定的thisArg
  5. thisArg = thisArg != null && thisArg != undefined ? Object(thisArg) : window
  6. thisArg.fn = fn
  7. var result
  8. //1. 可以用条件判断==================
  9. /*
  10. if (!argsArray) {
  11. result = thisArg.fn()
  12. } else {
  13. result = thisArg.fn(...argsArray)
  14. }
  15. */
  16. //2. 可以使用三元运算符呀=============
  17. /*
  18. argsArray = argsArray ? argsArray : []
  19. */
  20. //3. 可以使用逻辑
  21. argsArray = argsArray || []
  22. result = thisArg.fn(...argsArray)
  23. delete thisArg.fn
  24. return result
  25. }
  26. //测试代码====================================
  27. // 两个参数
  28. function sum(num1, num2) {
  29. console.log('sum被调用', this, num1, num2)
  30. return num1 + num2
  31. }
  32. // 一个参数
  33. function single(num1) {
  34. console.log('single被调用', this, num1)
  35. return num1
  36. }
  37. function none() {
  38. console.log('none被调用', this)
  39. }
  40. // 两个参数
  41. var result = sum.Dhapply('a', [10, 20])
  42. console.log(result)
  43. // 一个参数也必须是数组类型
  44. var result = single.Dhapply('a', [10])
  45. console.log(result)
  46. // 没有参数.那么Dhapply第二个参数是undefined,所以不能被迭代。会报错。
  47. var result = none.Dhapply('a')
  48. console.log(result)

实现 bind

这是原生的 bind 实现

  1. function foo() {
  2. console.log('foo被执行', this)
  3. }
  4. function sum(num1, num2, num3, num4) {
  5. console.log(num1, num2, num3, num4)
  6. }
  7. //没有参数
  8. var bar = foo.bind('abc')
  9. bar()
  10. //有参数,在bind的时候传
  11. var newSum = sum.bind('aaa', 10, 20, 30, 40)
  12. newSum()
  13. //有参数,在调用的时候传
  14. var newSum = sum.bind('aaa')
  15. newSum(10, 20, 30, 40)
  16. //有参数,两边都传
  17. var newSum = sum.bind('aaa', 10, 20)
  18. newSum(30, 40)

下面手写 bind 进行实现

  1. Function.prototype.Dhbind = function (thisArg, ...argArray) {
  2. //1. 获取到真实需要调用的函数
  3. var fn = this
  4. //2. 绑定this
  5. thisArg = thisArg !== undefined && thisArg !== null ? Object(thisArg) : window
  6. function proxyFn(...args) {
  7. thisArg.fn = fn
  8. var finalArgs = [...argArray, ...args]
  9. var result = thisArg.fn(...finalArgs)
  10. delete thisArg.fn
  11. return result
  12. }
  13. return proxyFn
  14. }
  15. //测试代码================================================
  16. function sum(num1, num2, num3, num4) {
  17. console.log(this, num1, num2, num3, num4)
  18. return num1 + num2 + num3 + num4
  19. }
  20. var newSum = sum.Dhbind('abc', 10, 20)
  21. var res = newSum(30, 40)
  22. console.log(res) //100

认识 arguments

arguments 是一个 对应于 传递给函数的参数类数组(array-like)对象

默认会有一个 arguments,类数组对象中(长的像是一个数组,本质上是一个对象:arguments)

  1. function foo(num1, num2, num3) {
  2. //默认会有一个arguments,类数组对象中(长的像是一个数组,本质上是一个对象:arguments)
  3. console.log(arguments)
  4. console.log(num1, num2, num3)
  5. }
  6. foo(10, 20, 30, 40, 50)

arguments 操作

array-like 意味着它不是一个数组类型,而是一个对象类型:

  • 但是它却拥有数组的一些特性,比如说 length,比如可以通过 index 索引来访问;
  • 但是它却没有数组的一些方法,比如 forEach、map 等;

常见的对 arguments 的操作有三个

  1. 获取参数的长度
  1. console.log(arguments.length)
  1. 根据索引值获取某一参数
  1. console.log(arguments[2])
  2. console.log(arguments[3])
  3. console.log(arguments[4])
  1. callee 获取当前 arguments 所在的函数
  1. console.log(arguments.callee)

所以为了可以使用数组方法,我们把 arguments 转换为数组

  1. //把arguments转换为数组.slice全部放到数组里面,然后返回这个新数组
  2. var newArr = Array.prototype.slice.call(arguments)
  3. console.log(newArr)

那么 Array 中 slice 的实现原理

  1. //这是slice原理
  2. Array.prototype.Dhslice = function (start, end) {
  3. start = start || 0
  4. end = end || arr.length
  5. var arr = this
  6. var newArray = []
  7. for (let i = start; i < end; i++) {
  8. newArray.push(arr[i])
  9. }
  10. return newArray
  11. }
  12. var newArray = Array.prototype.Dhslice.call(['a', 'b', 'c', 'd'], 1, 4)
  13. console.log(newArray) // [10, 20, 30, 40, 50]

把 arguments 转换为数组另外的方法

  1. //ES6语法
  2. var newArr = Array.from(arguments)
  3. console.log(newArr)

7_函数柯里化 - 图1

  1. //展开运算符
  2. var newArr = [...arguments]
  3. console.log(newArr)

注意,箭头函数没有 arguments

箭头函数是不绑定 arguments 的,所以我们在箭头函数中使用 arguments 会去上层作用域查找

  1. var foo = () => {
  2. console.log(arguments)
  3. }
  4. foo() //浏览器中没有arguments,node中有arguments

那我们在箭头函数中,应该使用剩余参数