
JS 精简要点
原创2025年1月10日...大约 6 分钟
JS 精简要点
let vs const vs var
- 变量提升。
- 暂时性死区。
- 块级作用域。
- 重复声明。
- 修改声明的变量。
作用域链
- 作用域链本质上是底层的变量查找机制。
- 嵌套关系的作用域串联起来形成了作用域链。
- 相同作用域链按照从小到大的规则查找变量。
- 子作用域能够访问父作用域,父级作用域无法访问子级作用域。
作用域链查找规则
- 会优先在当前函数作用域中查找变量。
- 查找不到则会依次逐级查找父级作用域直到全局作用域。
let a = 1;
let b = 2;
function f() {
let a = 1;
function g() {
a = 2;
console.log(a);
}
g();
}
f();
JS 垃圾回收机制
垃圾回收机制(Garbage Collection) 简称 GC。JS 中内存的分配和回收都是自动完成的,内存在不使用的时候会被垃圾回收器自动回收。
JS 垃圾回收算法
- 引用计数法:IE 采用的引用计数算法, 定义“内存不再使用”,就是看一个对象是否有指向它的引用,没有引用了就回收对象。
- 标记清除法:现代浏览器通用的大多是基于标记清除算法的某些改进算法。从根部扫描对象,能查找到的就是使用的,查找不到的就要回收。
闭包
闭包是指有权访问另一个函数作用域中的变量的函数,创建闭包常见方式,就是在一个函数的内部创建另一个函数。
闭包的优缺点
- 闭包的优点是可以避免变量的污染。
- 闭包的缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。
闭包应用场景
- 应用场景:使用闭包主要为了设计私有的方法和变量。
- 不适用场景:返回闭包的函数是个非常大的函数。
闭包的特点
- 函数嵌套函数。
- 函数内部可以引用外部的参数和变量。
- 参数和变量不会被垃圾回收机制回收。
函数提升
- 函数提升能够使函数的声明调用更灵活。
- 函数表达式不存在提升的现象。
- 函数提升出现在相同作用域当中。
函数动态参数
arguments 是函数内部内置的伪数组变量,它包含了调用函数时传入的所有实参。
- arguments 是一个伪数组,只存在于函数中。
- arguments 的作用是动态获取函数的实参。
- 可以通过 for 循环依次得到传递过来的实参。
function sum() {
let s = 0;
for (let i = 0; i < arguments.length; i++) {
s += arguments[i];
}
console.log(`Sum: ${s}`);
}
sum(1, 2, 3, 4, 5); // Sum: 15
sum(10, 20, 30); // Sum: 60
函数剩余参数(推荐使用)
剩余参数允许我们将一个不定数量的参数表示为一个数组。借助 ...
获取的剩余实参,是个真数组。
function getSum(...other) {
let sum = 0;
for (let i = 0; i < other.length; i++) {
sum += other[i];
}
console.log(`Sum: ${sum}`);
}
getSum(1, 2, 3, 4, 5); // Sum: 15
getSum(10, 20, 30); // Sum: 60
展开运算符
展开运算符...
,将一个数组进行展开。ES6 通过扩展元素符...
,好比 rest
参数的逆运算,将一个数组转为用逗号分隔的参数序列。
const arr = [1, 2, 3, 4, 5];
console.log(...arr); // 1,2,3,4,5
箭头函数
引入箭头函数的目的是更简短的函数写法并且不绑定 this
,箭头函数的语法比函数表达式更简洁。箭头函数更适用于那些本来需要匿名函数的地方。
- 加括号的函数体返回对象字面量表达式。
const fn1 = (uname) => ({ uname: uname });
console.log(fn1("John")); // { uname: 'John' }
- 箭头函数没有
arguments
动态参数,但是有 剩余参数..args
。
const getSum = (...other) => {
let sum = 0;
for (let i = 0; i < other.length; i++) {
sum += other[i];
}
console.log(`Sum: ${sum}`);
};
getSum(1, 2, 3, 4, 5); // Sum: 15
getSum(10, 20, 30); // Sum: 60
- 箭头函数
this
。在箭头函数出现之前,每一个新函数根据它是被如何调用的来定义这个函数的this
值,箭头函数不会创建自己的this
,它只会从自己的作用域链的上一层沿用this
。
解构赋值
- 数组解构:赋值运算符
=
左侧的[]
用于批量声明变量,右侧数组的单元值将被赋值给左侧的变量。变量的顺序对应数组单元值的位置依次进行赋值操作。前面有两哪种情况需要加分号的,
立即执行函数和数组解构。
const [a, b, c] = [100, 60, 80];
console.log(a); //100
console.log(b); //60
console.log(c); //80
let arr = [1, 6, 3, 9, 5];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
}
console.log(arr); // [1, 3, 5, 6, 9]
对象解构
非严格模式 this 的值
- 全局执行环境下 ,this 指向 window。
- 直接调用函数 ,this 指向 window。
- 对象调用函数 ,this 指向调用者。
严格模式 this 的值
//为整个脚本开启严格模式
"use strict"; //写在最顶端
function func() {
//为函数开启严格模式
"use strict"; //写在最顶端
console.log(this);
}
- 全局执行环境下 ,this 指向 window。
- 直接调用函数 ,this 指向 undefined。
- 对象调用函数 ,this 指向调用者。
指定 this 的值
- 调用时指定:call、apply。
func.call(thisArg,参数1,参数2...)
func.apply(thisArg,[参数1,参数2...])
- 创建时指定:bind、箭头函数。
func.bind(thisArg,参数1,参数2...)
const itheima = {
name:'播仔',
eat(){
setTimeout(()=>{
console.log(this)
})
}
}
fetch 请求
async function func() {
const res = await fetch("请求地址");
res.status;
const data = await res.json();
}
异步请求
axios("url1").
then(res1=>{
return axios("url2")
}).
then(res2=>{
return axios("url3")
}).
then(res3=>{
...
})
async function func() {
const res1 = await axios("url1");
const res2 = await axios("url2");
const res3 = await axios("url3");
...
}
Promise 解决异步操作的优点
- 链式操作减低了编码难度。
- 代码可读性明显增强。
- 对象的状态不受外界影响,只有异步操作的结果,可以决定当前是哪一种状态。
- 一旦状态改变(从 pending 变为 fulfilled 和从 pending 变为 rejected),就不会再变,任何时候都可以得到这个结果。
promise 对象仅有三种状态
- pending(进行中)
- fulfilled(已成功)
- rejected(已失败
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});