[JavaScript] ES6及以后版本的新特性

文章目录

  • 箭头函数(Arrow Functions)
    • 为什么需要箭头函数?
    • 箭头函数的完整语法
    • 箭头函数中的 `this`
    • 实用场景
  • 解构赋值(Destructuring Assignment)
    • 为什么需要解构赋值?
    • 数组解构赋值的完整用法
    • 对象解构赋值的完整用法
    • 实用场景
  • 模块化(Modules)
    • 为什么需要模块化?
    • 模块的基本概念
  • 模板字面量(Template Literals)
    • 为什么需要模板字面量?
    • 模板字面量的基本语法
    • 高级用法
    • 使用场景
  • Promise与异步编程
    • 为什么需要 Promise 和异步编程?
    • Promise 的语法与用法
    • async 和 await
    • 实用场景

箭头函数(Arrow Functions)

为什么需要箭头函数?

  1. 代码简洁

对比代码:

// ES5 写法
const numbers = [1, 2, 3];
const squared = numbers.map(function (n) {
    return n * n;
});

// ES6 箭头函数写法
const squared = numbers.map(n => n * n);
- ES5 中的函数定义通常会比较冗长,特别是在回调函数或嵌套逻辑中,代码可读性较差。
- 箭头函数通过简化语法,减少 `function` 和 `return` 等关键字的使用,使代码更加直观。
  1. 避免 this 问题
    • 在 ES5 中,函数的 this 是由调用时动态决定的,可能会指向全局对象或 undefined,造成意外错误。
    • 箭头函数继承了定义时的 this(即词法作用域),从而避免了 this 绑定问题。

箭头函数的完整语法

  1. 基本形式
const func = (param1, param2) => {
    // 函数体
    return param1 + param2;
};
  1. 省略规则
    • 如果函数体只有一行表达式,并且需要返回值,可以省略大括号 {}return
const add = (a, b) => a + b;
- 如果没有参数,必须加括号:
const greet = () => console.log("Hello!");
  1. 返回对象字面量
    如果需要返回一个对象字面量,必须用括号包裹,否则会与箭头函数的语法冲突:
const createPerson = (name, age) => ({ name, age });
console.log(createPerson("Kevin", 25)); // 输出 { name: "Kevin", age: 25 }

箭头函数中的 this

  1. this** 的词法作用域**:

示例:

// 普通函数中 this 的问题
function Timer() {
    this.seconds = 0;

    setInterval(function () {
        this.seconds++; // this 指向全局或 undefined
        console.log(this.seconds);
    }, 1000);
}

// 用箭头函数解决
function Timer() {
    this.seconds = 0;

    setInterval(() => {
        this.seconds++; // this 绑定到 Timer 对象
        console.log(this.seconds);
    }, 1000);
}
- 箭头函数不会创建自己的 `this`,它会从外层作用域中继承 `this`。
- 这在回调函数中尤为重要,避免了手动绑定 `this` 的麻烦。
  1. 无法用作构造函数
    箭头函数没有 [[Construct]] 方法,因此不能使用 new 来调用。
const Person = (name) => {
    this.name = name;
};

// new Person("Kevin"); // 报错

实用场景

  1. 回调函数
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(n => n * 2); // 简化 map 回调
  1. 事件监听
const button = document.querySelector("button");
button.addEventListener("click", () => {
    console.log("Button clicked!");
});

解构赋值(Destructuring Assignment)

为什么需要解构赋值?

  1. 简化代码
    在传统写法中,获取数组或对象的特定值需要多次声明变量。解构赋值直接在一行代码中完成这一任务,使代码更紧凑。对比代码:
// ES5 写法
const person = { name: "Kevin", age: 25 };
const name = person.name;
const age = person.age;

// ES6 解构赋值
const { name, age } = person;
  1. 避免多次访问对象属性
    解构赋值减少了对同一对象或数组的多次访问,提升性能。

数组解构赋值的完整用法

  1. 按顺序提取值
const arr = [10, 20, 30];
const [first, second] = arr;
console.log(first, second); // 输出 10 20
  1. 跳过某些值
const arr = [1, 2, 3];
const [, second] = arr;
console.log(second); // 输出 2
  1. 使用默认值
const arr = [10];
const [first, second = 20] = arr;
console.log(second); // 输出 20

对象解构赋值的完整用法

  1. 基础用法
const obj = { x: 10, y: 20 };
const { x, y } = obj;
console.log(x, y); // 输出 10 20
  1. 别名(重命名)
const obj = { x: 10, y: 20 };
const { x: newX, y: newY } = obj;
console.log(newX, newY); // 输出 10 20
  1. 嵌套解构
const obj = { person: { name: "Kevin", age: 25 } };
const { person: { name, age } } = obj;
console.log(name, age); // 输出 Kevin 25

实用场景

  1. 函数参数
function greet({ name, age }) {
    console.log(`Hello, ${name}. You are ${age} years old.`);
}
greet({ name: "Kevin", age: 25 });
  1. 交换变量值
let a = 1, b = 2;
[a, b] = [b, a];
console.log(a, b); // 输出 2 1

模块化(Modules)

为什么需要模块化?

在 ES5 之前,JavaScript 没有原生模块化系统,开发者通常使用全局变量或外部库(如 require.js)来实现模块化。但这会导致代码难以维护、命名冲突等问题。


模块的基本概念

  1. 导出模块
    • 命名导出:可以导出多个变量或函数。
export const name = "Kevin";
export function greet() {
    console.log("Hello!");
}
- **默认导出**:每个模块只能有一个默认导出。
export default function greet() {
    console.log("Hello!");
}
  1. 引入模块
    • 引入命名导出
import { name, greet } from "./module.js";
- **引入默认导出**:
import greet from "./module.js";

好的,以下将针对剩余的 模板字面量(Template Literals)Promise与异步编程 进行更加详细的讲解,包括其语法背景、具体用法、以及背后的原理和实用场景。


模板字面量(Template Literals)

为什么需要模板字面量?

在 ES5 中,字符串的操作非常繁琐,尤其是在拼接变量时,需要使用 + 串联,且难以处理多行字符串。此外,插入表达式和动态生成内容也较为麻烦。
模板字面量 的出现解决了这些问题,提供了一种更加优雅的方式来处理字符串。


模板字面量的基本语法

  1. 模板字面量的定义:用反引号 ``(反引号 ` 而不是单引号 ')定义的字符串。**
const message = `这是一个模板字面量`;
  1. 插入变量(占位符)
    使用 ${} 将变量或表达式嵌入到字符串中:
const name = "Kevin";
const age = 25;
const message = `Hello, my name is ${name} and I am ${age} years old.`;
console.log(message); // 输出:Hello, my name is Kevin and I am 25 years old.
  1. 多行字符串
    在 ES5 中,我们需要通过 \n 或字符串拼接实现多行字符串,这不仅麻烦而且不直观。
    • ES5 写法
const text = "这是第一行\n" +
             "这是第二行";
console.log(text);
- **模板字面量写法**:
const text = `这是第一行
这是第二行`;
console.log(text); // 输出多行字符串
  1. 嵌入表达式
    可以直接在 ${} 中编写表达式,而不仅仅是变量:
const a = 10, b = 20;
const result = `结果是:${a + b}`;
console.log(result); // 输出:结果是:30

高级用法

  1. 函数调用
    模板字面量支持在 ${} 中直接调用函数:
function greet(name) {
    return `Hello, ${name}!`;
}
const message = `${greet("Kevin")}`;
console.log(message); // 输出:Hello, Kevin!
  1. 标签模板(Tagged Template Literals)
    标签模板允许我们通过函数对模板字面量进行自定义解析。
function highlight(strings, ...values) {
    return strings.reduce((result, str, i) => {
        return `${result}${str}<strong>${values[i] || ""}</strong>`;
    }, "");
}

const name = "Kevin";
const age = 25;
const message = highlight`Name: ${name}, Age: ${age}`;
console.log(message); 
// 输出:Name: <strong>Kevin</strong>, Age: <strong>25</strong>

  1. 嵌套模板字面量
    支持嵌套使用模板字面量:
const user = { name: "Kevin", age: 25 };
const info = `User Info: ${`Name: ${user.name}, Age: ${user.age}`}`;
console.log(info); 
// 输出:User Info: Name: Kevin, Age: 25

使用场景

  1. 动态生成 HTML
    模板字面量非常适合用于构建动态 HTML 字符串:
const name = "Kevin";
const html = `
    <div>
        <h1>${name}</h1>

        <p>欢迎访问我的网站!</p>

    </div>

`;
console.log(html);
  1. 构建 SQL 查询
const table = "users";
const column = "name";
const sql = `SELECT ${column} FROM ${table} WHERE active = 1`;
console.log(sql);
// 输出:SELECT name FROM users WHERE active = 1

Promise与异步编程

为什么需要 Promise 和异步编程?

在 JavaScript 中,异步操作(如网络请求、文件读取、定时器等)是常见场景。
传统的异步处理方式(如回调函数)可能会导致 回调地狱(Callback Hell),使代码难以阅读和维护。

Promiseasync/await 的引入解决了这些问题,使异步代码更加可读和可维护。


Promise 的语法与用法

  1. 创建 Promise
    Promise 是一个对象,表示一个异步操作的最终完成(或失败)及其结果。
    它有三种状态:

示例:

const promise = new Promise((resolve, reject) => {
    const success = true;

    if (success) {
        resolve("操作成功");
    } else {
        reject("操作失败");
    }
});

promise
    .then(result => console.log(result)) // 操作成功
    .catch(error => console.log(error)); // 捕获错误
- `pending`:初始状态,操作尚未完成。
- `fulfilled`:操作成功完成。
- `rejected`:操作失败。
  1. 链式调用
    Promise 支持链式调用,使代码逻辑更清晰。
const fetchData = () => {
    return new Promise(resolve => {
        setTimeout(() => resolve("数据加载完成"), 1000);
    });
};

fetchData()
    .then(data => {
        console.log(data);
        return "处理后的数据";
    })
    .then(processed => console.log(processed));
  1. Promise.all
    并行执行多个 Promise,并等待所有完成:
const p1 = new Promise(resolve => setTimeout(() => resolve(1), 1000));
const p2 = new Promise(resolve => setTimeout(() => resolve(2), 2000));

Promise.all([p1, p2]).then(results => console.log(results)); 
// 输出:[1, 2]

async 和 await

  1. 为什么需要 async/await?
    • async/await 是 Promise 的语法糖,使异步代码看起来像同步代码,极大地提高了代码的可读性。
  2. 基本用法

示例:

const fetchData = () => {
    return new Promise(resolve => setTimeout(() => resolve("数据加载完成"), 1000));
};

async function loadData() {
    const data = await fetchData();
    console.log(data); // 输出:数据加载完成
}

loadData();
- 使用 `async` 声明一个函数,该函数返回一个 Promise。
- 使用 `await` 暂停异步操作,直到 Promise 完成。
  1. 错误处理
    可以使用 try...catch 捕获错误:
async function fetchWithErrorHandling() {
    try {
        const response = await fetch("https://api.example.com/data");
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("请求出错:", error);
    }
}

实用场景

  1. 数据请求
async function fetchData() {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");
    const post = await response.json();
    console.log(post);
}

fetchData();
  1. 动画和定时器
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

async function run() {
    console.log("开始");
    await delay(1000); // 等待 1 秒
    console.log("结束");
}

run();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/959299.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ipad和macbook同步zotero文献附件失败的解决办法

背景&#xff1a;我所有的文献及其附件pdf都是在台式机&#xff08;windows系统&#xff09;&#xff0c;想要把这些文献同步到云上&#xff0c;然后再从云上同步到平板和其他笔记本电脑比如macbook。文献同步虽已成功&#xff0c;但文献附件都无法打开。 平板报错如下&#xf…

element tbas增加下拉框

使用Tabs 标签页的label插槽&#xff0c;嵌入Dropdown 下拉菜单&#xff0c;实现Tabs 标签页增加下拉切换功能 Tabs 标签页 tab-click"事件"&#xff08;这个事件当中到拥有下拉框的tab里时&#xff0c;可以存一下Dropdown 第一个菜单的id&#xff0c;实现点击到拥有…

环境变量配置与问题解决

目录 方法 配置了还是运行不了想要的东西 解决方案 为什么 解决方案 方法 方法一&#xff1a;此电脑右击-属性-相关链接-高级系统设置-环境变量&#xff08;N&#xff09;-系统变量里面找到Path-三个确定】 方法二&#xff1a;winr cmd 黑框输入sysdm.cpl&#xff0c;后面…

【C++】详细讲解继承(下)

本篇来继续说说继承。上篇可移步至【C】详细讲解继承&#xff08;上&#xff09; 1.继承与友元 友元关系不能继承 &#xff0c;也就是说基类友元不能访问派⽣类私有和保护成员。 class Student;//前置声明class Same //基类 { public:friend void Fun(const Same& p, con…

联想电脑怎么设置u盘启动_联想电脑设置u盘启动方法(支持新旧机型)

有很多网友问联想电脑怎么设置u盘启动&#xff0c;联想电脑设置u盘启动的方法有两种&#xff0c;一是通过bios进行设置。二是通过快捷方式启动进入u盘启动。但需要注意有两种引导模式是&#xff0c;一种是uefi引导&#xff0c;一种是传统的leacy引导&#xff0c;所以需要注意制…

算法|牛客网华为机试53-62C++

牛客网华为机试 上篇&#xff1a;算法|牛客网华为机试41-52C 文章目录 HJ53 杨辉三角的变形HJ54 表达式求值HJ55 挑7HJ56 完全数计算HJ57 高精度整数加法HJ58 输入n个整数&#xff0c;输出其中最小的k个HJ59 找出字符串中第一个只出现一次的字符HJ60 查找组成一个偶数最接近的两…

消息队列篇--通信协议篇--TCP和UDP(3次握手和4次挥手,与Socket和webSocket的概念区别等)

1、TCP和UDP概述 TCP&#xff08;传输控制协议&#xff0c;Transmission Control Protocol&#xff09;和UDP&#xff08;用户数据报协议&#xff0c;User Datagram Protocol&#xff09;都算是最底层的通信协议&#xff0c;它们位于OSI模型的传输层。*传输层的主要职责是确保…

springboot基于Spring Boot的智慧养老服务系统的设计与实现

系统介绍&#xff1a; 智慧养老服务系统是一种运用现代科技手段&#xff0c;整合各类养老资源&#xff0c;为老年人提供全方位、个性化服务的综合性平台。该系统通过智能化设备、大数据分析、云计算等技术&#xff0c;实现对老年人健康状况、生活需求的实时监控与精准匹配&…

深圳大学-智能网络与计算-实验一:RFID原理与读写操作

实验目的与要求 掌握超高频RFID标签的寻卡操作。掌握超高频RFID标签的读写操作。掌握超高频RFID标签多张卡读取时的防冲突机制。 方法&#xff0c;步骤 软硬件的连接与设置超高频RFID寻卡操作超高频RFID防冲突机制超高频RFID读写卡操作 实验过程及内容 一&#xff0e;软硬…

python实现http文件服务器访问下载

//1.py import http.server import socketserver import os import threading import sys# 获取当前脚本所在的目录 DIRECTORY os.path.dirname(os.path.abspath(__file__))# 设置服务器的端口 PORT 8000# 自定义Handler&#xff0c;将根目录设置为脚本所在目录 class MyHTT…

【unity游戏开发之InputSystem——02】InputAction的使用介绍(基于unity6开发介绍)

文章目录 前言一、InputAction简介1、InputAction是什么&#xff1f;2、示例 二、监听事件started 、performed 、canceled1、启用输入检测2、操作监听相关3、关键参数 CallbackContext4、结果 三、InputAction参数相关1、点击齿轮1.1 Actions 动作&#xff08;1&#xff09;动…

Python 在Word中添加、或删除超链接

在Word文档中&#xff0c;超链接是一种将文本或图像连接到其他文档、网页或同一文档中不同部分的功能。通过添加超链接&#xff0c;用户可以轻松地导航到相关信息&#xff0c;从而增强文档的互动性和可读性。本文将介绍如何使用Python在Word中添加超链接、或删除Word文档中的超…

mysql 学习3 SQL语句--整体概述。SQL通用语法;DDL创建数据库,查看当前数据库是那个,删除数据库,使用数据库;查看当前数据库有哪些表

SQL通用语法 SQL语句分类 DDL data definition language : 用来创建数据库&#xff0c;创建表&#xff0c;创建表中的字段&#xff0c;创建索引。因此成为 数据定义语言 DML data manipulation language 有了数据库和表以及字段后&#xff0c;那么我们就需要给这个表中 添加数…

Unity自学之旅05

Unity自学之旅05 Unity学习之旅⑤&#x1f4dd; AI基础与敌人行为&#x1f94a; AI导航理论知识&#xff08;基础&#xff09;开始实践 &#x1f383; 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 &#x1f917; 总结归纳 Unity学习之旅⑤ &#x1f4dd; AI基础与敌…

UDP 广播组播点播的区别及联系

1、网络IP地址的分类 组播地址是分类编址的IPv4地址中的D类地址&#xff0c;又叫多播地址&#xff0c;他的前四位必须是1110&#xff0c;所以网络地址的二进制取值范围是11100000~11101111对应的十进制为 224~~239。所以以224~239开头的网络地址都是组播地址。 组播地址的功能…

css粘性定位超出指定宽度失效问题

展示效果 解决办法&#xff1a;外层容器添加display:grid即可 完整代码 <template><div class"box"><div class"line" v-for"items in 10"><div class"item" v-for"item in 8">drgg</div>&…

携程旅行 登录分析

声明: 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 逆向分析 所有加密流程基本一样就说…

(Java版本)基于JAVA的网络通讯系统设计与实现-毕业设计

源码 论文 下载地址&#xff1a; ​​​​c​​​​​​c基于JAVA的网络通讯系统设计与实现(源码系统论文&#xff09;https://download.csdn.net/download/weixin_39682092/90299782https://download.csdn.net/download/weixin_39682092/90299782 第1章 绪论 1.1 课题选择的…

PageView组件的功能和用法

文章目录 1 概念介绍2 使用方法3 示例代码 我们在上一章回中介绍了如何屏蔽事件关的内容,本章回中将介绍PageView Widget.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1 概念介绍 我们在这里介绍的PageView是指左右滑动或者上下滑动显示不同的页面&#xff0c;Flutter把它…

《Memory Barriers a Hardware View for Software Hackers》阅读笔记

CPU 设计者引入内存屏障&#xff08;memory barriers&#xff09;是为了应对在多处理器系统&#xff08;SMP&#xff09;中&#xff0c;内存引用重排序可能导致的同步问题。尽管重排序可以提高性能&#xff0c;但在某些情况下&#xff08;如同步原语&#xff09;&#xff0c;正…