Bootstrap

【前端速通系列|第一篇】ES6核心语法


在这里插入图片描述

1.ES6简介

ES6 是 ECMAScript 2015 的缩写,是 ECMAScript 语言标准的第6个版本。ECMAScript 是 JavaScript 语言的国际标准化组织制定的规范,规定了语言的基本语法、类型、对象、属性以及方法等内容。ES6 于2015年6月正式发布,引入了许多重要的新特性和语法改进,旨在使 JavaScript 更适合构建复杂和大规模的应用程序。

2.let和const

letconst 是在ES6中引入的两个新的变量声明关键字,它们为 JavaScript 的变量声明和作用域管理带来了重要的改进。

在此之前还有一个关键字可以声明变量,那就是var

例如:

var a = 1;
let b = 2;

可能大家也听说过,能用var的地方都可以使用let进行替代. 至于为什么,是因为使用var会出现以下几个问题:

  1. 越狱image-20240608223806476

如图所示,a和b实在代码块中定义的,但是a越出了代码块,所以在使用时可能会出现一些问题

  1. 重复声明

用var声明变量时,可以对同一个变量重复声明,而使用let不行,只允许声明一次

image-20240608224220616

  1. 变量提升

在Java中是使用变量是要先声明变量的,与let相同.但是使用var声明变量时则可以不先声明就可以使用. 而let则不行
image-20240608224454314

接着说const, const修饰的变量是不允许修改的,可以看到这里就直接报错了
image-20240608224827361

3.解构

解构允许你将数组或对象的属性直接赋值给不同的变量。

这里的解构分为数组结构和对象结构

  • 数组解构:能够将数组中的元素直接分配给独立的变量。
let arr = [1, 2, 3];
console.log(arr[0])
console.log(arr[1])
console.log(arr[2])

let [a, b, c] = arr;
console.log(a)
console.log(b)
console.log(c)

一般我们在取数组中的元素时,都是按照下标来取. 数组解构是将数组 [1, 2, 3] 的元素分别被解构赋值给变量 a, b, 和 c

  • 对象解构:将对象的属性值直接赋给同名的变量。
let user = {
    id: 1,
    name: zhansgan,
    age: 18
}
console.log(user.id)
console.log(user.name)
console.log(user.age)

let {name, age} = user
console.log(name)
console.log(age)

// 还能用在方法上
function test({name, age}) {
    console.log(name)
    console.log(age)
}

test(user)

解构赋值不仅限于简单变量,它也可以用于函数参数,使得函数能更简洁地接收和使用数组或对象类型的参数,提高了代码的清晰度和效率。

4.链判断

链判断运算符(也称为可选链操作符)是ECMAScript 2020(ES2020)中引入的一个新特性,其符号表示为?.。这个运算符主要用于安全地访问深层嵌套的属性或方法,而无需担心中间某个环节为nullundefined时导致的错误。

在没有链判断运算符的情况下,访问深层属性通常需要先检查每一级是否为nullundefined,以避免抛出错误。例如:

// 如果想要获取obj.info.user.content
if (obj && obj.info && obj.info.user) {
    console.log(obj.info.user.content);
} else {
    console.log('err');
}

可以看到对每一层进行非空检查,会十分麻烦.

而使用链判断运算符则可以很好的简化

console.log(obj?.info?.user?.content || 'err');

上面这一行代码就是对前面四行代码的简化.

?.运算符会在尝试访问属性前检查左侧的操作数是否为nullundefined。如果是,则立即停止评估并返回undefined,而不是继续执行并抛出错误。这在处理可能缺失的属性路径时非常有用,尤其是在处理外部API返回的数据或是可选配置对象时。

这里要提两个运算符||??

??(空值合并运算符)和||(逻辑或运算符)都可以用于为变量提供默认值

  • ??(空值合并运算符)在左侧的操作数为null或undefined时,才会返回右侧的操作数。这意味着如果左侧的操作数有一个非null和非undefined的值(即使这个值是false、0、空字符串或其他“假”值),都不会返回右侧的操作数。
  • ||(逻辑或运算符)在左侧的操作数被解释为“假”(包括null、undefined、false、0、空字符串、NaN)时,会返回右侧的操作数。因此,如果左侧是任何“假”值,不管它是不是严格意义上的null或undefined,都会返回右侧的操作数。

5.参数默认值

参数默认值允许你在定义函数时为参数指定一个默认的值。如果函数被调用时没有为该参数提供值或者提供的值是undefined,那么该参数就会使用其默认值。

在JavaScript中,可以直接在函数参数定义时通过= value来指定默认值:

例如:

function hello(name = 'World') {
    console.log(`Hello, ${name}!`);
}

hello(); // 输出 "Hello, World!"
hello('abc'); // 输出 "Hello, abc!"

6.箭头函数

箭头函数是一种更简化的函数表达式书写方式,它使用=>符号定义。它类似于Java中的lambda表达式

一般情况下创建方法的两种方式:

function add(a, b) {
    console.log(a + b);
}

let add1 = function add(a, b) {
    console.log(a + b);
}

使用箭头函数创建

let add2 = (a, b) => {
    console.log(a + b);
}

⭐简单来说就是把function删除掉,在参数列表后面加 =>

如果函数体内部只有一句话,也可以省略{}

let add2 = (a, b) => console.log(a + b);

如果函数只有参数,可以省略()

let func1 = num => console.log(num)
func1(1) // 调用方法

7.模板字符串

ES6引入了模板字符串,这是一种增强型的字符串字面量表示法,使用**反引号`**来界定字符串。

模板字符串最常见的用法就是插值.

插值(Interpolation):通过${expression}语法,可以在字符串中嵌入表达式。表达式将在运行时求值,并将其转换为字符串形式插入到最终的字符串中。这使得字符串拼接变得简单且易读。

例如:

const name = "zhangsan"
const age = 19
console.log(`姓名是 ${name}, 年龄是${age}`)
// 输出结果 姓名是 zhangsan, 年龄是19

除此之外,还有两个不常用的用法.

多行字符串:模板字符串允许你在字符串中直接编写多行文本,无需使用转义字符,这使得编写HTML片段、SQL语句或者任何需要跨越多行的文本变得更加自然。

例如:

const html = `
    <div>
        <h1>Hello, world!</h1>
    </div>
`;

8.Promise

ES6引入了Promise对象,Promise代表异步对象

Promise 是现代 JavaScript 中异步编程的基础,是一个由异步函数返回的可以向我们指示当前操作所处的状态的对象。在 Promise 返回给调用者的时候,操作往往还没有完成,但 Promise 对象可以让我们操作最终完成时对其进行处理(无论成功还是失败)基本概念:

上面都是一些概念不好理解,可以看下我的理解

⭐异步操作: 在实际开发中,我们往往要发送网络请求,如果是同步操作,就会等待网络请求完成.但如果网络请求很慢,就会阻塞后面代码的执行. 而异步操作则不会阻塞,发送网络请求完成后,依旧会执行后面代码,等网络请求成功后再进行处理

Promise 有三种状态:

  • Pending(等待中):初始状态,既没有被兑现,也没有被拒绝。
  • Fulfilled(已成功):表示操作成功完成,此时Promise变为resolved状态,并携带一个成功的结果值。
  • Rejected(已失败):表示操作失败,Promise变为rejected状态,并携带一个失败的原因。

创建Promise

const promise = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    if (/* 操作成功 */) {
      resolve('操作成功后的操作');
    } else {
      reject('操作失败的原因');
    }
  }, 2000);
});

消费Promise

  • then():用于处理成功的场景,可以链式调用。
  • catch():用于处理失败的场景。
  • finally():无论Promise成功还是失败,都会执行的回调,常用于清理资源。
promise
  .then(result => console.log('成功:', result))
  .catch(error => console.error('失败:', error))
  .finally(() => console.log('无论成功还是失败,都会执行'));

9.Async函数

Async/Await是ES2017中引入的一个非常重要的特性,它建立在Promise的基础上,提供了更简洁、更易读的方式来处理异步操作。

async:是一个关键字,用于声明一个异步函数。异步函数总是返回一个Promise。

示例:

async function func() {
    // 业务代码示例
    let x = 101;
    if (x % 2 === 0) {
        return x;
    } else {
        throw new Error("x不是偶数");
    }
}
func()
    .then(data => console.log("then", data))
    .catch(err => console.log("catch", err))

因为返回的是Promise对象,因为可以使用对应的then,catch方法.

有一点需要注意,catch方法是处理失败的场景.如果想要让catch进行处理,就需要在业务代码中抛出异常

10.Await关键字

await:只能在async函数内部使用,用来等待Promise的结果,它会使代码暂停执行,直到Promise解析完成(resolve或reject),然后继续执行并返回Promise的结果。

在不使用await关键字时,要获取Promise对象里的数据,要用到.then方法,还要用到箭头函数.如果在.then方法中处理数据又有Promise对象,就需要再使用.then方法,就会非常麻烦且代码可读性不好.

示例:

async function fetchData() {
    let promise1 = fetch(url);
    promise1.then(data => {
        let promise2 = data.json();
        promise2.then(jdata => {
            console.log(jdata)
        });
    })
}
fetchData();

使用await关键字可以简单代码如下:

async function fetchData() {
    let promise1 = await fetch(url);
    let promise2 = await promise1.json();
    console.log(promise2)
}

fetchData();

fetch方法是现代Web开发中用于发送网络请求的核心API,它是在ES6中被引入的,用于替代传统的XMLHttpRequest(XHR)对象。fetch提供了一个更强大、灵活且易于使用的接口来处理网络请求,支持Promise,适用于各种资源的获取,如JSON数据、文本、图片等。

基本用法:最基础的fetch调用非常简单,只需要传入URL作为参数

返回值:fetch返回的是一个Promise,它会根据HTTP响应的状态来解析为一个Response对象。从Response对象中,你可以进一步提取数据,比如使用.json().text()等方法。

⭐需要注意:async修饰的方法仍然是异步的,await只是在这个方法内做了暂停等待,等待期间async以外的代码依然继续执行,当await结束后async方法内部的代码继续执行

11.模块化

模块化是软件开发中的一个重要概念,它涉及到将复杂的程序分解为多个相互独立、功能单一的模块。

ES6正式引入了原生的模块系统,它使用importexport关键字来定义和使用模块。

在Java中,我们在开发中,通常会将用到的mapper,service,controller,实体类等创建在对应的包下面.如果我要在controller中使用到实体类对象,就需要import导入对应的实体类.js也是如此

Java中可以使用访问控制修饰符保护对类、变量、方法和构造方法的访问,但是js中没有访问控制修饰符这一概念,但可以使用export关键字来实现.

多说无益,直接看代码:

我在lib目录下创建user.js 用于定义user相关的属性和方法,使用export关键字导出单个或多个函数、对象、类等。

const user = {
    id: 1,
    name: "zhangsan",
    age: 20
}

const isAdult = (age) => {
    if (age > 18) {
        console.log("已成年")
    } else {
        console.log("未成年")
    }
}
const test = () => console.log("test")
// export 导出
export {user, isAdult}

在main.js中进行导入调用

import {user, isAdult} from 'lib/user'

isAdult(user.age)

// test(); 这个方法并没有导出,因此也没法导入使用

在html页面中导入js时,还需要使用type="module"

<script src="main.js" type="module"></script>

通过type=“module”,浏览器能够识别这些语句并正确地解析模块间的依赖关系,按照正确的顺序加载它们。

;