JS学习之旅-day10
- [1. 作用域](#1. 作用域)
-
- [1.1 局部作用域](#1.1 局部作用域)
- [1.2 全局作用域](#1.2 全局作用域)
- [1.3 作用域链](#1.3 作用域链)
- [1.4 JS垃圾回收机制(GC)](#1.4 JS垃圾回收机制(GC))
- [1.5 闭包](#1.5 闭包)
- [1.6 变量提升](#1.6 变量提升)
- [2. 函数进阶](#2. 函数进阶)
-
- [2.1 函数提升](#2.1 函数提升)
- [2.2 函数参数](#2.2 函数参数)
- [2.3 箭头函数](#2.3 箭头函数)
- [3. 解构赋值](#3. 解构赋值)
-
- [3.1 数组解构](#3.1 数组解构)
- [3.2 对象解构](#3.2 对象解构)
- [4. 数组遍历](#4. 数组遍历)
-
- [4.1 forEach](#4.1 forEach)
- [4.2 filter](#4.2 filter)
1. 作用域
作用域规定了变量能够访问的"范围",分为:局部作用域、全局作用域
1.1 局部作用域
- 函数作用域:只能在函数内部访问,外部无法直接访问,函数执行完后,函数内部的变量会被清空。
- 块作用域:被
{}
包裹的,使用let、const
声明的变量会产生块作用域,var不会产生块作用域
1.2 全局作用域
- 写在最外层:
1.3 作用域链
- 本质:底层的变量查找机制
- 变量查找机制:
- 在函数被执行时,会
优先在当前函数
作用域中查找变量 - 如果当前作用域查找不到,则会依次
逐级查找父级作用域
直到全局作用域
- 在函数被执行时,会
- 总结:
- 嵌套关系的作用域串联起来形成了作用域链
- 相同作用域中按着从小到大的规则查找变量
- 子作用域可以访问父作用域,父作用域无法访问子作用域
1.4 JS垃圾回收机制(GC)
- JS中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
- 内存的生命周期:
- 内存分配:当我们声明变量、函数、对象的时候,系统会自动为他们分配内存
- 内存使用:即读写内存,也就是使用变量、函数等
- 内存回收:使用完毕,由垃圾回收器自动回收不再使用的内存
- 说明:
- 全局变量一般不会回收(关闭页面回收)
- 局部变量不被使用了,会被自动回收掉
- 内存泄露:程序中分配的
内存
由于某种原因程序未释放
或无法释放
叫做内存泄露
- 算法说明:
- 堆栈空间分配区别:
- 栈:由
操作系统自动分配释放
函数的参数值、局部变量等,基本数据类型都放在栈里 - 堆:一般由程序员分配释放,若程序员不释放,由
垃圾回收机制
回收。复杂数据类型放在堆里
- 栈:由
- 垃圾回收机制两种常见的算法:
引用计数法
和标记清除法
-
引用计数(不再使用)
-
嵌套引用(循环引用):如果两个对象相互引用,尽管他们不再使用,但垃圾回收器不会进行回收,
导致内存泄露
function fn(){ let o1 = {} let 02 = {} o1.a=o2 o2.a=o1 return '引用计数无法回收' }
-
-
标记清除法:从
根部
扫描对象,能查找到的就是使用的,查找不到的就是要回收的
-
- 堆栈空间分配区别:
1.5 闭包
-
概念:一个函数对周围状态的引用捆绑在一起,内部函数中访问到其他外层函数的作用域
-
闭包 = 内层函数 + 外层函数的变量
function outer(){ const a=1 function f(){ console.log(a) } f() } outer()
-
闭包的作用:封装数据,提供操作,外部也可以访问函数内部的变量
function outer() { const a = 1; function fn() { console.log(a); } return fn } const fn = outer() fn()
-
风险:内存泄露
1.6 变量提升
- 把所有var声明的变量提升到
当前作用域
前面;let/const 不存在变量提升 - 只提升声明,不提升赋值
- 变量提升出现在相同作用域中
2. 函数进阶
2.1 函数提升
-
会把所有函数声明提升到当前作用域的最前面
-
只提升函数声明,不提升函数调用。(函数表达式不存在提升的现象)
//函数提升 foo() function foo(){ console.log('提升了') } //函数表达式不存在提升 bar() var bar=function(){ console.log('报错了') }
2.2 函数参数
-
动态参数:
arguments
是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参function sum() { // arguments 动态参数 只存在函数中 // arguments 是一个伪数组, 它不是一个真正的数组, 但是它有length属性, 可以通过下标访问元素 // console.log(arguments); let total = 0; for (let i = 0; i < arguments.length; i++) { total += arguments[i]; } console.log(total); } sum(1, 2); sum(1, 2, 3); sum(1, 2, 3, 4); sum(1, 2, 3, 4, 5);
-
剩余参数:允许我们将一个不定数量的参数表示为一个数组
-
...
是语法符号,之余最末函数形参之前,用于获取多余
的实参 -
借助
...
获取的剩余实参,是一个真数组function sum(a,...other) {
console.log(other);
}
sum(1, 2); // [2]
sum(1, 2, 3); // [2,3]
sum(1, 2, 3, 4); // [2,3,4]
sum(1, 2, 3, 4, 5); // [2,3,4,5]
-
-
展开运算符
...
-
可以将一个数组展开
const arr=[1,2,3] console.log(...arr) //1 2 3
-
说明
- 不会修改原数组
- 最典型的应用:求数组的最值、合并数组
const arr = [1, 2, 3, 4, 5];
console.log(...arr);
// 求数组最大值
console.log(Math.max(...arr));// 合并数组
const arr2 = [6, 7, 8, 9, 10];
const arr3 = [...arr, ...arr2];
-
2.3 箭头函数
-
目的:更简洁的函数写法并且不绑定this,适用于那些
需要匿名函数
的地方 -
基本语法
// 只有一行代码时, 可以省略大括号,return 会自动返回 const fn = (a, b) => a + b; console.log(fn(1, 2)); // 只有一个形参时, 可以省略小括号 const fn2 = a => a + 1; console.log(fn2(1)); // 直接返回一个对象 const fn3 = (uname) => ({ uname: uname }); console.log(fn3("张三"))
-
参数
- 箭头函数
没有arguments
参数,但是有剩余参数
- 箭头函数不会创建自己的this,它会从自己的作用域链的上一层沿用this
- 箭头函数
3. 解构赋值
3.1 数组解构
-
定义:将数组的单元值快速批量赋值给一系列的变量。
-
语法:
const [a,b,c] = [100,60,80]
-
代码案例:交换变量
let x = 1; let y = 2; [x, y] = [y, x]; console.log(x, y);
3.2 对象解构
-
语法:
const { name, age } = { name: 'John', age: 20 };
-
注意:变量名和属性名一定要相同
-
解构的变量名可以重新命名:
const { name: name1, age: age1 } = { name: 'John', age: 20 };
-
数组对象解构:
// 数组对象解构 const pig = [ { name: 'John', age: 20 }, ] const [{ name: name2, age: age2 }] = pig;
-
多级对象解构
// 多级对象解构 const person = { uname: 'John', uage: 20, address: { city: 'New York', }} const { uname, uage, address: { city } } = person;
4. 数组遍历
4.1 forEach
-
代码:
被遍历的数组.forEach(function(当前数组元素,当前元素索引号){ //函数体 })
-
注意:
- forEach主要是遍历数组
- 当前数组元素是必须写的,索引号可以省略
- 与map的区别:map有返回,forEach没有
4.2 filter
-
筛选数组
符合条件
的元素,并返回
筛选之后元素的新数组 -
代码:
被遍历的数组.filter(function(当前数组元素,当前元素索引号){ return 筛选条件 })