1 函数属性和arguments
2 纯函数的理解和应用
3 柯里化的理解和应用
4 组合函数理解和应用
5 with、eval的使用
6 严格模式的使用
函数对象的属性length可以拿到形参的个数,对后面柯理化有用。length不会计算剩余参数的长度。
下面这张图,从第二个默认参数和第三个...others都不能算在函数属性的length里面。这里长度是1.
函数的形参会放到函数对象的argument里面。
扫描二维码关注公众号,回复:
16576462 查看本文章
函数增强-函数的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>