JS学习之旅-day10
- 1. 作用域
- 1.1 局部作用域
- 1.2 全局作用域
- 1.3 作用域链
- 1.4 JS垃圾回收机制(GC)
- 1.5 闭包
- 1.6 变量提升
- 2. 函数进阶
- 2.1 函数提升
- 2.2 函数参数
- 2.3 箭头函数
- 3. 解构赋值
- 3.1 数组解构
- 3.2 对象解构
- 4. 数组遍历
- 4.1 forEach
- 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=o2o2.a=o1return ‘引用计数无法回收’ }
- 嵌套引用(循环引用):如果两个对象相互引用,尽管他们不再使用,但垃圾回收器不会进行回收,
- 标记清除法:从
根部
扫描对象,能查找到的就是使用的,查找不到的就是要回收的
- 引用计数(不再使用)
- 堆栈空间分配区别:
1.5 闭包
-
概念:一个函数对周围状态的引用捆绑在一起,内部函数中访问到其他外层函数的作用域
-
闭包 = 内层函数 + 外层函数的变量
function outer(){const a=1function 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 筛选条件 })