1.1 let和const
上课时间:2021.09.26
课堂内容
| 标题 | var | let | const |
|---|---|---|---|
| 重复声明 | Y | N | N |
| 作用域 | 函数级 | 块级 | 块级 |
| 变量提升 | 声明-初始化-执行-赋值 | 声明-执行-初始化-赋值 | 同let |
问题思考
let深入理解-变量提升和暂时性死区:let有变量提升吗
1.2 块级作用域
上课时间:2021.10.17
课堂内容
| 标题 | var | let | const |
|---|---|---|---|
| 重复声明 | Y | N | N |
| 作用域 | 函数级 | 块级 | 块级 |
| 变量提升 | 声明-初始化-执行-赋值 | 声明-执行-初始化-赋值 | 同let |
1.3 解构赋值
上课时间:2021.10.19
课堂内容
可以结构赋值的对象: 对象 数组 字符串等 iterable 对象
1.4 展开运算符
上课时间:2021.10.19
课堂内容
...是一层深拷贝
扩展运算符的底层使用 for...of 实现的循环
1.5 Set 和 WeakSet
上课时间:2021.10.19
课堂内容
Set类似数组,但是成员的值都是唯一的,没有重复
Set是一个构造函数 用于生成Set数据结构
属性:size
方法:clear(),delete(),add(),has()
遍历操作:keys(), values(), entries(),forEach()
set的遍历是有序的,遍历顺序就是插入顺序。这个特性非常有用,比如用Set保存一个回调函数列表,调用时就可以保证按照顺序调用
Set结构的实例默认可遍历,这意味着可以省略keys和values方法,直接用for...of遍历Set
WeakSet与Set类似,但是有两个区别:1.WeakSet的成员只能是对象 2.WeakSet中的对象都是弱引用,不计入垃圾回收机制。因此不能用于遍历,适合临时存放对象和存放跟对象绑定的信息。
问题思考
Set内部如何判断两个值相等? 使用算法 Same-value equality,类似 === 运算符,与===的区别是NaN在此处等于自身。
1.6 Map 和 WeakMap
上课时间:2021.10.22
课堂内容
Map类似对象,也是键值对的集合。但是键的值不仅限于字符串。是一种更完善的Hash结构实现。
Map的键实际上是和内存地址绑定的,内存地址不一样就视为两个键,除了NaN
属性:size
方法:clear(),delete(),has(),set(),get()
遍历操作:keys(), values(), entries(),forEach()
与其他类型的转换
- Map转数组 [...testMap.vlaues()] [...testMap.keys()]
- 数组转Map new Map([testArray])
- Map转对象 键都是字符串 循环转换
- 对象转Map 循环转换
- Map转为JSON 转为对象或数组再转json
- JSON转为Map 转为对象或数组再转map
WeakMap与Map类似,但是有两个区别:1.WeakMap只接受对象作为键名 2.WeakMap中的键都是弱引用,不计入垃圾回收机制。因此不能用于遍历,它的键适合绑定将来有可能消失的对象,比如Dom节点。
1.7 函数新增内容
上课时间:2021.10.27
课堂内容
函数参数默认值
如果参数默认值是变量,则变量所处的作用域先是当前函数作用域,然后才是全局作用域 如果函数参数的默认值是个函数,那么参数的作用域是其声明时的作用域,如下🌰
var x=1;
function f(x, y=x) {
console.log(y)
}
f(2) // 2
let foo = 'outer'
function bar(func = x => foo) {
let foo = 'inner'
console.log(func())
}
bar() // outer
// 匿名函数声明时 bar的作用域还没有形成 因此foo指向外部作用域
rest参数
Es6用 ...变量名 的方式替代 arguments 参数
扩展运算符 ...
扩展运算符调用的是数据结构的Iterator接口,有 Iterator接口的对象都可以用...变为真正的数组。如Set Map string等。如果没有Iterator接口,可以先调用Array.from转换为数组,再使用扩展运算符。
一些实际应用: 合并数组,将字符串转为数组等。
箭头函数
- 箭头函数内部的this对象,就是定义时的this对象,不是使用时的this对象
- 不可以当做构造函数
- 不可以使用arguments对象
- 不可以使用yield命令
函数绑定
ES7提出函数绑定 :: 用于替代call apply bind的调用
:: 左边是一个对象,右边是一个函数,该运算符自动将左边的对象,作为上下文环境(this)绑定到右边函数上面
foo::bar
// 等同于
::foo.bar
// 等同于
bar.bind(foo)
- 由于::返回的还是原来的对象,因此可以链式调用
尾调用优化
尾调用是函数式编程的一个重要概念,是指某一个函数的 最后一步 是调用另一个函数
每个函数调用会在内存中形成一个调用帧,函数返回帧才会消失。调用帧组成一个调用栈(call stack)。在严格模式下,ES6使用尾调用,可以只保留最后一个调用帧,从而大大节省内存。不会发生栈溢出错误。
非严格模式下,可以自己实现尾调用优化:将递归改为循环,每次返回自己的另一个版本。
function trampoline(fn) {
while(fn && fn instanceof Function) {
fn = fn()
}
return fn
}
// fn符合递归条件 每次返回自己的另一个版本
问题思考
这些this的面试题,你都会嘛 7道关于this的面试题
1.8 数组新增方法
上课时间:2021.11.14
课堂内容
数组方法分为 Array构造函数原型上的方法和数组对象方法
Array构造函数上的方法
- Aarry.from: 将类数组(有下标,有length)转化为数组 用法: Array Array.from(lis[, mapFn[, thisArg]])([]在手册中代表可选参数)
- Array.of 将参数转为数组 用法:Array Array.of(element0[, element1[, ...[, elementN]])
- Array.isArray
1.9 数组新增方法
上课时间:2021.11.14
数组对象方法
- includes,startWith,endWith
- find, findIndex
1.10 数组扁平化flat和includes
上课时间:2021.11.14
- flat 用法:Array Array.flat([, number])
1.11 字符串新增方法
上课时间:2021.11.15
课堂内容
- ES6为字符串新增了遍历器接口,字符串可以由for...of循环遍历
- includes,startWith,endsWith 返回Boolean
- repeat 返回新的字符串
- padStart, padEnd
字符串自动补全长度 String String.padStart(number[, padString]) padString默认为空格
1.12 模板字符串
上课时间:2021.11.15
课堂内容
${}格式表示字符串
- 标签模板:紧跟在一个函数后面,该函数将被调用来处理这个模板字符串 如果模板字符串中有变量,模板字符串将被处理为多个参数,再调用。
标签模板的一个重要应用是过滤html字符串,防止用户输入恶意内容;另一个应用是多语言转换(国际化处理)
String.raw()
String.raw方法往往用于充当模板字符串的处理函数,它会将所有的变量都替换,并将反斜线都转义。
String.raw `hhh\n${2+3}` // 'hhh\\n5'
1.13 对象的新增方法
上课时间:2021.11.15
课堂内容
属性的简洁表示法
hello:function() {... === hello() {...
属性名表达式
ES6允许将表达式作为对象的属性名 obj['a'+'bc'] = 123;
方法的name属性
函数的name属性返回函数名,基础用法是 person.sayName.name = 'sayName'
如果对象的方法使用了取值函数get, 则name属性不在该方法上面,而是在该方法属性的描述对象的get属性上面
const obj = {
get foo() {},
set foo(x) {}
}
obj.foo.name // undefined
const des = Object.getOwnPropertyDescription(obj, 'foo')
des.get.name // 'get foo'
Object.is()
ES5比较二者是否相等: == 的缺点: 自动转换数据类型
=== 的缺点:NaN不等于NaN +0 === -0
Object.is是严格相等 NaN等于NaN, +0不等于-0
Object.assign()
将源对象所有的可枚举属性复制到目标对象,第一个参数是目标对象,其他都是源对象
只有一个参数:
- 如果只有一个对象,则直接返回该参数
- 如果上面的参数不是对象,会先转成对象再复制。不可转为对象则报错
如果非对象参数出现在源对象的位置,那么这些参数都会转为对象,如果是字符串,将被转为数组,其他不可转为对象的则跳过。
因为只有字符串的包装对象会产生可枚举属性,所以字符串会被Object.assign转为数组。
Object.assign是浅拷贝。如果源对象的某个属性的值是对象,那么目标对象复制的是这个对象的引用。
属性的可枚举性
描述对象的 enumerable 被称为“可枚举性”
以下方法会忽略enumerable为false的属性:
- for...in 只遍历自身的和继承的可枚举属性
- Object.keys 返回对象自身的可枚举属性
- JSON.stringify 只格式化自身的可枚举属性
- Object.assign 只复制自身的可枚举属性
ES6规定 所有Class原型的方法都是不可枚举的 使用 for...in 会引入继承的属性,让问题复杂化,因此应尽量用Object.keys代替for...in
属性的遍历
- for...in 循环遍历
自身和继承的可枚举属性 - Object.keys [] 返回
自身的可枚举属性 - Object.getOwnPropertyNames [] 返回自身的
可枚举和不可枚举属性,不含Symbol - Object.getOwnPropertySymbols [] 返回自身的
所有Symbol属性 - Reflect.ownKeys [] 返回自身
所有属性
proto, Object.setPrototypeOf(), Object.getPrototypeOf()
- __proto__的值是对象原型
- setPrototyeof作用与 __proto__相同,用来设置一个对象的prototype对象,ES6推荐使用
- getPrototypeof 读取一个对象的prototype对象
Object.keys(), Object.values(), Object.entries()
分别返回属性,键值,键值对组成的数组
- 都是返回
自身可枚举的值 - 顺序不可控
扩展运算符
- 结构赋值是
浅拷贝, 如果一个键的值是复合类型的值(数组,对象,函数),那么解构赋值的是这个值的引用,而不是这个值的副本。 - 解构赋值不会复制继承来的对象属性
Object.getOwnPropertyDescriptors()
返回对象所有自身属性(非继承属性)的描述对象
主要是为了解决Object.assign不能正确复制 get和set的问题
const source = {
set foo(value) { console.log(value) }
}
const object1 = {}
const object2 = {}
Object.assign(object1, source)
Object.getOwnPropertyDescriptors(object1, 'foo')
// {value: undefined,
// writable: true,
// enumerable: true,
// configurable: true }
Object.defineProperties(object2, Object.getOwnPropertyDescriptors(source))
Object.getOwnPropertyDescriptors(object2, 'foo')
// {getundefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
Null传导运算符?.
a?.b 如果a是 null或者undefined 不产生任何效果
问题思考
怎么手动实现深拷贝?