• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2025-04-05 15:28 Aet 隐藏边栏 |   抢沙发  4 
文章评分 2 次,平均分 5.0

解构赋值

概述

  1. JavaScript 中最常用的两种数据结构是 ObjectArray
    1. 对象是一种根据键存储数据的实体
    2. 数组是一种直接存储数据的有序列表
  2. 但是,当我们把它们传递给函数时,函数可能不需要整个对象/数组,而只需要其中一部分
    1. 解构赋值 是一种特殊的语法,它使我们可以将数组或对象“拆包”至一系列变量中
    2. 解构操作对那些具有很多参数和默认值等的函数也很奏效

数组解构

  1. 将数组解构到变量中的例子:

  1. split 函数(或其他返回值为数组的函数)结合使用时,看起来更优雅:

注意

  1. “解构”并不意味着“破坏”
    1. 这种语法被叫做“解构赋值”,是因为它“拆开”了数组或对象,将其中的各元素复制给一些变量
    2. 原来的数组或对象自身没有被修改
    3. 换句话说,解构赋值只是写起来简洁一点。以下两种写法是等价的:

  1. 忽略使用逗号的元素
    1. 可以通过添加额外的逗号来丢弃数组中不想要的元素:
    2. 代码中,数组的第二个元素被跳过了,第三个元素被赋值给了 title 变量
    3. 数组中剩下的元素也都被跳过了(因为在这没有对应给它们的变量)

  1. 等号右侧可以是任何可迭代对象
    1. 实际上,我们可以将其与任何可迭代对象一起使用,而不仅限于数组:
    2. 这种情况下解构赋值是通过迭代右侧的值来完成工作的
    3. 这是一种用于对在 = 右侧的值上调用 for..of 并进行赋值的操作的语法糖

  1. 赋值给等号左侧的任何内容
    1. 可以在等号左侧使用任何“可以被赋值的”东西
    2. 例如,一个对象的属性:

  1. .entries() 方法进行循环操作
    1. 可以将 .entries() 方法与解构语法一同使用,来遍历一个对象的“键—值”对:

  1. 交换变量值的技巧
    1. 使用解构赋值来交换两个变量的值是一个著名的技巧:
    2. 创建了一个由两个变量组成的临时数组,并且立即以颠倒的顺序对其进行了解构赋值

其余的 ‘…’

  1. 通常,如果数组比左边的列表长,那么“其余”的数组项会被省略
    1. 例如,这里只取了两项,其余的就被忽略了:

  1. 如果我们还想收集其余的数组项 —— 我们可以使用三个点 "..." 来再加一个参数以获取其余数组项:
    1. rest 的值就是数组中剩下的元素组成的数组

默认值

  1. 如果数组比左边的变量列表短,这里不会出现报错。缺少对应值的变量都会被赋 undefined

  1. 如果我们想要一个“默认”值给未赋值的变量,我们可以使用 = 来提供:

  1. 默认值可以是更加复杂的表达式,甚至可以是函数调用
    1. 不过,这些表达式或函数只会在这个变量未被赋值的时候才会被计算
    2. 注意:prompt 将仅针对缺失值(surname)运行

对象解构

  1. 解构赋值同样适用于对象
    1. 在等号右侧是一个已经存在的对象,我们想把它拆分到变量中
    2. 等号左侧包含了对象相应属性的一个类对象“模式(pattern)”
    3. 在最简单的情况下,等号左侧的就是 {...} 中的变量名列表

  1. 等号左侧的模式(pattern)可以更加复杂,指定属性和变量之间的映射关系
    1. 如果我们想把一个属性赋值给另一个名字的变量,比如把 options.width 属性赋值给名为 w 的变量,那么我们可以使用冒号来设置变量名称:
    2. 冒号的语法是“从对象中什么属性的值:赋值给哪个变量”
    3. 例子中,属性 width 被赋值给了 w,属性 height 被赋值给了 h,属性 title 被赋值给了同名变量

  1. 对于可能缺失的属性,我们可以使用 "=" 设置默认值,如下所示:
    1. 就像数组或函数参数一样,默认值可以是任意表达式甚至可以是函数调用
    2. 它们只会在未提供对应的值时才会被计算/调用

  1. 还可以将冒号和等号结合起来:

  1. 如果我们有一个具有很多属性的复杂对象,那么我们可以只提取所需的内容:

剩余模式pattern

  1. 如果对象拥有的属性数量比我们提供的变量数量还多,该怎么办?
    1. 可以只取其中的某一些属性,然后把“剩余的”赋值到其他地方吗?
    2. 可以使用剩余模式(pattern),与数组类似
    3. 一些较旧的浏览器不支持此功能(例如 IE,可以使用 Babel 对其进行 polyfill),但可以在现代浏览器中使用

注意

  1. 不使用 let 时的陷阱
    1. 上面的示例中,变量都是在赋值中通过正确方式声明的:let {…} = {…}
    2. 当然,我们也可以使用已有的变量,而不用 let,但这里有一个陷阱
  2. 以下代码无法正常运行:
    1. 问题在于 JavaScript 把主代码流(即不在其他表达式中)的 {...} 当做一个代码块

  1. 这样的代码块可以用于对语句分组,如下所示:
    1. 因此,这里 JavaScript 假定我们有一个代码块,这就是报错的原因。我们需要解构它
    2. 为了告诉 JavaScript 这不是一个代码块,我们可以把整个赋值表达式用括号 (...) 包起来:

嵌套解构

  1. 如果一个对象或数组嵌套了其他的对象和数组,我们可以在等号左侧使用更复杂的模式(pattern)来提取更深层的数据
  2. 下面的代码中,options 的属性 size 是另一个对象,属性 items 是另一个数组
    1. 赋值语句中等号左侧的模式(pattern)具有相同的结构以从中提取值:

智能函数参数

  1. 有时,一个函数有很多参数,其中大部分的参数都是可选的
    1. 对用户界面来说更是如此。想象一个创建菜单的函数。它可能具有宽度参数,高度参数,标题参数和项目列表等
    2. 下面是实现这种函数的一个很不好的写法:

  1. 实际开发中,记忆如此多的参数的位置是一个很大的负担
    1. 常集成开发环境(IDE)会尽力帮助我们,特别是当代码有良好的文档注释的时候
    2. 但是…… 另一个问题就是,在大部分的参数只需采用默认值的情况下,调用这个函数时会需要写大量的 undefined
    3. 这太难看了。而且,当我们处理更多参数的时候可读性会变得很差

  1. 解构赋值可以解决这些问题
    1. 可以用一个对象来传递所有参数,而函数负责把这个对象解构成各个参数:

  1. 也可以使用带有嵌套对象和冒号映射的更加复杂的解构:
    1. 完整语法和解构赋值是一样的:
    2. 对于参数对象,属性 incomingProperty 对应的变量是 varName,默认值是 defaultValue

  1. 注意,这种解构假定了 showMenu() 函数确实存在参数
    1. 如果我们想让所有的参数都使用默认值,那我们应该传递一个空对象:
    2. 也可以通过指定空对象 {} 为整个参数对象的默认值来解决这个问题:

日期和时间

Date

  1. 该对象存储日期和时间,并提供了日期/时间的管理方法

创建

  1. 调用 new Date() 来创建一个新的 Date 对象

  1. 在调用时可以带有一些参数,如下所示:
    1. 创建一个 Date 对象,其时间等于 197011UTC+0 之后经过的毫秒数(1/1000 秒)
    2. 传入的整数参数代表的是自 1970-01-01 00:00:00 以来经过的毫秒数,该整数被称为 时间戳

  1. 01.01.1970 之前的日期带有负的时间戳,例如:

  1. 如果只有一个参数,并且是字符串,那么它会被自动解析
    1. 算法与 Date.parse 所使用的算法相同

  1. new Date(year, month, date, hours, minutes, seconds, ms)
    1. year 应该是四位数。为了兼容性,也接受 2 位数,并将其视为 19xx,例如 981998 相同,但强烈建议始终使用 4 位数
    2. month 计数从 0(一月)开始,到 11(十二月)结束
    3. date 是当月的具体某一天,如果缺失,则为默认值 1
    4. 如果 hours/minutes/seconds/ms 缺失,则均为默认值 0
    5. 时间度量最大精确到 1 毫秒(1/1000 秒):

getFullYear

  1. 获取年份(4 位数)

getMonth

  1. 月份,011

getDate

  1. 获取当月的具体日期,从 131,这个方法名称可能看起来有些令人疑惑

getHours,getMinutes,getSeconds,getMilliseconds

  1. 获取相应的时间组件

getDay

  1. 获取一周中的第几天,从 0(星期日)到 6(星期六)
  2. 第一天始终是星期日,在某些国家可能不是这样的习惯

getUTCFullYear,getUTCMonth,getUTCDay

  1. 如果你当地时区相对于 UTC 有偏移,那么下面代码会显示不同的小时数:

getTime

  1. 返回日期的时间戳 —— 从 1970-1-1 00:00:00 UTC+0 开始到现在所经过的毫秒数

getTimezoneOffset

  1. 返回 UTC 与本地时区之间的时差,以分钟为单位:

注意

  1. 不是 getYear(),而是 getFullYear()

设置日期

  1. setFullYear(year, [month\], [date])
  2. setMonth(month, [date\])
  3. setDate(date)
  4. setHours(hour, [min\], [sec], [ms])
  5. setMinutes(min, [sec\], [ms])
  6. setSeconds(sec, [ms\])
  7. setMilliseconds(ms)
  8. setTime(milliseconds)(使用自 1970-01-01 00:00:00 UTC+0 以来的毫秒数来设置整个日期)

自动校准(Autocorrection

  1. 自动校准 是 Date 对象的一个非常方便的特性。我们可以设置超范围的数值,它会自动校准

  1. 超出范围的日期组件将会被自动分配
    1. 假设我们要在日期 “28 Feb 2016” 上加 2
    2. 结果可能是 “2 Mar” 或 “1 Mar”,因为存在闰年
    3. 但是我们不需要考虑这些,只需要直接加 2 天,剩下的 Date 对象会帮我们处理:

  1. 这个特性经常被用来获取给定时间段后的日期。例如,我们想获取“现在 70 秒后”的日期:

  1. 还可以设置 0 甚至可以设置负值。例如:

日期转数字,日期差值

  1. Date 对象被转化为数字时,得到的是对应的时间戳,与使用 date.getTime() 的结果相同:

  1. 有一个重要的副作用:日期可以相减,相减的结果是以毫秒为单位时间差
    1. 这个作用可以用于时间测量:

Date.now

  1. 如果我们仅仅想要测量时间间隔,我们不需要 Date 对象
    1. 有一个特殊的方法 Date.now(),它会返回当前的时间戳
    2. 相当于 new Date().getTime(),但它不会创建中间的 Date 对象
      因此它更快,而且不会对垃圾回收造成额外的压力

基准测试(Benchmarking

  1. 在对一个很耗 CPU 性能的函数进行可靠的基准测试(Benchmarking)时,我们需要谨慎一点
    1. 例如,我们想判断以下两个计算日期差值的函数:哪个更快?
    2. 这种性能测量通常称为“基准测试(benchmark

  1. 首先想到的方法可能是连续运行两者很多次,并计算所消耗的时间之差
    1. 就这个例子而言,函数过于简单,所以我们必须执行至少 100000
    2. 看起来使用 getTime() 这种方式快得多,这是因为它没有进行类型转换,对引擎优化来说更加简单

对字符串调用 Date.parse

  1. 可以从一个字符串中读取日期
  2. 字符串的格式应该为:YYYY-MM-DDTHH:mm:ss.sssZ,其中:
    1. YYYY-MM-DD —— 日期:年-月-日
    2. 字符 "T" 是一个分隔符
    3. HH:mm:ss.sss —— 时间:小时,分钟,秒,毫秒
    4. 可选字符 'Z'+-hh:mm 格式的时区。单个字符 Z 代表 UTC+0 时区
  3. 简短形式也是可以的,比如 YYYY-MM-DDYYYY-MM,甚至可以是 YYYY
    1. Date.parse(str) 调用会解析给定格式的字符串,并返回时间戳(自 1970-01-01 00:00:00 起所经过的毫秒数)
    2. 如果给定字符串的格式不正确,则返回 NaN

  1. 可以通过时间戳来立即创建一个 new Date 对象:
    1. 通常使用 new Date(timestamp) 通过时间戳来创建日期,并可以使用 date.getTime() 将现有的 Date 对象转化为时间戳

JSON

概述

  1. 假设我们有一个复杂的对象,我们希望将其转换为字符串,以通过网络发送,或者只是为了在日志中输出它

  1. 但在开发过程中,会新增一些属性,旧的属性会被重命名和删除
    1. 每次更新这种 toString 都会非常痛苦

方法

  1. JavaScript 提供了如下方法:
    1. JSON.stringify 将对象转换为 JSON
    2. JSON.parseJSON 转换回对象

JSON.stringify

  1. 用于对象

  1. 用于原始类型
    1. Objects { ... }
    2. Arrays [ ... ]
    3. Primitives
      strings
      numbers
      boolean values true/false
      null

  1. JSON 是语言无关的纯数据规范,因此一些特定于 JavaScript 的对象属性会被 JSON.stringify 跳过

  1. 支持嵌套对象转换,并且可以自动对其进行转换

  1. 注意
    1. 不得有循环引用

排除和转换:replacer

  1. stringify语法
    1. value 要编码的值
    2. replacer 要编码的属性数组或映射函数 function(key, value)
    3. space 用于格式化的空格数量

  1. replacer

space

自定义toJSON

  1. toString 进行字符串转换,对象也可以提供 toJSON 方法来进行 JSON 转换。如果可用,JSON.stringify 会自动调用它

JSON.parse

  1. 解码 JSON 字符串

使用 reviver

  1. 想象一下,我们从服务器上获得了一个字符串化的 meetup 对象

  1. 现在我们需要对它进行 反序列(deserialize),把它转换回 JavaScript 对象
    1. meetup.date 的值是一个字符串,而不是 Date 对象
    2. JSON.parse 怎么知道应该将字符串转换为 Date

  1. 让我们将 reviver 函数传递给 JSON.parse 作为第二个参数,该函数按照“原样”返回所有值,但是 date 会变成 Date

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享