
JavaScript函数的增强知识
1 函数属性和arguments
函数对象的属性

认识arguments

arguments转Array

箭头函数不绑定arguments

函数的剩余(rest)参数

2 纯函数的理解和应用
理解JavaScript纯函数

副作用概念的理解

纯函数的案例

判断下面函数是否是纯函数?

纯函数的作用和优势

3 柯里化的理解和应用
柯里化概念的理解

柯里化的代码转换

<!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>
4 组合函数理解和应用
组合函数概念的理解

<!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>
5 with、eval的使用
with语句的使用

eval函数

6 严格模式的使用
认识严格模式

开启严格模式

严格模式限制

<!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>
手写apply、call、bind函数实现(原型后)

JavaScript对象的增强知识
1 Object.defineProperty
对属性操作的控制

2 Object.defineProperties
Object.defineProperty

3 数据属性描述符
属性描述符分类

数据属性描述符

数据属性描述符测试代码

4 存取属性描述符
存取属性描述符
存储属性描述符测试代码
同时定义多个属性
5 对象的其他方法补充
对象方法补充