这篇文章主要介绍了 JavaScript 中的多种运算符、表达式和关键字,包括加法、赋值、异步函数相关操作(如顺序执行、并行执行、异步函数生成器)、立即执行函数表达式、for await...of循环、await、类表达式、逗号运算符、三元运算符、自减、删除对象属性、解构赋值、除法等。
1.加法:+
2.加法赋值 :+=
x += y // x = x + y
3.赋值:=
4.async function
定义表达式中的异步函数
const resolveAfter = (s)=>{
return async (x) =>new Promise((resolve)=>{
setTimeout(()=>resolve(x),s * 1000)
})
}
const after2Seconds = resolveAfter(2)
const after3Seconds = resolveAfter(3)
顺序执行
const add1 = async ()=>{
const a = await after2Seconds(20)
const b = await after3Seconds(30)
return a + b // 执行共花费5s
}
a和b是按顺序执行的,等待after2Seconds执行完毕后,才会执行after3Seconds,所以最后的总花费时间为5s
并行执行
const add2 = async ()=>{
const a = after2Seconds(20)
const b = after3Seconds(30)
return await a + await b // 执行共花费3s
}
a和b在初始化的时候会同时开始执行,因为这时候没有使用await等待,会直接开始异步操作,等待时间最长的after3Seconds完成后,add2才会返回,最后总的时间为3s,
个人感觉第二种在用法上跟Promise.all()有点类似
5.立即执行函数表达式(IIFE)
是一个在定义的时候就会执行的表达式,也被称为自执行匿名函数,一般用在不会重复使用的初始化代码上
(function(){...})()
(()=>{...})()
(async ()=>{})()
1)第一个括号内是一个具有单独作用域的匿名函数,阻止了外界访问自执行函数中的变量,并且还不会污染全局作用域
2)第二个括号,创建了一个立即执行函数表达式(),有了他,javascript引擎就会立即执行该函数
(() => {
let firstVariable;
let secondVariable;
})();
6.async function*
在表达式中定义一个异步函数生成器,会返回一个异步迭代器,可以通过await...of进行异步迭代
我认为可以简单这样理解,函数的作用是每次只执行一次yield返回的异步函数,可以使用多个yield定义异步函数,并且我们可以在每一个yield执行结束后执行我们想要的逻辑,可以选择继续执行下一个yield,也可以暂停。相当于一个异步函数管理器!! 实现按需请求、逐步获取和处理大量数据
async function* foo() {
console.log('--111:第一次执行--');
yield await after2Seconds(20); // 等待 2 秒后返回 20
console.log('--222:第二次执行--');
yield await after3Seconds(30); // 等待 3 秒后返回 30
console.log('--333:第三次执行--');
yield await after2Seconds(40); // 等待 2 秒后返回 40
}
6.1.遍历输出
(async function generate() {
for await (const val of foo()) {
console.log(val);
}
})()
介绍一下
for await...of循环1.获取异步迭代器对象
2.在每次迭代时调用异步迭代器的
next()方法3.等待
next()返回的Promise解析,获取value和done4.如果
done为false,继续执行下次循环;如果为true,结束循环概括为:能自动在每次循环的时候调用异步迭代器的
next()方法并处理Promise,无需手动调用next()
6.2.手动next()输出
这时候第一次执行完毕,处于暂停状态,,直到下次next()触发
每次触发next(),都会执行下一个yield返回的异步函数
7.await
用于异步编程的操作符,可以暂停代码执行,直到一个Promise被解决(fulfilled或rejected),只能在异步函数或者模块顶层使用。简而言之,它让异步代码看起来像同步代码。
// 模拟一个异步操作
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => resolve("数据已加载"), 1000);
});
}
// 使用 await
async function getData() {
console.log("开始加载...");
const result = await fetchData(); // 暂停,等待 fetchData 完成
console.log(result); // "数据已加载"
}
getData();
注意:
1、须在async函数中使用
2、如果抛出异常,可以使用try...catch处理
async function example(){
try {
const result = await someAsyncFunction();
console.log(result);
} catch (error) {
console.error("发生错误:", error);
}
}
3、因为await会暂停代码执行,如果有多个异步操作可以使用Promise.all会更高效
const [res1, res2] = await Promise.all([fetchData1(), fetchData2()]);
8.类表达式
类表达式是JavaScript中定义类的一种语法,类似于函数表达式。类表达式可以是命名的,也可以是匿名的
const MyClass = class {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}`);
}
};
const instance = new MyClass("吃🐟的熊");
instance.sayHello(); // 输出:Hello, 吃🐟的熊
9.逗号运算符
,运算符会对他的每个操作数,从左到右求值,并返回最后一个操作数的值。
10.三元运算符
?问号前的值为真,返回:前的值,为假则返回:后的值。可以直接看成if...else的简化版本来用
11.自减:--
不管是x--还是--x,可以看成他们本身就是一个值。x--表示减一之前的值,--x表示减一之后的值,x本身都会被减一
11.1. x--
let x = 2
console.log(x--) // 2
console.log(x) // 1
返回x本身,x被修改
11.2. --x
let x = 2
console.log(--x) // 1
console.log(x) // 1
返回x-1的值,x被修改
12.delete运算符
可以删除对象的某个属性:
const obj = { name: "李华", age: 18 };
delete obj.age; // 删除 age 属性
console.log(obj); // { name: "李华" }
如果在程序的其他地方没有任何引用指向obj.age,它就会被javascript的垃圾回收机制回收,释放内存
const obj = { nested: { key: "value" } };
const anotherRef = obj.nested; // 创建对 nested 的额外引用
delete obj.nested; // 删除 obj.nested 属性
console.log(obj) // {}
console.log(anotherRef); // { key: "value" }
在上诉代码中,即使delete obj.nested,anotherRef仍然引用的是原来的对象{ key: "value" },所以不会被垃圾回收机制回收
13.解构赋值
将数组或对象的属性取出,赋值给其他变量
const [a, b, ...rest] = [10, 20, 30, 40, 50]
console.log(a) // 10
console.log(b) // 20
console.log(rest) // [30, 40, 50]
const {a, b, ...rest} = { a: 10, b: 20, c: 30, d: 40 }
console.log(a) // 10
console.log(b) // 20
console.log(rest) // { c: 30, d: 40 }
上述所结构出来的变量都是只读的,注:...rest会将数组或对象的所有剩余属性储存到新的对象或数组中,所以必须放在解构模式中的最后一个
如果你希望某些变量可以重新分配,可以使用let
const obj = { a: 1, b: { c: 2 } }
let { b: { c: count } } = obj // 此时将 obj.b.c 赋值给了 count
console.log(count) // 2
count++
console.log(count) // 3
如果你不确定某个对象是否包含你想要的值,可以在你的解构属性上添加一个默认值,当属性不存在或为undefined时,将使用默认值
const obj = { a: '', b: 'b', c: null }
const { a = '-', b = '-', c = '-', d = '-' } = obj
console.log({ a, b, c, d }) // {a: '', b: 'b', c: null, d: '-'}
14.除法:/
console.log(12 / 2) // 6
15.除法赋值:/=
将变量除以右边的值,并将结果赋值给该变量,返回结果值
let x = 12
x /= 2 // 6
console.log(x) // 6
16.相等:==
检查两个操作数是否相等,返回一个布尔值结果(会尝试转换不同类型后进行比较)
console.log(1 == '1') // true
console.log(0 == false) // true
17.严格相等运算符:===
严格相等左右如果是不同类型的操作数,返回的是false(并不会尝试转换类型再比较)
console.log(1 === 1) // true
console.log(1 === '1') // false
console.log(0 === false) // false
18.严格不相等运算符:!==
可以认为是严格相等运算的反义
console.log(1 !== 1) // false
console.log(1 !== '1') // true
console.log(0 !== false) // true
19.幂:**
返回第一个操作数取第二个操作数的幂的结果
console.log(2 ** 3) // 2的3次方:8
20.幂赋值:**=
对两个操作数执行幂运算,并将结果返回给左侧操作数
const a = 5
a **= 2 // 5的2次方:25
21.函数表达式:function
function关键字用来在表达式中定义一个函数
const fun1 = function(){
console.log('执行fun1()后能打印出这段话')
}
注: 函数表达式是没有函数提升的
22.function*表达式
可以在内部定义一个生成器函数
23.大于:>
console.log(5 > 3) // true
console.log(3 > 3) // false
24.大于等于:>=
console.log(5 >= 3) // true
console.log(3 >= 3) // true
25.圆括号运算符:()
可以控制表达式中的运算优先级,可以把括号看成优先级最高的运算符
console.log(1+1) // 2
console.log(1+1*2) // 3
console.log((1+1)*2) // 4
......