JavaScript函数的增强知识

1 函数属性和arguments

2 纯函数的理解和应用

3 柯里化的理解和应用

4 组合函数理解和应用

5 with、eval的使用

6 严格模式的使用

函数对象的属性length可以拿到形参的个数,对后面柯理化有用。length不会计算剩余参数的长度。

下面这张图,从第二个默认参数和第三个...others都不能算在函数属性的length里面。这里长度是1. 

函数的形参会放到函数对象的argument里面。

函数增强-函数的arguments

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function foo(m, n) {
      // arguments 类似数组对象
      console.log(arguments)
      // 1.默认用法:
      // 通过索引获取内容
      // console.log(arguments[0])
      // console.log(arguments[1])

      // // for循环遍历
      // for (var i = 0; i < arguments.length; i++) {
      //   console.log(arguments[i])
      // }
      // for (var arg of arguments) {
      //   console.log(arg)
      // }

      // 2.需求获取所有参数中的偶数
      // 数组 filter
      // for (var arg of arguments) {
      //   if (arg % 2 === 0) {
      //     console.log(arg)
      //   }
      // }
    //这里不能调用数组的方法 FILTER
      // var evenNums = arguments.filter(item => item % 2 === 0)
      // console.log(eventNums)

      // 2.1.将arguments转成数组方式一: for循环深度拷贝
      // var newArguments = []
      // for (var arg of arguments) {
      //   newArguments.push(arg)
      // }
      // console.log(newArguments)

      // 2.2.将arguments转成数组方式三: ES6中方式
      // var newArgs1 = Array.from(arguments)
      // console.log(newArgs1)
      // var newArgs2 = [...arguments]
      // console.log(newArgs2)

      // 2.3.将arguments转成数组方式二: 调用slice方法,通过this的优先级;原型
      var newArgs = [].slice.apply(arguments)
      // var newArgs = Array.prototype.slice.apply(arguments)
      console.log(newArgs)
    }

    foo(10, 25, 32, 41)





    // slice方法的回顾: 了解细节
    // var names = ["abc", "cba", "nba", "mba"]
    // var newNames = names.slice() // this -> names

    // // slice方法 -> 函数
    // console.log(newNames)
    // obj.foo() // this -> obj


  </script>

</body>
</html>

函数增强-箭函的arguments

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <script>
    // 1.箭头函数不绑定arguments
    // var bar = () => {
    //   console.log(arguments)
    // }

    // bar(11, 22, 33)


    // 2.函数的嵌套箭头函数,由于箭头函数没有argument,所以去外层作用域去找了,
    //这里的argument指向foo函数的。
    function foo() {
      var bar = () => {
        console.log(arguments)
      }
      bar()
    }

    foo(111, 222)

  </script>

</body>
</html>

函数增强-函数的剩余参数

在es6里面,有剩余参数来代替argument。

注意事项: 剩余参数需要写到其他的参数最后

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 剩余参数: rest parameters
    function foo(num1, num2, ...otherNums) {
      // otherNums数组
      console.log(otherNums)
    }

    foo(20, 30, 111, 222, 333)


    // 默认一个函数只有剩余参数
    function bar(...args) {
      console.log(args)
    }

    bar("abc", 123, "cba", 321)

    // 注意事项: 剩余参数需要写到其他的参数最后

  </script>

</body>
</html>

函数增强-纯函数概念理解

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function sum(num1, num2) {
      return num1 + num2
    }

    // 不是一个纯函数,info.flag = "已经打印结束"给对象添加了一个key,
    //  原来的对象发生了改变 ,这就是副作用
    var address = "广州市"
    function printInfo(info) {
      console.log(info.name, info.age, info.message)
      info.flag = "已经打印结束"
      address = info.address
    }

    var obj = {
      name: "why",
      age: 18,
      message: "哈哈哈哈"
    }

    printInfo(obj)

    console.log(obj)
    if (obj.flag) {
      
    }

  </script>

</body>
</html>

函数增强-数组splice和slice

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    var names = ["abc", "cba", "nba", "mba"]

    // 1.slice: 纯函数
    var newNames = [].slice.apply(names, [1, 3])
    console.log(names)

    // 2.splice: 操作数组的利器(不是纯函数),会修改原函数
    names.splice(2, 2)
    console.log(names)
    
  </script>

</body>
</html>

函数增强-纯函数作用优势

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 1.安心的写: 你不需要去关心外层作用域中的值, 目前是什么状态
    var counter = 0

    function add(num) {
      return num
    }

    // 2.安心的用: 调用函数时, 可以知道: 确定的输入一定产生确定的输出
    add(5) // 10
    add(5) // 10


    // react中的编写函数组件,这样子写是错误
    function Foo(props) {
      console.log(props.name)
      props.name = "kobe"
    }


  </script>

</body>
</html>

函数增强-柯里化函数变换

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 普通的函数
    function foo1(x, y, z) {
      console.log(x + y + z)
    }

    // foo1(10, 20, 30)
    // foo1(20, 33, 55)


    // 因为foo不是一个柯里化的函数, 所以目前是不能这样调用
    // 柯里化函数
    function foo2(x) {
      return function(y) {
        return function(z) {
          console.log(x + y + z)
        }
      }
    }

    foo2(10)(20)(30)
    foo2(20)(33)(55)


    // 另外一种写法: 箭头函数的写法
    // function foo3(x) {
    //   return y => {
    //     return z => {
    //       console.log(x + y + z)
    //     }
    //   }
    // }

    var foo3 = x => y => z => {
      console.log(x + y + z)
    }

    foo3(10)(20)(30)


  </script>

</body>
</html>

函数增强-柯里化案例练习一

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    // 案例一: 打印一些日志
    // 信息一: 日志的时间
    // 信息二: 日志的类型: info/debug/feature
    // 信息三: 具体的信息

    // 1.没有柯里化的时候做法
    function logInfo(date, type, message) {
      console.log(`时间:${date} 类型:${type} 内容:${message}`)
    }

    // // 打印日志
    // logInfo("2022-06-01", "DEBUG", "修复界面搜索按钮点击的bug")

    // // 又修复了一个bug
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
    // logInfo("2022-06-01", "DEBUG", "修复了从服务器请求数据后展示的bug")
    
    // logInfo("2022-06-01", "FEATURE", "增加了商品的过滤功能")


    // 2.对函数进行柯里化: 柯里化函数的做法
    // var logInfo = date => type => message => {
    //   console.log(`时间:${date} 类型:${type} 内容:${message}`)
    // }
    function logInfo(date) {
      return function(type) {
        return function(message) {
          console.log(`时间:${date} 类型:${type} 内容:${message}`)
        }
      }
    }

    var logToday = logInfo("2022-06-01")
    var logTodayDebug = logToday("DEBUG")
    var logTodayFeature = logToday("FEATURE")

    // 打印debug日志
    logTodayDebug("修复了从服务器请求数据后展示的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")
    logTodayDebug("修复界面搜索按钮点击的bug")

    logTodayFeature("新建过滤功能")
    logTodayFeature("新建搜索功能")

  </script>

</body>
</html>

函数增强-柯里化案例练习二

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function sum(num1, num2) {
      return num1 + num2
    }

    sum(5, 10)
    sum(5, 15)
    sum(5, 18)

    // makeAdder函数就是对sum的柯里化
    function makeAdder(count) {
      function add(num) {
        return count + num
      }
      return add
    }

    // 1.数字和5相加
    var adder5 = makeAdder(5)
    adder5(10)
    adder5(15)
    adder5(18)

    // 2.数组和10相加
    var adder10 = makeAdder(10)
    adder10(10)
    adder10(16)
    adder10(19)

    // adder5 = null
    // adder10 = null

  </script>

</body>
</html>

每次想要生成柯理化函数手动改很麻烦,于是需要一个自动生成的方法。

柯理化函数不是一定要用的,只是有些时候是需要复用某些参数的时候,我们可以用这个来优化代码。

函数增强-自动柯里化函数

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    function foo(x, y, z) {
      console.log(x + y + z)
    }

    function sum(num1, num2) {
      return num1 + num2
    }

    function logInfo(date, type, message) {
      console.log(`时间:${date} 类型:${type} 内容:${message}`)
    }

    // 手动转化

    // 封装函数: 自动转化柯里化过程(有一点难度)
    function hyCurrying(fn) {
      function curryFn(...args) {
        // 两类操作:
        // 第一类操作: 继续返回一个新的函数, 继续接受参数
        // 第二类操作: 直接执行fn的函数
        if (args.length >= fn.length) { // 执行第二类
          // return fn(...args)
          return fn.apply(this, args)
        } else { // 执行第一类
          return function(...newArgs) {
            // return curryFn(...args.concat(newArgs))
            return curryFn.apply(this, args.concat(newArgs))
          }
        }
      }

      return curryFn
    }

    // 对其他的函数进行柯里化
    var fooCurry = hyCurrying(foo)
    fooCurry(10)(20)(30)
    fooCurry(55, 12, 56)

    var sumCurry = hyCurrying(sum)
    var sum5 = sumCurry(5)
    console.log(sum5(10))
    console.log(sum5(15))
    console.log(sum5(18))

    var logInfoCurry = hyCurrying(logInfo)
    logInfoCurry("2022-06-01")("DEBUG")("我发现一个bug, 哈哈哈哈")


    // 举个栗子
    // var names = ["abc", "cba", "nba"]
    // // spread
    // console.log(...names)

  </script>

</body>
</html>

函数增强-组合函数的案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    var num = 100

    // 第一步对数字*2
    function double(num) {
      return num * 2
    }

    // 第二步对数字**2
    function pow(num) {
      return num ** 2
    }

    console.log(pow(double(num)))
    console.log(pow(double(55)))
    console.log(pow(double(22)))

    // 将上面的两个函数组合在一起, 生成一个新的函数
    function composeFn(num) {
      return pow(double(num))
    }

    console.log(composeFn(100))
    console.log(composeFn(55))
    console.log(composeFn(22))

  </script>

</body>
</html>

函数增强-组合函数的封装

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 第一步对数字*2
    function double(num) {
      return num * 2
    }

    // 第二步对数字**2
    function pow(num) {
      return num ** 2
    }

    // 封装的函数: 你传入多个函数, 我自动的将多个函数组合在一起挨个调用
    function composeFn(...fns) {
      // 1.边界判断(edge case)
      var length = fns.length
      if (length <= 0) return
      for (var i = 0; i < length; i++) {
        var fn = fns[i]
        if (typeof fn !== "function") {
          throw new Error(`index position ${i} must be function`)
        }
      }

      // 2.返回的新函数
      return function(...args) {
        var result = fns[0].apply(this, args)
        for (var i = 1; i < length; i++) {
          var fn = fns[i]
          result = fn.apply(this, [result])
        }
        return result
      }
    }

    var newFn = composeFn(double, pow, console.log)
    newFn(100)
    newFn(55)
    newFn(22)
    // console.log(newFn(100))
    // console.log(newFn(55))
    // console.log(newFn(22))

  </script>

</body>
</html>

额外知识-严格模式的使用

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 给整个script开启严格模式
    "use strict"

    // 给一个函数开启严格模式
    function foo() {
      "use strict"
    }

    //默认严格模式
    class Person {
      
    }


  </script>

</body>
</html>

额外知识-严格模式的限制

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    "use strict"
    // 1.不会意外创建全局变量
    // function foo() {
    //   message = "Hello World"
    // }

    // foo()
    // console.log(message)

    // 2.发现静默错误
    var obj = {
      name: "why"
    }

    Object.defineProperty(obj, "name", {
      writable: false,
      configurable: false
    })

    // obj.name = "kobe"
    console.log(obj.name)

    // delete obj.name
    console.log(obj)

    // 3.参数名称不能相同
    // function foo(num, num) {

    // }

    // 4.不能以0开头
    // console.log(0o123)

    // 5.eval函数不能为上层创建变量
    // eval(`var message = "Hello World"`)
    // console.log(message)

    // 6.严格模式下, this是不会转成对象类型的
    function foo() {
      console.log(this)
    }
    foo.apply("abc")
    foo.apply(123)
    foo.apply(undefined)
    foo.apply(null)
    
    // 独立函数执行默认模式下, 绑定window对象
    // 在严格模式下, 不绑定全局对象而是undefined
    foo()

  </script>

</body>
</html>

对象增强-对象属性的控制

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>

    var obj = {
      name: "why",
      age: 18
    }

    // 默认情况下属性都是没有特别的限制
    // obj.name = ""
    // delete obj.name
    // console.log(obj.name)


    // 可以对对象中的属性进行某些限制
    

  </script>

</body>
</html>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_56663198/article/details/131470854