Javascript解耦,以及Javascript学习网站推荐

一、学习网站推荐

解构 - JavaScript | MDN

界面如下,既有知识点,也有在线编译器执行代码。初学者可以看看

二、Javascript什么是解构

解构语法是一种 Javascript 语法。可以将数组中的值或对象的属性取出,赋值给其他变量。它可以在接收数据的位置使用(例如赋值的左侧或创建新标识符绑定的任何位置)。

代码如下:

let a, b, rest;
[a, b] = [10, 20];console.log(a);
// 期望输出:10console.log(b);
// 期望输出:20[a, b, ...rest] = [10, 20, 30, 40, 50];console.log(rest);
// 期望输出:Array [30, 40, 50]

运行结果如下:

 1020Array [30, 40, 50]

语法

const [a, b] = array;
const [a, , b] = array;
const [a = aDefault, b] = array;
const [a, b, ...rest] = array;
const [a, , b, ...rest] = array;
const [a, b, ...{ pop, push }] = array;
const [a, b, ...[c, d]] = array;const { a, b } = obj;
const { a: a1, b: b1 } = obj;
const { a: a1 = aDefault, b = bDefault } = obj;
const { a, b, ...rest } = obj;
const { a: a1, b: b1, ...rest } = obj;
const { [key]: a } = obj;let a, b, a1, b1, c, d, rest, pop, push;
[a, b] = array;
[a, , b] = array;
[a = aDefault, b] = array;
[a, b, ...rest] = array;
[a, , b, ...rest] = array;
[a, b, ...{ pop, push }] = array;
[a, b, ...[c, d]] = array;({ a, b } = obj); // brackets are required
({ a: a1, b: b1 } = obj);
({ a: a1 = aDefault, b = bDefault } = obj);
({ a, b, ...rest } = obj);
({ a: a1, b: b1, ...rest } = obj);

描述

对象和数组字面量表达式提供了一种简单的方法来创建临时的数据包。

const arr = [a, b, c];

解构使用类似的语法,但在赋值的左侧定义了要从原变量中取出哪些值。

const arr = [1, 2, 3];
const [a, b, c] = arr;
// a = 1, b = 2, c = 3

同样,你可以在赋值语句的左侧解构对象。

const obj = { a, b, c };
const { a, b, c } = obj;
// 等同于:
// const a = obj.a, b = obj.b, c = obj.c;const obj = { prop1: x, prop2: y, prop3: z };
const { prop1: x, prop2: y, prop3: z } = obj;
// 等同于:
// const x = obj.prop1, y = obj.prop2, z = obj.prop3;

这种功能类似于 Perl 和 Python 等语言中存在的特性。

有关数组或对象解构的特定功能,请参阅下面的各个示例。

绑定与赋值

对于对象和数组的解构,有两种解构模式:绑定模式赋值模式,它们的语法略有不同。

在绑定模式中,模式以声明关键字(varlet 或 const)开始。然后,每个单独的属性必须绑定到一个变量或进一步解构。

const obj = { a: 1, b: { c: 2 } };
const {a,b: { c: d },
} = obj;
// 变量 `a` 和 `d` 被绑定

所有变量共享相同的声明,因此,如果你希望某些变量可重新分配,而其他变量是只读的,则可能需要解构两次——一次使用 let,一次使用 const

const obj = { a: 1, b: { c: 2 } };
const { a } = obj; // a 为常量
let {b: { c: d },
} = obj; // d 可被重新赋值

你也可以在其他许多为你绑定变量的语法中,使用绑定解构模式。这些包括:

  • for...in、for...of 和 for await...of 循环中的循环变量,
  • 函数参数,
  • catch 绑定变量。

在赋值模式中,模式不以关键字开头。每个解构属性都被赋值给一个赋值目标——这个赋值目标可以事先用 var 或 let 声明,也可以是另一个对象的属性——一般来说,可以是任何可以出现在赋值表达式左侧的东西。

const numbers = [];
const obj = { a: 1, b: 2 };
({ a: numbers[0], b: numbers[1] } = obj);
// 属性 `a` 和 `b` 被赋值给了 `numbers` 的属性

备注: 当使用对象字面量解构而不带声明时,在赋值语句周围必须添加括号 ( ... )

{ a, b } = { a: 1, b: 2 } 不是有效的独立语法,因为左侧的 {a, b} 被视为块而不是对象字面量。但是,({ a, b } = { a: 1, b: 2 }) 是有效的,const { a, b } = { a: 1, b: 2 } 也是有效的。

如果你的编码风格不包括尾随分号,则 ( ... ) 表达式前面需要有一个分号,否则它可能用于执行前一行的函数。

请注意,上述代码在等效的绑定模式中不是有效的语法:

const numbers = [];
const obj = { a: 1, b: 2 };
const { a: numbers[0], b: numbers[1] } = obj;// 等同于:
//   const numbers[0] = obj.a;
//   const numbers[1] = obj.b;
// 无效代码

你只能在赋值运算符的左侧使用赋值模式。不能与复合赋值运算符如 += 或 *= 一起使用。

默认值

每个解构属性都可以有一个默认值。当属性不存在或值为 undefined 时,将使用默认值。如果属性的值为 null,则不使用默认值。

const [a = 1] = []; // a 是 1
const { b = 2 } = { b: undefined }; // b 是 2
const { c = 2 } = { c: null }; // c 是 null

默认值可以是任何表达式。仅在必要时对其进行求值。

const { b = console.log("hey") } = { b: 2 };
// 不会输出任何东西,因为 `b` 的值已经被定义,所以不需要求默认值。

剩余属性和剩余元素

你可以使用剩余属性(...rest)结束解构模式。对数组解构时,此模式会将数组的剩余元素存储到新的名为 rest(或在代码中指定的其他名字)的数组中。对对象解构时,此模式会将对象剩余的可枚举属性存储到新的名为 rest 的对象中。

更正式的说,...rest 语法在数组解构中被称作“剩余元素”,在对象解构中被称作“剩余属性”,但我们通常统称其为“剩余属性”。

const { a, ...others } = { a: 1, b: 2, c: 3 };
console.log(others); // { b: 2, c: 3 }const [first, ...others2] = [1, 2, 3];
console.log(others2); // [2, 3]

剩余属性必须是模式中的最后一个,并且不能有尾随逗号。

const [a, ...b,] = [1, 2, 3];// SyntaxError: rest element may not have a trailing comma
// 始终考虑将剩余运算符作为最后一个元素

示例

解构数组

基本变量赋值
const foo = ["one", "two", "three"];const [red, yellow, green] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // "three"
解构比源更多的元素

在从赋值语句右侧指定的长度为 N 的数组解构的数组中,如果赋值语句左侧指定的变量数量大于 N,则只有前 N 个变量被赋值。其余变量的值将是未定义。

const foo = ["one", "two"];const [red, yellow, green, blue] = foo;
console.log(red); // "one"
console.log(yellow); // "two"
console.log(green); // undefined
console.log(blue); //undefined
交换变量

可以在一个解构表达式中交换两个变量的值。

没有解构的情况下,交换两个变量需要一个临时变量(或者用低级语言中的异或交换技巧)。

let a = 1;
let b = 3;[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1const arr = [1, 2, 3];
[arr[2], arr[1]] = [arr[1], arr[2]];
console.log(arr); // [1, 3, 2]
解析一个从函数返回的数组

从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。

在下面例子中,要让 f() 返回值 [1, 2] 作为其输出,可以使用解构在一行内完成解析。

function f() {return [1, 2];
}const [a, b] = f();
console.log(a); // 1
console.log(b); // 2
忽略某些返回值

你可以忽略你不感兴趣的返回值:

function f() {return [1, 2, 3];
}const [a, , b] = f();
console.log(a); // 1
console.log(b); // 3const [c] = f();
console.log(c); // 1

你也可以忽略全部返回值:

[, ,] = f();
使用绑定模式作为剩余属性

数组解构的剩余属性可以是另一个数组或对象绑定模式。这允许你同时提取数组的属性和索引。

const [a, b, ...{ pop, push }] = [1, 2];
console.log(a, b); // 1 2
console.log(pop, push); // [Function pop] [Function push]
const [a, b, ...[c, d]] = [1, 2, 3, 4];
console.log(a, b, c, d); // 1 2 3 4

这些绑定模式甚至可以嵌套,只要每个剩余属性都在列表的最后。

const [a, b, ...[c, d, ...[e, f]]] = [1, 2, 3, 4, 5, 6];
console.log(a, b, c, d, e, f); // 1 2 3 4 5 6

另一方面,对象解构只能有一个标识符作为剩余属性。

const { a, ...{ b } } = { a: 1, b: 2 };
// SyntaxError: `...` must be followed by an identifier in declaration contextslet a, b;
({ a, ...{ b } } = { a: 1, b: 2 });
// SyntaxError: `...` must be followed by an assignable reference in assignment contexts
从正则表达式匹配项中提取值

当正则表达式的 exec() 方法找到匹配项时,它将返回一个数组,该数组首先包含字符串的整个匹配部分,然后返回与正则表达式中每个括号组匹配的字符串部分。解构允许你轻易地提取出需要的部分,如果不需要,则忽略完整匹配。

function parseProtocol(url) {const parsedURL = /^(\w+):\/\/([^/]+)\/(.*)$/.exec(url);if (!parsedURL) {return false;}console.log(parsedURL);// ["https://developer.mozilla.org/zh-CN/docs/Web/JavaScript",// "https", "developer.mozilla.org", "zh-CN/docs/Web/JavaScript"]const [, protocol, fullhost, fullpath] = parsedURL;return protocol;
}console.log(parseProtocol("https://developer.mozilla.org/zh-CN/docs/Web/JavaScript"),
);
// "https"
在任何可迭代对象上使用数组解构

数组解构调用右侧的迭代协议。因此,任何可迭代对象(不一定是数组)都可以解构。

jsCopy to Clipboard

const [a, b] = new Map([[1, 2],[3, 4],
]);
console.log(a, b); // [1, 2] [3, 4]

不可迭代对象不能解构为数组。

jsCopy to Clipboard

const obj = { 0: "a", 1: "b", length: 2 };
const [a, b] = obj;
// TypeError: obj is not iterable

只有在分配所有绑定之前,才会迭代可迭代对象。

jsCopy to Clipboard

const obj = {*[Symbol.iterator]() {for (const v of [0, 1, 2, 3]) {console.log(v);yield v;}},
};
const [a, b] = obj; // Only logs 0 and 1

其余的绑定会提前求值并创建一个新数组,而不是使用旧的迭代器。

jsCopy to Clipboard

const obj = {*[Symbol.iterator]() {for (const v of [0, 1, 2, 3]) {console.log(v);yield v;}},
};
const [a, b, ...rest] = obj; // Logs 0 1 2 3
console.log(rest); // [2, 3] (an array)

解构对象

基本赋值

jsCopy to Clipboard

const user = {id: 42,isVerified: true,
};const { id, isVerified } = user;console.log(id); // 42
console.log(isVerified); // true
赋值给新的变量名

可以从对象中提取属性,并将其赋值给名称与对象属性不同的变量。

jsCopy to Clipboard

const o = { p: 42, q: true };
const { p: foo, q: bar } = o;console.log(foo); // 42
console.log(bar); // true

举个例子,const { p: foo } = o 从对象 o 中获取名为 p 的属性,并将其赋值给名为 foo 的局部变量。

赋值到新的变量名并提供默认值

一个属性可以同时是两者:

  • 从对象提取并分配给具有不同名称的变量。
  • 指定一个默认值,以防获取的值为 undefined

jsCopy to Clipboard

const { a: aa = 10, b: bb = 5 } = { a: 3 };console.log(aa); // 3
console.log(bb); // 5
从作为函数参数传递的对象中提取属性

传递给函数参数的对象也可以提取到变量中,然后可以在函数体内访问这些变量。至于对象赋值,解构语法允许新变量具有与原始属性相同或不同的名称,并为原始对象未定义属性的情况分配默认值。

请考虑此对象,其中包含有关用户的信息。

jsCopy to Clipboard

const user = {id: 42,displayName: "jdoe",fullName: {firstName: "Jane",lastName: "Doe",},
};

在这里,我们展示了如何将传递对象的属性提取到具有相同名称的变量。参数值 { id } 表示传递给函数的对象的 id 属性应该被提取到一个同名变量中,然后可以在函数中使用。

jsCopy to Clipboard

function userId({ id }) {return id;
}console.log(userId(user)); // 42

你可以定义提取变量的名称。在这里,我们提取名为 displayName 的属性,并将其重命名为 dname,以便在函数体内使用。

jsCopy to Clipboard

function userDisplayName({ displayName: dname }) {return dname;
}console.log(userDisplayName(user)); // `jdoe`

嵌套对象也可以提取。下面的示例展示了属性 fullname.firstName 被提取到名为 name 的变量中。

jsCopy to Clipboard

function whois({ displayName, fullName: { firstName: name } }) {return `${displayName} is ${name}`;
}console.log(whois(user)); // "jdoe is Jane"
设置函数参数的默认值

默认值可以使用 = 指定,如果指定的属性在传递的对象中不存在,则将其用作变量值。

下面我们展示了一个默认大小为 big的函数,默认坐标为 x: 0, y: 0,默认半径为 25。

jsCopy to Clipboard

function drawChart({size = "big",coords = { x: 0, y: 0 },radius = 25,
} = {}) {console.log(size, coords, radius);// do some chart drawing
}drawChart({coords: { x: 18, y: 30 },radius: 30,
});

在上面 drawChart 的函数签名中,解构的左侧具有空对象 = {} 的默认值。

你也可以在没有该默认值的情况下编写该函数。但是,如果你省略该默认值,该函数将在调用时寻找至少一个参数来提供,而在当前形式下,你可以在不提供任何参数的情况下调用 drawChart()。否则,你至少需要提供一个空对象字面量。

有关详细信息,请参阅默认参数值 > 有默认值的解构参数。

解构嵌套对象和数组

jsCopy to Clipboard

const metadata = {title: "Scratchpad",translations: [{locale: "de",localization_tags: [],last_edit: "2014-04-14T08:43:37",url: "/de/docs/Tools/Scratchpad",title: "JavaScript-Umgebung",},],url: "/zh-CN/docs/Tools/Scratchpad",
};let {title: englishTitle, // renametranslations: [{title: localeTitle, // rename},],
} = metadata;console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"
For of 迭代和解构

jsCopy to Clipboard

const people = [{name: "Mike Smith",family: {mother: "Jane Smith",father: "Harry Smith",sister: "Samantha Smith",},age: 35,},{name: "Tom Jones",family: {mother: "Norah Jones",father: "Richard Jones",brother: "Howard Jones",},age: 25,},
];for (const {name: n,family: { father: f },
} of people) {console.log(`Name: ${n}, Father: ${f}`);
}// "Name: Mike Smith, Father: Harry Smith"
// "Name: Tom Jones, Father: Richard Jones"
对象属性计算名和解构

计算属性名,如对象字面量,可以被解构。

const key = "z";
const { [key]: foo } = { z: "bar" };console.log(foo); // "bar"
无效的 JavaScript 标识符作为属性名称

通过提供有效的替代标识符,解构可以与不是有效的 JavaScript 标识符的属性名称一起使用。

const foo = { "fizz-buzz": true };
const { "fizz-buzz": fizzBuzz } = foo;console.log(fizzBuzz); // true

解构基本类型

对象解构几乎等同于属性访问。这意味着,如果尝试解构基本类型的值,该值将被包装到相应的包装器对象中,并且在包装器对象上访问该属性。

const { a, toFixed } = 1;
console.log(a, toFixed); // undefined ƒ toFixed() { [native code] }

与访问属性相同,解构 null 或 undefined 会抛出 TypeError。

jsCopy to Clipboard

const { a } = undefined; // TypeError: Cannot destructure property 'a' of 'undefined' as it is undefined.
const { a } = null; // TypeError: Cannot destructure property 'b' of 'null' as it is null.

即使模式为空,也会发生这种情况。

const {} = null; // TypeError: Cannot destructure 'null' as it is null.
组合数组和对象解构

数组和对象解构可以组合使用。假设你想要下面 props 数组中的第三个元素,然后你想要对象中的 name 属性,你可以执行以下操作:

jsCopy to Clipboard

const props = [{ id: 1, name: "Fizz" },{ id: 2, name: "Buzz" },{ id: 3, name: "FizzBuzz" },
];const [, , { name }] = props;console.log(name); // "FizzBuzz"
解构对象时查找原型链

当解构一个对象时,如果属性本身没有被访问,它将沿着原型链继续查找。

const obj = {self: "123",__proto__: {prot: "456",},
};
const { self, prot } = obj;console.log(self); // "123"
console.log(prot); // "456"

规范

Specification
ECMAScript® 2026 Language Specification# sec-destructuring-assignment
ECMAScript® 2026 Language Specification# sec-destructuring-binding-patterns

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java大模型开发入门 (11/15):让AI自主行动 - 初探LangChain4j中的智能体(Agents)

前言 在过去的十篇文章里,我们已经打造出了一个相当强大的AI应用。它有记忆,能进行多轮对话;它有知识,能通过RAG回答关于我们私有文档的问题。它就像一个博学的“学者”,你可以向它请教任何在其知识范围内的问题。 但…

Qt KDReports详解与使用

Qt KDReports详解与使用 一、KD Reports 简介二、安装与配置三、核心功能与使用1、创建基础报表2、添加表格数据3、导出为 PDF4、XML报表定义 四、高级功能1、动态数据绑定2、自定义图表3、模板化设计4、页眉页脚设置 五、常见问题六、总结七、实际应用示例:发票生成…

Spring Cloud 原生中间件

📝 代码记录 Consul(服务注册与发现 分布式配置管理) 拥有服务治理功能,实现微服务之间的动态注册与发现 ❌不在使用Eureka:1. 停更进维 2. 注册中心独立且和微服务功能解耦 Consul官网 Spring官方介绍 三个注册中…

CMake实践: 以开源库QSimpleUpdater为例,详细讲解编译、查找依赖等全过程

目录 1.环境和工具 2.CMake编译 3.查找依赖文件 3.1.windeployqt 3.2.dumpbin 4.总结 相关链接 QSimpleUpdater:解锁 Qt 应用自动更新的全新姿势-CSDN博客 1.环境和工具 windows 11, x64 Qt5.12.12或Qt5.15.2 CMake 4.0.2 干净的windows 7,最好是…

WordToCard制作高考志愿填报攻略小卡片【豆包版】

一、什么是WordToCard WordToCard是一个免费的工具,能够将Word文档自动转换为美观的知识卡片或图文海报。以下是它的主要特点: 功能优势 格式支持:支持标题、列表、表格、LaTeX公式等多种格式。模板丰富:提供多种风格的模板&am…

什么是PostCSS

PostCSS是一个用 JavaScript 工具和插件转换 CSS 代码的工具 PostCSS是基于 JavaScript 的 CSS 转换引擎,通过插件系统对 CSS 进行现代化处理,PostCSS 不是预处理器,而是 CSS 的编译器工具链,如同 Babel 之于 JavaScript&#xf…

游戏引擎学习第315天:取消排序键的反向顺序

仓库:https://gitee.com/mrxiao_com/2d_game_8 必须保证代码能跟上不然调试很麻烦 回顾并为今天定调 目前正处于对引擎中 Z 轴处理方式进行修改的阶段。上次我们暂停在一个节点,当时我们希望不再让所有屏幕上的精灵都必须通过同一个排序路径进行排序。我们想要将…

MySQL EXPLAIN 详解

MySQL EXPLAIN 详解:掌握 SQL 性能优化的关键工具 在日常数据库开发和优化过程中,很多开发者会遇到 SQL 查询变慢、索引未命中等问题。MySQL 提供了一个非常实用的工具 —— EXPLAIN 关键字,它可以帮助我们分析 SQL 查询的执行计划,识别潜在的性能瓶颈,从而有针对性地进行…

k8s使用私有harbor镜像源

前言 在node上手动执行命令可以正常从harbor拉取镜像,但是用k8s不行,使用kubectl describe pods xxx 提示未授权 unauthorized to access repository。 处理方法 创建一个secrete资源对象。以下示例中 registry-harbor 为secret资源对象的名称。除了邮…

AI绘画能发展到企业大规模使用的地步么?

1 技术演进与当前成熟度 AI绘画技术经历了从实验室概念到商业级工具的蜕变过程。早期技术受限于模型坍缩等问题,难以满足商业需求。关键突破出现在新型生成模型的应用,大幅提升生成速度至30秒内,在画面逻辑性和风格多样性方面实现质的飞跃。…

使用MyBatis-Plus实现数据权限功能

什么是数据权限 数据权限是指系统根据用户的角色、职位或其他属性,控制用户能够访问的数据范围。与传统的功能权限(菜单、按钮权限)不同,数据权限关注的是数据行级别的访问控制。 常见的数据权限控制方式包括: 部门数…

大模型——Dify 与 Browser-use 结合使用

大模型——Dify 与 Browser-use 结合使用 Dify 与 Browser-use 的结合使用,能够通过 AI 决策与自动化交互的协同,构建智能化、场景化的业务流程。 以下是两者的整合思路与技术落地方案: 一、核心组合逻辑 分工定位 Dify:作为AI模型调度中枢,负责自然语言理解、决策生成、…

transformer demo

import torch import torch.nn as nn import torch.nn.functional as F import math import numpy as np import pytestclass PositionalEncoding(nn.Module):def __init__(self, d_model, max_seq_length5000):super(PositionalEncoding, self).__init__()# 创建位置编码矩阵p…

centos 8.3(阿里云服务器)mariadb由系统自带版本(10.3)升级到10.6

1. 备份数据库 在进行任何升级操作前,务必备份所有数据库: mysqldump -u root -p --all-databases > all_databases_backup.sql # 或者为每个重要数据库单独备份 mysqldump -u root -p db_name1 > db_name1_backup.sql mysqldump -u root -p db…

如何稳定地更新你的大模型知识(算法篇)

目录 在线强化学习的稳定知识获取机制:算法优化与数据策略一、算法层面的稳定性控制机制二、数据处理策略的稳定性保障三、训练过程中的渐进式优化策略四、环境设计与反馈机制的稳定性影响五、稳定性保障的综合应用策略六、总结与展望通过强化学习来让大模型学习高层语义知识,…

图的遍历模板

图的遍历 BFS 求距离 #include<bits/stdc.h>using namespace std;int n, m, k,q[20001],dist[20001]; vector<int> edge[20001];int main(){scanf("%d%d%d",&n,&m,&k);for (int i 1;i<m;i){int x,y;scanf("%d%d",&x,&am…

Java集合 - LinkedList底层源码解析

以下是基于 JDK 8 的 LinkedList 深度源码解析&#xff0c;涵盖其数据结构、核心方法实现、性能特点及使用场景。我们从 类结构、Node节点、插入/删除/访问操作、线程安全、性能对比 等角度进行详细分析 一、类结构与继承关系 1. 类定义 public class LinkedList<E> e…

Pytorch 卷积神经网络参数说明一

系列文章目录 文章目录 系列文章目录前言一、卷积层的定义1.常见的卷积操作2. 感受野3. 如何理解参数量和计算量4.如何减少计算量和参数量 二、神经网络结构&#xff1a;有些层前面文章说过&#xff0c;不全讲1. 池化层&#xff08;下采样&#xff09;2. 上采样3. 激活层、BN层…

C++ 中的 iostream 库:cin/cout 基本用法

iostream 是 C 标准库中用于输入输出操作的核心库&#xff0c;它基于面向对象的设计&#xff0c;提供了比 C 语言的 stdio.h 更强大、更安全的 I/O 功能。下面详细介绍 iostream 库中最常用的输入输出工具&#xff1a;cin 和 cout。 一、 基本概念 iostream 库&#xff1a;包…

SAP复制一个自定义移动类型

SAP复制移动类型 在SAP系统中&#xff0c;复制移动类型201可以通过事务码OMJJ或SPRO路径完成&#xff0c;用于创建自定义的移动类型以满足特定业务需求。 示例操作步骤 进入OMJJ事务码&#xff1a; 打开事务码OMJJ&#xff0c;选择“移动类型”选项。 复制移动类型&#xff…