# 一、let 变量
以前我们使用的是var
,但可能存在以下问题:
- if、for 等内定义的变量容易暴露,造成污染
# 1、块级作用域
{
var age = 20
}
console.log(age) // 20
{
let age = 20
}
console.log(age) // age is not defind
- 应用示例
for (let i = 0; i < 5; i++) {
//
}
- var 和 let 对比
var oli = document.querySelectorAll('ul li')
// 失败案例
// for (var i = 0; i < oli.length; i++) {
// oli[i].onclick = function () {
// console.log(i)
// }
// }
// 【由于点击属于异步操作,var定义的是全局变量:
// 导致打印的始终是执行完后的最后一个全局i 】
// 解决方案1
for (var i = 0; i < oli.length; i++) {
// 为每个节点存储一个index属性
oli[i].index = i
oli[i].onclick = function () {
// 打印节点身上的属性
console.log(this.index)
}
}
// 解决方案2
for (let i = 0; i < oli.length; i++) {
oli[i].onclick = function () {
console.log(i)
}
}
// 【此时的i不受外界影响,打印的就是当前执行时的i】
# 2、限制条件
// 1、不允许重复声明
var a = 2
// ……
var a = 1
// 2、取消变量提升
// 错误示例
console.log(name)
let name = 'lencamo'
# 3、特性
// 不与顶层对象挂钩
let count = 2
console.log(window.count) // undefined
# 二、const 常量
# 1、说明
let 的东西 const 基本也有,但两者之间也有些许区别。
# 2、特点
// 初始化常量--必须赋值
const name = 'lencamo'
// const常量--不能二次赋值
name = 'zhangsan'
- 使用场景
// 相对固定的内容
# 3、经典面试
const 定义的内容不可以被修改吗?
const obj = {
age = 20,
name = 'lencamo'
}
obj = "HelloWorld" // 错误
obj.age = 22
console.log(obj) // 修改成功
- 绝对固定
const obj = Object.freeze({
age = 20,
name = 'lencamo'
})
# 三、Set 结构(数组)
类似于没有重复元素的 数组
Set 本身是一个构造函数,说其原型对象上有一些实例方法可以供我们使用:size
、add
、delete
、has
、clear
区别:
add
# 1、属性/方法
console.log(setT.size)
setT.add(6)
setT.delete(1)
setT.has(3)
setT.clear()
# 2、数组去重
let arr = [1, 2, 2, 3, 4, 4]
console.log(Array.from(new Set(arr))) // [1, 2, 3, 4]
console.log([...new Set(arr)]) // [1, 2, 3, 4]
其实,去除字符串中的重复字符也可以用 Set 去重:
let str = 'hahaha'
console.log([...new Set(str)].join('')) // 'ha'
复杂去重
let list = [
1,
2,
2,
'lencamo',
'lencamo',
[1, 2],
[3, 4],
[1, 2],
{ name: 'lencamo' },
{ age: 66 },
{ name: 'lencamo' }
]
let res = new Set()
let newList = list.filter((item) => {
let i = JSON.stringify(item)
if (res.has(i)) {
return false
} else {
res.add(i)
return true
}
})
console.log(newList)
# 3、Set 迭代
Set 结构的迭代器有三种:for...of
、forEach
、keys()
、values()
、entries()
let setT = new Set([1, 2, 3, 4, 4])
// 1、for...of
for (let item of setT) {
console.log(item) // 1, 2, 3, 4
}
// 2、forEach
setT.forEach((item) => {
console.log(item) // 1, 2, 3, 4
})
// 3、keys()、values()、entries()
for (let key of setT.keys()) {
console.log(key) // 1, 2, 3, 4
}
for (let value of setT.values()) {
console.log(value) // 1, 2, 3, 4
}
for (let item of setT.entries()) {
console.log(item) // [1, 1], [2, 2], [3, 3], [4, 4]
}
# 4、WeakSet 结构
WeakSet 结构与 Set 结构类似,也是不重复的值的集合。但是,它与 Set 有两个区别:
- WeakSet 中的值只能是对象,不能是其他类型的值。
- WeakSet 中的对象都是弱引用,即如果没有其他引用指向这个对象,那么这个对象将自动被垃圾回收(即不用担心内存泄漏问题)。
由于 WeakSet 的自动垃圾回收功能,因此 WeakSet 数据是不可预测的,不能确定它里面有多少个元素。所以,WeakSet 不可遍历(没有 size 属性、没有 forEach 方法),也不支持迭代器。
应用:存储 DOM 节点
let ws = new WeakSet()
let div1 = document.createElement('div')
let div2 = document.createElement('div')
ws.add(div1)
ws.add(div2)
console.log(ws.has(div1)) // true
console.log(ws.has(div2)) // true
div1 = null
console.log(ws.has(div1)) // false
let ws = new WeakSet()
ws.add(1)
ws.add('lencamo')
ws.add({ name: 'lencamo' })
console.log(ws.has(1)) // true
console.log(ws.has('lencamo')) // true
console.log(ws.has({ name: 'lencamo' })) // true
ws.delete(1)
console.log(ws.has(1)) // false
# 四、Map 结构(对象)
类似于不限键类型、键不重复的对象,和 Storage 接口一样采取的是键值对的方式
同样,Map 本身也是一个构造函数,说其原型对象上有一些实例方法可以供我们使用:size
、set
、get
、delete
、has
、clear
区别:
set
、get
注意:Map 结构有序,而 Object 结构无序。
# 1、属性/方法
console.log(mapT.size)
mapT.set('age', 33)
mapT.get('age') // 33
mapT.delete('age')
mapT.has('age')
mapT.clear()
# 2、数据覆盖
- Map 中
let mapT = new Map()
mapT.set('name', 'lencamo')
mapT.set('name', 'zhangsan')
console.log(mapT.get('name')) // zhangsan
- 对象中
let obj = {
name: 'lencamo',
age: 22
}
let newObj = { ...obj, age: 66 }
console.log(newObj) // {name: "lencamo", age: 66}
应用:存储配置信息
# 3、Map 迭代
let mapT = new Map([
['name', 'lencamo'],
['age', 22]
])
for (let [key, value] of mapT) {
console.log(key, value) // name lencamo, age 22
}
for (let key of mapT.keys()) {
console.log(key) // name, age
}
for (let value of mapT.values()) {
console.log(value) // lencamo, 22
}
for (let [key, value] of mapT.entries()) {
console.log(key, value) // name lencamo, age 22
}
# 4、WeakMap 结构
WeakMap 结构与 Map 结构类似,也是不限键类型、键不重复的对象。但是,它与 Map 有两个区别:
- WeakMap 中的键只能是对象,不能是其他类型的值。
- WeakMap 中的对象都是弱引用,即如果没有其他引用指向这个对象,那么这个对象将自动被垃圾回收(即不用担心内存泄漏问题)。
由于 WeakMap 的自动垃圾回收功能,因此 WeakMap 数据是不可预测的,不能确定它里面有多少个元素。所以,WeakMap 不可遍历(没有 size 属性、没有 forEach 方法),也不支持迭代器。
let wm = new WeakMap()
let obj = {
name: 'lencamo'
}
wm.set(obj, 'age')
console.log(wm.get(obj)) // age
obj = null
console.log(wm.get(obj)) // undefined
# 五、其他
# 1、解构赋值
注意
我们要明白使用解构赋值的目的:快速获取数组、对象、字符串等中的某些数据 值
# 2、扩展运算符
# 3、属性名简写
// 动态属性名
let name = 'lencamo'
let funT = 'moduleA'
// ---常规---
let obj = {
name: name,
test: function () {
//
}
}
// ---简写---
let ojb = {
name,
test() {
//
},
[funT + 'add']() {
//
}
}
// obj.name 不同于 obj[name]
# 4、函数简写
let funT = function () {
return 'lencamo'
}
console.log(funT())
// 可以简写为
let funT = () => 'lencamo'
let funT = () => ({
// 返回对象
name: 'lencamo'
})
console.log(funT())
# 5、箭头函数
对于普通函数来说,内部的 this 指向函数运行时所在的对象,而箭头函数的 this 指向定义时上层作用域中的 this,它有如下特点:
也就是说,箭头函数内部的 this 指向是固定的,相比之下,普通函数的 this 指向是可变的。
无法访问 arguments
无法 new 实例(构造函数)
箭头函数没有 this 对象
var id = 21
// 普通函数
function foo2() {
// console.log(this) // { id: 42 }
setTimeout(function () {
console.log(this) // Window {}
console.log(this.id)
}, 100)
}
foo2.call({ id: 42 }) // 21 ✨
// 箭头函数
function foo() {
// console.log(this) // { id: 42 }
setTimeout(() => {
console.log(this) // { id: 42 }
console.log(this.id)
}, 100)
}
foo.call({ id: 42 }) // 42 ✨
← --ECMAScript-- ES6进阶 →