JS 进阶(part1)
作用域
局部作用域
-
定义: 局部作用域指的是在函数内部定义的变量,只能在函数内部访问,外部不能访问。
-
特点: 局部作用域变量只能在函数内部或代码块中访问,外部不能访问。
-
分类:
-
函数作用域: 指的是在函数内部定义的变量,只能在函数内部访问,外部不能访问。
-
块作用域: 指的是在代码块({})中定义的变量,可以在代码块中访问,外部不能访问。
-
全局作用域
-
定义: 全局作用域指的是在函数外部定义的变量,可以在整个程序范围内访问。
-
特点: 全局作用域变量可以在整个程序范围内访问。
-
建议: 不建议在全局作用域定义变量,容易造成命名冲突。
作用域链
-
定义: 作用域链是由一系列变量对象组成的链式结构,它决定了变量的查找方式。
-
作用: 作用域链的作用是保证对变量的访问权限。
-
机制: 当解释器在执行代码时,会在当前作用域和上层作用域中查找变量,如果在当前作用域中没有找到,则继续在上层作用域中查找,直到找到为止。
-
特点: 子作用域能够访问父作用域, 但父作用域不能访问子作用域。
JS 垃圾回收机制
-
定义: 垃圾回收机制是指自动释放不再使用的内存,以便为应用程序提供更多的内存空间。
-
内存的生命周期:
- 分配: 当我们声明变量、函数或创建对象时,系统会在内存中分配一块内存空间。
- 使用: 程序运行时(读写内存),系统使用分配的内存空间。
- 释放: 程序运行结束时,系统释放分配的内存空间。
-
注意:
- 全局变量: 全局变量的生命周期与程序运行时长相关,当程序结束时,系统会自动释放全局变量所占用的内存。
- 局部变量: 局部变量的生命周期与函数执行时长相关,当函数执行结束时,系统会自动释放局部变量所占用的内存。
- 内存泄露: 未释放或无法释放内存。
-
算法说明:
- 标记清除: 定义"无法到达的对象", 从根部出发, 如果能找到标记对象, 暂时不清除, 找不到则清除。
- 引用计数: 定义"内存不再使用", 就是看一个对象是否有指向它的引用, 如果没有, 则说明该对象不再使用, 可以进行回收。 / 缺点: 嵌套引用时, 无法回收。
闭包
-
定义: 闭包是指有权访问另一个函数作用域的函数,创建闭包的常见方式是函数嵌套。
-
特点: 闭包 = 内层函数 + 外层函数的变量
-
作用: 封闭数据, 提供操作, 外部也可以访问函数内部的变量
-
优点:
- 可以读取函数内部的变量和参数
- 可以在函数外部修改变量的值
- 延迟初始化, 只有在调用函数时才初始化变量
-
缺点:
- 内存泄漏, 闭包会占用内存, 导致内存泄漏
- 性能问题, 每次调用函数都会创建新的闭包, 性能较低
javascript
function outer() {
let a = 1;
function inner() {
console.log(a);
}
return inner;
}
cosnt fun = outer();
fun();
变量提升
-
定义: 变量提升是指 JavaScript 在执行代码前,会将在当前作用域下, var 声明的变量和函数, 提升到当前作用域的最前面, 只提升声明, 不提升赋值。
-
作用: 变量提升可以让变量在函数内部使用前就已经声明, 避免报错, 但实际开发中, 应该避免使用变量提升。
展开运算符
-
定义: 展开运算符是指将数组或类数组对象转换为用逗号分隔的参数序列。
-
作用: 展开运算符可以将数组或类数组对象转换为用逗号分隔的参数序列, 方便求最值和合并数组。
-
语法: 展开运算符是三个点(...)
-
注意: 展开运算符只能用于数组或类数组对象, 不能用于字符串, 对象, Map, Set 等。
javascript
let arr = [1, 2, 3];
let arr2 = [4, 5, 6];
let newArr = [...arr, ...arr2]; // [1, 2, 3, 4, 5, 6]
let max = Math.max(...newArr); // 6
函数
函数提升
- 定义: 函数提升是指 JavaScript 在执行代码前,会将在当前作用域下, 函数声明的函数, 提升到当前作用域的最前面。
函数参数
-
动态参数
-
定义: 动态参数指的是函数调用时, 传入的参数个数不确定, 可以是 0 个或多个。
-
用法: 使用 arguments 对象(伪数组), 可以获取调用函数时传入的参数。
-
作用: 可以实现函数的可变参数。
javascriptfunction getSum() { let sum = 0; for (let i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum; } let result = getSum(1, 2, 3); // 6
-
-
剩余参数
-
定义: 剩余参数指的是函数调用时, 传入的参数个数不确定, 但最后一个参数必须是数组。
-
用法: 使用(a, b,...arr), 可以将传入的参数收集到真数组中。
-
作用: 可以实现函数的可变参数。
javascriptfunction getSum(a, b, ...arr) { let sum = a + b; for (let i = 0; i < arr.length; i++) { sum += arr[i]; } return sum; } let result = getSum(1, 2, 3); // 6
-
箭头函数
- 定义: 箭头函数是 ES6 新增的一种函数, 与普通函数的区别在于, 箭头函数没有自己的 this, arguments, super, new.target, 并且没有原型链。
javascript
// 普通的箭头函数
let add = (a, b) => {
return a + b;
};
let result = add(1, 2); // 3
// 只有一个参数的箭头函数可以省略括号, 只有一个语句的箭头函数可以省略大括号, 并且有返回值
let add1 = (a) => a + 1;
let result1 = add1(1); // 2
// 返回一个对象
let obj = (name, age) => ({ name: name, age: age });
let resultObj = obj("Tom", 20); // {name: 'Tom', age: 20}
箭头函数参数
-
箭头函数没有 arguments 对象, 不能使用 arguments.length, 不能使用 arguments[i]获取参数, 但有剩余参数。
-
箭头函数不会创建自己的 this, 但可以使用上级作用域的 this。
解构赋值
数组解构
-
定义: 将数组中的单元值快速依次批量赋值给变量。
-
语法: let [变量 1, 变量 2, 变量 3] = 数组;
-
注意: 当解构赋值的变量个数与数组的单元值个数不一致时, 多余的变量会被赋值为 undefined, 少于的变量会被忽略。
javascript
/*普通数组解构*/
const arr = [1, 2, 3];
const [a, b, c] = arr;
/*交换变量的值*/
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
/*利用剩余参数*/
let [a, b, ...rest] = [1, 2, 3, 4, 5];
console.log(a, b, rest); // 1 2 [3, 4, 5]
/*防止undefined传递*/
let [a = 0, b = 0, c = 0] = [1, 2];
console.log(a, b, c); // 1 2 0
/*按需导入赋值*/
let [x, , y] = [1, 2, 3];
console.log(x, y); // 1 3
/*多维数组解构*/
let [a, b, [c, d]] = [1, 2, [3, 4]];
console.log(a, b, c, d); // 1 2 3 4
对象解构
-
定义: 将对象中的属性值快速依次批量赋值给变量。
-
语法: let {变量 1: 变量 2, 变量 3: 变量 4} = 对象;
-
注意: 当解构赋值的变量个数与对象属性个数不一致时, 多余的变量会被赋值为 undefined, 少于的变量会被忽略。且变量名应该与属性名一致。
javascript
/*普通对象解构*/
const obj = { name: "Tom", age: 20 };
const { name, age } = obj;
/*重新改名*/
const obj2 = { name: "Tom", age: 20 };
const { name: n, age: a } = obj2;
// 旧名 新名
/*对象数组的解构*/
const arr = [
{ name: "Tom", age: 20 },
{ name: "Jerry", age: 25 },
];
const [{ name, age }, { name: n, age: a }] = arr;
/*多级对象解构*/
const pig = {
name: "小猪",
family: {
father: "爸爸",
mother: "妈妈",
sister: {
Siname: "姐姐",
Sname: "妹妹",
},
},
};
const {
name,
family: {
father,
mother,
sister: { Sname, Siname },
},
} = pig;
数组进阶
forEach 遍历
javascript
let arr = [1, 2, 3];
arr.forEach(function (value, index) {
console.log(value);
console.log(index);
});
filter 过滤
javascript
const arr = [1, 2, 3, 4, 5];
const newArr = arr.filter(function (value, index) {
return value > 2;
});
map 映射
javascript
const arr = [1, 2, 3, 4, 5];
const newArr = arr.map(function (value, index) {
return value * 2;
});
reduce 归并
javascript
const arr = [1, 2, 3, 4, 5];
const result = arr.reduce(function (prev, curr, index) {
return prev + curr;
}, 0);// 如果有初值, 则作为第一次执行的 prev, 每一次循环的返回值作为下一次的 prev
find 找出第一个匹配项
javascript
const arr = [1, 2, 3, 4, 5];
const result = arr.find(function (value, index) {
return value > 2;
});
findIndex 找出第一个匹配项的索引
javascript
const arr = [1, 2, 3, 4, 5];
const result = arr.findIndex(function (value, index) {
return value > 2;
});
includes 判断是否包含
javascript
const arr = [1, 2, 3, 4, 5];
const result = arr.includes(3);