JS ES新特性之变量的解耦赋值

目录
  • 1.数组的解耦赋值
    • 1.1数组解耦赋值是什么
    • 1.2数组解耦赋值失败
    • 1.3不完全解耦赋值
    • 1.4默认值
    • 1.5数组解耦赋值的复杂情况
  • 2.对象的解耦赋值
    • 2.1对象解耦赋值的特殊情况
    • 2.2解耦赋值失败
    • 2.3不完全解耦赋值
    • 2.4默认值
  • 3.字符串、数值、和布尔值的解耦赋值
    • 3.1字符串解耦赋值
    • 3.2数值和布尔值的解耦赋值
  • 4.函数的解耦赋值
  • 5.小括号的问题
    • 5.1不能使用小括号的情况
    • 5.2可以使用小括号的情况
  • 6.变量解耦赋值的用处
    • 6.1交换变量的值
    • 6.2从函数返回多个值
    • 6.3函数参数的定义
    • 6.4提取 JSON 数据

1.数组的解耦赋值

1.1数组解耦赋值是什么

ECMAScript 2015中允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为 解耦赋值 。

在ECMAScript 2015之前中为变量赋值的方式如下所示:

let a = 1;
let b = 2;
let c = 3;

在ECMAScript 2015允许写成下面这样。

let [a, b, c] = [1, 2, 3];

ECMAScript 2015的解耦赋值本质上属于模式匹配。赋值运算符两边的模式相同,左边的变量会被赋予对应位置的值。

1.2数组解耦赋值失败

如果解耦赋值失败的话,变量的值等于 undefined。示例代码如下所示:

// 如果数组的某个索引值的位置的变量,在 = 运算符的右边没有数组中没有对应的索引值与之对应,则解耦赋值失败,其值为 undefined
let [v] = []
let [a, b] = [1]
console.log(v, a, b); // undefined 1, undefined

如果想解决解耦赋值失败的问题,需要将其赋值运算符的左右两边的数量保持一致。

1.3不完全解耦赋值

所谓的不完全解耦赋值就是指赋值运算符的右边数组中的数量要大于左边数组中的数量,导致右边数组中的有些变量失效,但是这这种情况下解耦赋值还是会成功的。

示例代码如下所示:

// 赋值运算符左边变量的数量小于右边值的数量
let [a, b, c] = [1, 2, 3, 4]  // 依然会解耦赋值成功
console.log(a, b, c); // 1 2 3

1.4默认值

解耦赋值允许指定默认值的。示例代码如下所示:

/*
 * 解耦赋值中允许指定默认值
 * 语法结构如下
 * let [var1 = value1, var2 = value2 ,...] = [val1, val2,...]
   var1,var2 表示变量名
   value1,value2 表示默认值
   val1,val2, 表示指定的值
 */
let [a = 1, b = 2] = [100]
console.log(a, b); // 100 2

在使用默认值的时候值得注意的一点就是,ECMAScript6 内部会使用全等于 === 运算符来判断指定位置的值是否全等于undefined。只有当 全等于undefined时,其默认值才会生效。

测试代码如下所示:

let [a = 1, b = 2] = [100, undefined]
console.log(a, b); // 100 2

当我们使用null值时,虽然null也表示为空,但是null !== undefined。所以我们的默认值并不会生效,

测试代码如下:

let [a = 1, b = 2] = [100, null]
console.log(a, b); // 100 null

1.5数组解耦赋值的复杂情况

由于JavaScript是一个弱类型的语言,所以赋值号右边是什么类型都是允许的,那就会出现以下几种特殊情况:

情况一:运算符右边是一个函数,示例代码如下

// 1. 运算符右边是一个函数
let [a, b] = [1, function () {
  return 10;
}]
console.log(b()); // 10

情况二:运算符右边是一个对象,示例代码如下

// 2. 运算符右边是一个对象
let [a, b] = [1, {
  name: '狐妖小红娘'
}]
console.log(b); // { name: '狐妖小红娘' }

情况三:运算符右边函数数组,示例代码如下

// 3. 运算符右边是含有数组
let [a, b] = [1, [2, 3]]
console.log(b); // [ 2, 3 ]

情况四:运算符左右两边都含有数组,示例代码如下所示

// 4. 运算符左右两边都含有数组,示例代码如下所示
let [a, [b, c]] = [1, [2, 3]]
console.log(b); // 2

2.对象的解耦赋值

对象的解耦赋值是通过变量名称实现与对象的属性名称一一对应实现的。示例代码如下所示:

/*
  * 对象的解耦赋值 - 从对象中提取值,为变量赋值
    ! 变量名称必须与对象的属性名称一一对应,否则就会导致失败。
*/
let {
  x,
  y
} = {
  x: 10,
  y: 20
}
console.log(x, y); //10 20

值得注意的是赋值运算符两边的格式需要保持一致。

2.1对象解耦赋值的特殊情况

由于 JavaScript 是一个弱类型的语言,所以赋值号右边是什么类型都是允许的,那就会出现以下几种特殊情况

情况一:运算符右边是一个函数,示例代码如下

// 1. 运算符右边是一个函数
let { a, b } = {
  a: 1,
  b: function () {
    return 10;
  }
}
console.log(b());// 10

情况二:运算符右边是一个对象,示例代码如下

// 2. 运算符右边是一个对象
let {a, b} = {
  a: 1,
  b: {
    name: 'ywanzhou'
  }
}
console.log(b); // { name: 'ywanzhou' }

情况三:运算符右边函数数组,示例代码如下

// 3. 运算符右边是含有数组
let {a, b} = {
  a: 1,
  b: [1, 2]
}
console.log(b); //[ 1, 2 ]

情况四:运算符左右两边都含有对象,示例代码如下所示

// 4. 运算符左右两边都含有对象
let {
  m: {
    name,
    age
  },
  n
} = {
  m: {
    name: 'test',
    age: 20
  },
  n: 20
}
console.log(name, age); // test 20

2.2解耦赋值失败

如果解耦赋值失败的话,变量的值等于undefined。示例代码如下所示:

// 解耦赋值失败
let {
  a,
  b
} = {
  a: 10
}
console.log(b);

2.3不完全解耦赋值

所谓的不完全解耦赋值就是指赋值运算符的右边对象中属性的数量要大于左边对象中属性的数量,导致右边对象中属性的有些变量失效,但是这这种情况下解耦赋值还是会成功的。

// 不完全解耦赋值
let {
  a
} = {
  a: 10,
  b: 20
}
console.log(a);

2.4默认值

解耦赋值允许指定默认值的。示例代码如下所示:

// 默认值
let {
  a,
  b = 100
} = {
  a: 10,
  b: 20
}
console.log(b);

3.字符串、数值、和布尔值的解耦赋值

3.1字符串解耦赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

let [h1, y, x] = "一碗周"
console.log(h1, y, x, h2); // 一 碗 周

3.2数值和布尔值的解耦赋值

如果直接对数字值/布尔值进行解耦赋值会抛出异常,在对数字值和布尔值进行操作时,其赋值运算符的右边是数值和布尔值,则会先转为对象。

// let [a] = 100; // 抛出异常 描述信息为 TypeError: 100 is not iterable
// console.log(a);
// 对布尔或者数值进行解耦赋值的话, 需要现将其改变成为对象类型。
let {
  toString: b
} = 1;
console.log(b === Number.prototype.toString); // true

let {
  toString: c
} = true;
console.log(c === Boolean.prototype.toString); // true

解构赋值的规则是,只要等号右边的值不是对象或数组,就先将其转为对象。由于undefinednull无法转为对象,所以对它们进行解构赋值,都会报错。

4.函数的解耦赋值

函数的参数也可以使用解构赋值。示例代码如下所示:

// 使用数组
function f([a, b]) {
  console.log(a, b);
}
f([10, 20]) // 10 20
// 使用对象
function fn({
  a,
  b
}) {
  console.log(a, b);
}
fn({
  a: 10,
  b: 20
})  // 10 20

5.小括号的问题

解耦赋值虽然很方便,但是解析起来并不容易。对于编译器来说,一个式子到底是模式,还是表达式,没有办法从一开始就知道,必须解析到(或解析不到)等号才能知道。

由此带来的问题是,如果模式中出现小括号怎么处理。ECMAScript 2015的规则是,只要有可能导致解构的歧义,就不得使用小括号。

但是,这条规则实际上不那么容易辨别,处理起来相当麻烦。因此,建议只要有可能,就不要在模式中放置小括号。

5.1不能使用小括号的情况

如下三种情况不能使用小括号

情况一:变量声明语句,示例代码如下所示

// 如下情况全部会报错
let [(a)] = [1];

let {x: (c)} = {};
let ({x: c}) = {};
let {(x: c)} = {};
let {(x): c} = {};

let { o: ({ p: p }) } = { o: { p: 2 } };

上面6个语句都会报错,因为它们都是变量声明语句,模式不能使用小括号。

情况二:作为函数参数

函数参数也属于变量声明,因此不能带有小括号。

// 报错
function f([(z)]) { return z; }
// 报错
function f([z,(x)]) { return x; }

情况三:赋值语句的模式

// 全部报错
({ p: a }) = { p: 42 };
([a]) = [5];

上面代码将整个模式放在小括号之中,导致报错。

// 报错
[({ p: a }), { x: c }] = [{}, {}];

上面代码将一部分模式放在小括号之中,导致报错。

5.2可以使用小括号的情况

可以使用小括号的情况只有一种:赋值语句的非模式部分,可以使用小括号。

[(b)] = [3]; // 正确
({ p: (d) } = {}); // 正确
[(parseInt.prop)] = [3]; // 正确

上面三行语句都可以正确执行,因为首先它们都是赋值语句,而不是声明语句;其次它们的小括号都不属于模式的一部分。第一行语句中,模式是取数组的第一个成员,跟小括号无关;第二行语句中,模式是p,而不是d;第三行语句与第一行语句的性质一致。

6.变量解耦赋值的用处

变量解耦赋值的用处有很多,下面举几个比较常见的例子。

6.1交换变量的值

如果没有解耦赋值交换变量需要借助第三个变量才能完成,示例代码如下所示:

var a = 10,
  b = 20;

var c = a;
a = b
b = c
c = null  /// 释放变量
console.log(a, b); // 20 10

借助变量解耦赋值完成 ,示例代码如下所示:

let a = 10,
  b = 20;
[a, b] = [b, a]
console.log(a, b); // 20 10

使用这种方式不仅简洁,而且易读,语义清晰。

6.2从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回。有了解构赋值,取出这些值就非常方便。

示例代码如下所示:

// 返回一个数组

function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();

6.3函数参数的定义

解构赋值可以方便地将一组参数与变量名对应起来。

// 参数是一组有次序的值
function f([x, y, z]) {
  console.log(x, y, z);
}
f([1, 2, 3]);  // 1 2 3

// 参数是一组无次序的值
function fn({x,  y,  z}) {
  console.log(x, y, z);
}
fn({
  z: 3,
  y: 2,
  x: 1
});  // 1 2 3

6.4提取 JSON 数据

解构赋值对提取 JSON 对象中的数据,尤其有用。

// 提取json数据
let jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
};

let {
  id,
  status,
  data: number
} = jsonData;

console.log(id, status, number); // 42, "OK", [867, 5309]

到此这篇关于JS ES新特性之变量的解耦赋值的文章就介绍到这了,更多相关ES变量的解耦赋值内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • JavaScript高级程序设计之变量与作用域

    目录 1.原始值与引用值 2.instanceof 3.作用域 1.原始值与引用值 6种简单数据类型的值都是原始值, 原始值通过变量赋值给另一个变量时,会复制一个出一个新的值,两者相互独立. let num1 = 5 let num2 = num1 引用值通过变量赋值给另一个变量时,也会复制一个值,这个值其实是一个指针(引用),该指针指向的还是同一个对象. let obj1 = new Object() let obj2 = obj1 既然是指向同一个引用对象,那么给obj1添加属性,也会作用到

  • JavaScript基础之变量

    目录 1.变量概述 1.1变量在内存中的存储 1.2 变量的使用 1.声明变量 2.赋值 3.变量的初始化 1.3变量语法扩展 1.更新变量 2.声明多个变量 3.声明变量特殊情况 1.5变量命名规范 总结 1.变量概述 1.1变量在内存中的存储 本质:变量是程序在内存中申请的一块用来存放数据的空间 1.2 变量的使用 变量的使用分为两步 :1.声明变量 2.赋值 1.声明变量 //声明变量 var age; //声明一个名称为age的变量 var是一个JS关键字,用来声明变量(variable

  • JS ES新特性之变量的解耦赋值

    目录 1.数组的解耦赋值 1.1数组解耦赋值是什么 1.2数组解耦赋值失败 1.3不完全解耦赋值 1.4默认值 1.5数组解耦赋值的复杂情况 2.对象的解耦赋值 2.1对象解耦赋值的特殊情况 2.2解耦赋值失败 2.3不完全解耦赋值 2.4默认值 3.字符串.数值.和布尔值的解耦赋值 3.1字符串解耦赋值 3.2数值和布尔值的解耦赋值 4.函数的解耦赋值 5.小括号的问题 5.1不能使用小括号的情况 5.2可以使用小括号的情况 6.变量解耦赋值的用处 6.1交换变量的值 6.2从函数返回多个值

  • JS ES新特性 模板字符串

    目录 1.模板字符串是什么 2.多行模板字符串 2.1带表达式的模板字符串 3.带标签的模板字符串 4.原始字符串 5.判断是否包含某字符串 5.1includes()方法 5.2startsWith()方法 5.3endsWith()方法 1.模板字符串是什么 模板字符串( Template String )是增强版的字符串,使用反引号(```)来代替谱通字符串中的用双引号和单引号.它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量. 普通用法如下所示: // 使用 `

  • JS ES新特性 扩展运算符介绍

    一.扩展运算符 扩展运算符是三个点... , 允许将一个表达式原地展开,当需要多个参数(比如函数的调用时) 或者多个值(比如数组)它会将其转为用逗号分隔的参数序列. 示例代码如下所示: // 定义一个数组 let arr = [1, 2, 3, 4, 5, 6] // 使用 ... 扩展运算符展开 console.log(...arr); // 1 2 3 4 5 6 // 定义一个函数 function fun(...item) { console.log(...item); } // 调用函

  • ES6新特性之变量和字符串用法示例

    本文实例讲述了ES6新特性之变量和字符串用法.分享给大家供大家参考,具体如下: 一.变量 1. LET 我们都习惯用var 来声明变量,现在还可以用let来声明变量,两者的主要区别是作用域:var声明的变量作用域为包围它的函数,而let声明的变量作用域仅在它所在的块中.(在ES5中是没有块的概念的). if(true){ let a=1; } console.log(a);//undifined 这样使代码更加干净,减少滞留的变量,再如我们经常用的数组遍历: for(let i=0;i<list

  • 基于JavaScript ES新特性let与const关键字

    目录 1.let关键字 1.1基本用法 1.2不存在变量提升 1.3暂时性死区 1.4不允许重复声明 1.5与函数的关系 2.const关键字 2.1基础用法 1.let关键字 1.1基本用法 let是ECMAScript 2015新增的一个关键字,用于声明变量,其用法类似于var,与之不同的是声明的变量只能在所在的代码块中使用. 语法结构如下所示: let var1 [= value1] [, var2 [= value2]] [, ..., varN [= valueN]]; 参数说明: v

  • JavaScript ES新特性块级作用域

    目录 1.块级作用域是什么 2.为什么需要块级作用域 3.与函数声明 前言: 在学习块级作用域之前需要我们对作用域有个了解,所谓的作用域就是代码当中的某个成员起作用的范围. 1.块级作用域是什么 所谓的块级作用域,就是该变量只能在声明时的代码块或者子代码块中使用.在ECMAScript 2015以前的版本中是不存在块级作用域的,而ECMAScript 2015提供的let关键字,使JavaScript出现了块级作用域,示例代码如下所示 /* * 块级作用域只能使用 let 关键字 * let关键

  • ES6新特性四:变量的解构赋值实例

    本文实例讲述了ES6新特性之变量的解构赋值.分享给大家供大家参考,具体如下: 1. 数组的解构赋值 //① 可以从数组中提取值,按照对应位置,对变量赋值 var [a, b] = [1, 2]; //a = 1;b = 2 //② 下面是一些使用嵌套数组进行解构 var [d, [[c], f]] = [1, [[2], 3]]; var [,,third] = ["foo", "bar", "baz"];//third = "baz&

  • JavaScript ECMAScript 6(ES2015~ES2022)所有新特性总结

    目录 前言 ES2015(ES6) let.const关键字和块级作用域 函数的扩展 数值的扩展 字符串的扩展 数组的扩展 对象的扩展 类 模块化 解构赋值 Symbol Promise Iterator Generator Proxy和Reffect Set.Map.WeakSet.WeakMap ES2016(ES7) 指数运算符 Array.prototype.includes()方法 ES2017(ES8) async/await语法糖 Atomics对象 对象扩展 函数扩展 字符串扩展

  • JDK10新特性之var泛型和多个接口实现方法

    简介 在JDK10的新特性:本地变量类型var中我们讲到了为什么使用var和怎么使用var. 今天我们来深入的考虑一下var和泛型,多个接口实现的问题. 实现多个接口 在JDK的实现和我们日常的工作中,很多时候都需要实现多个接口,我们举常用的两个例子ArrayList和CopyOnWriteArrayList.先看下他们的定义: public class ArrayList<E> extends AbstractList<E> implements List<E>, R

  • Vue.js 2.5新特性介绍(推荐)

    TypeScript TypeScript是一种由微软开发的自由和开源的编程语言.它是JavaScript的一个超集,而且本质上向这个语言添加了可选的静态类型和基于类的面向对象编程.2012年十月份,微软发布了首个公开版本的TypeScript,在2013年6月19日,微软发布了TypeScript 0.9的正式版本,到目前为止,TypeScript已发展到2.x版本 安装TypeScript 安装TypeScript主要有两种方式: 通过npm方式安装(Node.js包管理器) 安装TypeS

随机推荐