每天一个表达式和运算符

91 阅读7分钟

这篇文章主要介绍了 JavaScript 中的多种运算符、表达式和关键字,包括加法、赋值、异步函数相关操作(如顺序执行、并行执行、异步函数生成器)、立即执行函数表达式、for await...of循环、await、类表达式、逗号运算符、三元运算符、自减、删除对象属性、解构赋值、除法等。

fc990b2695a444eaf3023fae496639a.jpg

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
}

ab是按顺序执行的,等待after2Seconds执行完毕后,才会执行after3Seconds,所以最后的总花费时间为5s

image.png

并行执行

const add2 = async ()=>{
  const a = after2Seconds(20)
  const b = after3Seconds(30)
  return await a + await b // 执行共花费3s
}

ab在初始化的时候会同时开始执行,因为这时候没有使用await等待,会直接开始异步操作,等待时间最长的after3Seconds完成后,add2才会返回,最后总的时间为3s

image.png

个人感觉第二种在用法上跟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); 
  }
})()

image.png

介绍一下for await...of循环

1.获取异步迭代器对象

2.在每次迭代时调用异步迭代器的next()方法

3.等待next()返回的Promise解析,获取valuedone

4.如果donefalse,继续执行下次循环;如果为true,结束循环

概括为:能自动在每次循环的时候调用异步迭代器的next()方法并处理Promise,无需手动调用next()

6.2.手动next()输出

image.png

这时候第一次执行完毕,处于暂停状态,,直到下次next()触发

image.png

每次触发next(),都会执行下一个yield返回的异步函数

7.await

用于异步编程的操作符,可以暂停代码执行,直到一个Promise被解决(fulfilledrejected),只能在异步函数或者模块顶层使用。简而言之,它让异步代码看起来像同步代码。

// 模拟一个异步操作
function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => resolve("数据已加载"), 1000);
    });
}

// 使用 await
async function getData() {
    console.log("开始加载...");
    const result = await fetchData(); // 暂停,等待 fetchData 完成
    console.log(result); // "数据已加载"
}

getData();

image.png

注意:

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.逗号运算符

,运算符会对他的每个操作数,从左到右求值,并返回最后一个操作数的值。

image.png

10.三元运算符

?问号前的值为真,返回:前的值,为假则返回:后的值。可以直接看成if...else的简化版本来用

image.png

11.自减:--

image.png

不管是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.nestedanotherRef仍然引用的是原来的对象{ 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

......