1.作用域
作用域分为: 1.局部作用域 2.全局作用域
2.局部作用域
局部作用域分为函数作用域和块级作用域。
1.函数作用域:
在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。

2. 块级作用域 {}
在 JavaScript 中使用 { } 包裹的代码称为代码块,代码块内部声明的变量外部将【有可能】无法被访问

总结:
1. let 声明的变量会产生块作用域,var 不会产生块作用域
2. const 声明的常量也会产生块作用域
3. 不同代码块之间的变量无法互相访问
4. 推荐使用 let 或 const
3.全局作用域
<script> 标签 和 .js 文件 的【最外层】就是所谓的全局作用域,在此声明的变量在函数内部也可以被访问。
全局作用域中声明的变量,任何其它作用域都可以被访问

注意:
1. 为 window 对象动态添加的属性默认也是全局的,不推荐!
2. 函数中未使用任何关键字声明的变量为全局变量,不推荐!!!
3. 尽可能少的声明全局变量,防止全局变量被污染
4.作用域链
作用域链本质上是底层的变量查找机制
在函数被执行时,会优先查找当前函数作用域中查找变量
如果当前作用域查找不到则会依次逐级查找父级作用域直到全局作用域
总结:
1. 嵌套关系的作用域串联起来形成了作用域链
2. 相同作用域链中按着从小到大的规则查找变量
3. 子作用域能够访问父作用域,父级作用域无法访问子级作用域

5.JS垃圾回收机制
什么是垃圾回收机制?
垃圾回收机制(Garbage Collection) 简称 GC
JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
正因为垃圾回收器的存在,许多人认为JS不用太关心内存管理的问题
但如果不了解JS的内存管理机制,我们同样非常容易成内存泄漏(内存无法被回收)的情况
不再用到的内存,没有及时释放,就叫做内存泄漏
内存的生命周期
JS环境中分配的内存, 一般有如下生命周期:
1. 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
2. 内存使用:即读写内存,也就是使用变量、函数等
3. 内存回收:使用完毕,由垃圾回收自动回收不再使用的内存
4. 说明:
全局变量一般不会回收(关闭页面回收);
一般情况下局部变量的值, 不用了, 会被自动回收掉
垃圾回收算法说明
所谓垃圾回收, 核心思想就是如何判断内存是否已经不再会被使用了, 如果是, 就视为垃圾, 释放掉
浏览器垃圾回收算法: 引用计数法 和 标记清除法
引用计数法
IE采用的引用计数算法, 定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。
算法:
1. 跟踪记录每个值被引用的次数。
2. 如果这个值的被引用了一次,那么就记录次数1
3. 多次引用会累加。
4. 如果减少一个引用就减1。
5. 如果引用次数是0 ,则释放内存。
标记清除法
核心:
1. 标记清除算法将“不再使用的对象”定义为“无法达到的对象”。
2. 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。
3. 那些无法由根部出发触及到的对象被标记为不再使用,稍后进 行回收。
6.闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解:闭包 = 内层函数 + 外层函数的变量

闭包作用:封闭数据,提供操作,外部也可以访问函数内部的变量


7.变量提升
变量提升是 JavaScript 中比较“奇怪”的现象,它允许在变量声明之前即被访问(仅存在于var声明变量)

变量提升的流程
先把var 变量提升到当前作用域于最前面
只提升变量声明, 不提升变量赋值
然后依次执行代码
8.函数提升
函数提升与变量提升比较类似,是指函数在声明之前即可被调用

总结:
1. 函数提升能够使函数的声明调用更灵活
2. 函数表达式不存在提升的现象
3. 函数提升出现在相同作用域当中
9.函数参数
9.1动态参数
arguments 是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参

9.2剩余参数
1. ... 是语法符号,置于最末函数形参之前,用于获取多余的实参
2. 借助 ... 获取的剩余实参,是个真数组
剩余参数
function getSum(...arr) {
console.log(arr)
}
getSum(1, 2, 3)

9.3展开运算符

求数组最大值(最小值)、合并数组

展开运算符与剩余参数不同点
剩余参数: 函数参数使用,得到真数组
展开运算符: 数组中使用,数组展开

10.箭头函数
目标: 能够熟悉箭头函数不同写法
目的:引入箭头函数的目的是更简短的函数写法并且不绑定this,箭头函数的语法比函数表达式更简洁
使用场景:箭头函数更适用于那些本来需要匿名函数的地方
语法1:基本写法

语法2:只有一个参数可以省略小括号

语法3:如果函数体只有一行代码,可以写到一行上,并且无需写 return 直接返回值

语法4:加括号的函数体返回对象字面量表达式

语法5:只有一行代码时可以省略大括号
const fn = x => console.log(x)
fn(1)
语法6:箭头函数 基本语法
const fn = () => {
console.log(123)
}
fn()
const fn = (x) => {
console.log(x);
}
fn(1)
箭头函数参数
1. 普通函数有arguments 动态参数
2. 箭头函数没有 arguments 动态参数,但是有 剩余参数 ..args
箭头函数参数求和案例
<script>
const getSum = (...arr) => {
let sum = 0
for (let i = 0; i < arr.length; i++) {
sum = sum + arr[i]
}
return sum
}
let res = getSum(2, 3, 4, 5)
console.log(res)
</script>
箭头函数 this
箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this。



在开发中【使用箭头函数前需要考虑函数中 this 的值】,事件回调函数使用箭头函数时,this 为全局的 window,因此DOM事件回调函数为了简便,还是不太推荐使用箭头函数

11.解构赋值

12.数组解构
数组解构是将数组的单元值快速批量赋值给一系列变量的简洁语法
基本语法:
1. 赋值运算符 = 左侧的 [] 用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量
2. 变量的顺序对应数组单元值的位置依次进行赋值操作


案例:交换两个变量的值


12. js 前面必须加分号的两种情况
1. 立即执行函数

2. 数组解构

13.案例 需求有个数组: const pc = ['海尔', '联想', '小米', '方正']
解构为变量: hr lx mi fz
const [hr, lx, mi, fz] = ['海尔', '联想', '小米', '方正']
console.log(hr);
console.log(lx);
console.log(mi);
console.log(fz);
14.案例: 需求:请将最大值和最小值函数返回值解构 max 和min 两个变量
function getValue() {
return [100, 60]
}
const [max, min] = getValue()
console.log(max);
console.log(min);
15.数组解构细节
1. 变量多, 单元值少 , undefined
const [a, b, c, d] = [1, 2, 3]
console.log(a)
console.log(b)
console.log(c)
console.log(d)
2. 变量少, 单元值多
const [a, b] = [1, 2, 3]
console.log(a)
console.log(b)
3. 剩余参数 变量少, 单元值多
const [a, b, ...c] = [1, 2, 3, 4]
console.log(a)
console.log(b)
console.log(c)
4. 防止 undefined 传递
const [a = 0, b = 0] = [1, 2]
const [a = 0, b = 0] = []
console.log(a)
console.log(b)
5. 按需导入赋值
const [a, b, , d] = [1, 2, 3, 4]
console.log(a)
console.log(b)
console.log(d)
const arr = [1, 2, [3, 4]]
console.log(arr[0])
console.log(arr[1])
console.log(arr[2])
console.log(arr[2][0])
多维数组解构
const arr = [1, 2, [3, 4]]
const [a, b, c] = [1, 2, [3, 4]]
console.log(a)
console.log(b)
console.log(c)
const [a, b, [c, d]] = [1, 2, [3, 4]]
console.log(a)
console.log(b)
console.log(c)
console.log(d)
16.对象解构
对象解构是将对象属性和方法快速批量赋值给一系列变量的简洁语法
基本语法:
1. 赋值运算符 = 左侧的 {} 用于批量声明变量,右侧对象的属性值将被赋值给左侧的变量
2. 对象属性的值将被赋值给与属性名相同的变量
3. 注意解构的变量名不要和外面的变量名冲突否则报错
4.对象中找不到与变量名一致的属性时变量值为 undefined

对象解构
const obj = {
uname: 'pink老师',
age: 18
}
obj.uname
obj.age
const uname = 'red老师'
解构的语法
const { uname, age } = {age: 18, uname: 'pink老师' }
等价于 const uname = obj.uname
要求属性名和变量名必须一直才可以
console.log(uname)
console.log(age)
17.对象解构给新的变量名赋值:
1. 对象解构的变量名 可以重新改名 旧变量名: 新变量名
const { uname: username, age } = { uname: 'pink老师', age: 18 }
console.log(username)
console.log(age)
2. 解构数组对象
const pig = [
{
uname: '佩奇',
age: 6
}
]
const [{ uname, age }] = pig
console.log(uname)
console.log(age)
18.多级对象解构
const pig = {
name: '佩奇',
family: {
mother: '猪妈妈',
father: '猪爸爸',
sister: '乔治'
},
age: 6
}
多级对象解构
const { name, family: { mother, father, sister } } = pig
console.log(name)
console.log(mother)
console.log(father)
console.log(sister)
const person = [
{
name: '佩奇',
family: {
mother: '猪妈妈',
father: '猪爸爸',
sister: '乔治'
},
age: 6
}
]
const [{ name, family: { mother, father, sister } }] = person
console.log(name)
console.log(mother)
console.log(father)
console.log(sister)
19.多级对象解构案例
<body>
<script>
const msg = {
"code": 200,
"msg": "获取新闻列表成功",
"data": [{
"id": 1,
"title": "5G商用自己,三大运用商收入下降",
"count": 58
},
{
"id": 2,
"title": "国际媒体头条速览",
"count": 56
},
{
"id": 3,
"title": "乌克兰和俄罗斯持续冲突",
"count": 1669
},
]
}
function render({
data
}) {
console.log(data)
}
render(msg)
function render({
data: myData
}) {
console.log(myData)
}
render(msg)
</script>

20.遍历数组 forEach 方法
<script>
const arr = ['red', 'green', 'pink']
const result = arr.forEach(function (item, index) {
console.log(item)
console.log(index)
})
</script>

21.筛选数组 filter 方法
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素
主要使用场景: 筛选数组符合条件的元素,并返回筛选之后元素的新数组

<script>
const arr = [10, 20, 30]
const newArr = arr.filter(item => item >= 20)
console.log(newArr)
</script>