资讯专栏INFORMATION COLUMN

es6学习笔记-变量析构_v1.0_byKL

Aldous / 1763人阅读

摘要:学习笔记变量析构允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构。有一个属性用属性来获取字符串长度数值和布尔值的解构赋值解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

es6学习笔记-变量析构_v1.0

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

如果解构失败,变量的值等于undefined。

数组的解构赋值

"模式匹配",只要等号两边的模式相同,左边的变量就会被赋予对应的值。

let [a, b, c] = [1, 2, 3]; //相当于对号入座,一个萝卜一个坑

let [foo, [[bar], baz]] = [1, [[2], 3]]; //本质上也是对号入座了
console.log(foo) // 1
console.log(bar) // 2
console.log(baz) // 3

let [ , , third] = ["foo", "bar", "baz"];
console.log(third) // "baz"

let [x, , y] = [1, 2, 3]; //中间的变量空了,也自然跳过了中间的,然后直接赋值后面的
console.log(x) // 1
console.log(y) // 3

let [head, ...tail] = [1, 2, 3, 4]; //三个点号是用来扩展为一个数组序列的
console.log(head) // 1
console.log(tail) // [2, 3, 4],可以看到这里也是一个数组

let [x, y, ...z] = ["a"]; //因为其他没有值,所以都会变成undefined或者空数组,没办法对号入座
console.log(x); //a
console.log(y); // undefined
console.log(z);//[]

let [bar, foo] = [1]; //解构不成功的的值就是undefined
console.log(bar); //1
console.log(foo); // undefined

扩展运算符( spread )是三个点(...)。它好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列,即把数组或类数组对象展开成一系列用逗号隔开的值,看解释以为是变成了值,其实不然,看输出就知道,其实也是一个数组

事实上,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。

function * fibs() { //函数有* 是因为他是一个Generator,暂时忽略
    let a = 0;
    let b = 1;
    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

let [first, second, third, fourth, fifth, sixth] = fibs();
console.log(sixth) // 5

fibs是一个 Generator 函数(参见《Generator 函数》一章),原生具有 Iterator 接口。解构赋值会依次从这个接口获取值。

其实在这里只要大概理解他们的数据结构差不多是上面那种类型的时候,就能时候数组结构方式

数组解构默认值

默认值,主要是看左边是否能取到右边的值

let [foo = true] = []; //空数组,触发默认值
console.log(foo) // true

let [x, y = "b"] = ["a"]; //因为少了一个值,所以也触发默认值
console.log(x);
console.log(y);// x="a", y="b"

let [x, y = "b"] = ["a", undefined]; //这里也触发了,即使是undefined的值
console.log(x);
console.log(y);// x="a", y="b"

let [x = 1] = [undefined];
console.log(x) // 1

let [y = 1] = [null]; //正如下面提到,数组成员null的不触发默认值
console.log(y) // null

function f() {
    console.log("aaa");
}
//这里主要是看x能取值,右边的值是很正常能取到的,所以不会触发默认值
let [x = f()] = [1]; 
console.log(x);//1

let [x = 1, y = x] = [];//因为没有值,所以触发默认值,然后x先于y声明,所以y也可以使用x的值
console.log(x)
console.log(y)// x=1; y=1

let [x = 1, y = x] = [2]; //因为有值,并且能对应到x,并且先于y声明
console.log(x)
console.log(y)// x=2; y=2

let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError

ES6 内部使用严格相等运算符(===),判断一个位置是否有值。

如果一个数组成员是null,默认值就不会生效,因为null不严格等于undefined。

对象的解构赋值

对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

如果变量名与属性名不一致,需要利用原来的属性(键)来中转,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。

let { bar, foo } = { foo: "aaa", bar: "bbb" };
console.log(foo) // "aaa"
console.log(bar) // "bbb"
console.log(baz) // undefined,并且报错,这里没对应上对象的键,所以没有取到值

let obj = { first: "hello", last: "world" };
let { first: f, last: l } = obj; //这里的first就是原来的属性,现在要提取值到新的变量f,要这样写
console.log(f) // "hello"
console.log(l) // "world"

let obj = {
    p: [ //真正对应的是p里面的东西,因为下面p只是作为模式使用
        "Hello", //对应x
        { y: "World" } //对应{y}
    ]
};

let { p: [x, { y }] } = obj; //这里需要注意,p是模式,因为有冒号,而且位于左边
console.log(x) // "Hello"
console.log(y) // "World"
console.log(p) // p is not defined,这里p没有定义


let obj = {};
let arr = [];
//对于obj,这里直接对应的是obj的属性prop,而bar是对应arr的第一个元素的值
({ foo: obj.prop, bar: arr[0] } = { foo: 123, bar: true });
//很方便的直接赋值给对象属性和数组的元素的值
console.log(obj) // {prop:123}
console.log(arr) // [true],因为这个数组只有一个值
对象解构的默认值

大部分情况跟数组的结构默认值类似,也是通过判断是否undefined

let {x = 3} = {}; 
console.log(x) // 3

let {x, y = 5} = {x: 1};
console.log(x) // 1
console.log(y) // 5

//如果解构模式是嵌套的对象,而且子对象所在的父属性不存在,那么将会报错。
//等号左边对象的foo属性,对应一个子对象。该子对象的bar属性,解构时会报错。
//因为foo这时等于undefined,(没有对象然后直接去对象属性)再取子属性就会报错,请看下面的代码。
let {foo: {bar}} = {baz: "baz"};// 报错
对象的结构的方便用法

对象的解构赋值,可以很方便地将现有对象的方法,赋值到某个变量。

let { log, sin, cos } = Math; //这里直接使用了log和sin方法了
console.log(log(10));//2.302585092994046
console.log(sin(10));//-0.5440211108893698

对数组进行对象属性结构

let arr = [1, 2, 3];
//并且能够使用数组的基本数字键来做匹配,0,1,2的数组索引数字键
let {0 : first, [arr.length - 1] : last} = arr; //这里支持一些方法,例如length,需要用[]括起来
console.log(first) // 1
console.log(last) // 3
字符串的结构赋值

字符串被转换成了一个类似数组的对象。

有一个length属性

const [a, b, c, d, e] = "hello";
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = "hello"; //用length属性来获取字符串长度
len // 5
数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值和布尔值,则会先转为对象。

数值和布尔值的包装对象都有toString属性

let {toString: s} = 123;
//全等证明有这个toString属性
console.log(s === Number.prototype.toString )// true
console.log(s) //[Function: toString]

let {toString: s} = true;
console.log(s === Boolean.prototype.toString) // true
console.log(s) //[Function: toString]
函数参数的解构赋值
function add([x, y]){ //直接解析参数,相当于传参(x,y)
    return x + y;
}
console.log(add([1, 2])); // 3

//这里需要拆开来看
let test = [[1, 2], [3, 4]].map(([a, b]) => a + b);
console.log(test) // [ 3, 7 ]

[//这里只是普通的嵌套数组
    [1, 2], //每个子数组元素都是一个数组
    [3, 4] 
].map(//对他们使用map函数
    //这里传入了一个函数,并且参数是自动解析参数数组的,相当于每次处理都是一整个子数组
    ([a, b]) => a + b //并且因为能够对应得到析构模式,所以直接解析这个子数组
);
函数参数的解构的默认值

undefined就会触发函数参数的默认值

可以当做一个对象析构来看,只是这个对象是被放到函数参数里面去而已

//这里是为变量x,y指定默认值
function move({x = 0, y = 0} = {}) { 
    return [x, y];
}

console.log(move({x: 3, y: 8})); // [3, 8]
//参数对象的y析构失败,所以是0,而x成功,所以能够使用新的值
console.log(move({x: 3})); // [3, 0]
//参数对象析构都失败,因为是空对象
console.log(move({})); // [0, 0]
//参数对象析构都失败,因为什么都没有
console.log(move()); // [0, 0]


//这里是为函数move的参数指定默认值,而不是为变量x和y指定默认值
function move({x, y} = { x: 0, y: 0 }) {
    return [x, y];
}

console.log(move({x: 3, y: 8})); // [3, 8]
//因为y析构失败,所以y是undefined,但是没有触发外面参数对象的undefined,所以直接返回x,y的值
console.log(move({x: 3})); // [3, undefined]
//因为传入的是空对象,也不算是undefined,没触发到默认值,所以直接返回x,y的值
console.log(move({})); // [undefined, undefined]
//触发到默认值了,因为什么都没有传,被判定为参数对象的undefined
console.log(move()); // [0, 0]
变量析构的一些使用情况

交换变量的值

主要是为了简洁,易读

let x = 1;
let y = 2;

[x, y] = [y, x]; //交换变量x和y的值

从函数返回多个值

函数只能返回一个值,如果要返回多个值,只能将它们放在数组或对象里返回,所以需要从里面取出来

// 返回一个数组
function example() {
    return [1, 2, 3];
}
let [a, b, c] = example();//直接取出数组内容,赋值到变量或者数组
console.log([a, b, c]); //[ 1, 2, 3 ]

// 返回一个对象
function example1() {
    return {
        foo: 1,
        bar: 2
    };
}
let { foo, bar } = example1();//直接取出对象内容
console.log({ foo, bar }) //{ foo: 1, bar: 2 }

函数参数的定义

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

// 参数是一组有次序的值
function f([x, y, z]) { ... }//这个其实跟普通传参差不多
f([1, 2, 3]);

// 参数是一组无次序的值
function f({x, y, z}) { ... } //这里传参是用对象的方式就比较方便指定对象属性
f({z: 3, y: 2, x: 1});

提取JSON数据

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

let jsonData = {
    id: 42,
    status: "OK",
    data: [867, 5309]
};
//其实json对象也是对象,所以直接能够解析对象的方便性也体现在这里
let { id, status, data: number } = jsonData;

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

函数参数的默认值

指定参数的默认值,就避免了在函数体内部再写var foo = config.foo || "default foo";这样的语句。

jQuery.ajax = function (url, {
  async = true, //默认值
  beforeSend = function () {}, //默认值
  cache = true, //默认值
  complete = function () {}, //默认值
  crossDomain = false, //默认值
  global = true, //默认值
  // ... more config
}) {
  // ... do stuff
};

遍历Map结构

任何部署了Iterator接口的对象,都可以用for...of循环遍历。Map结构原生支持Iterator接口,配合变量的解构赋值,获取键名和键值就非常方便。

var map = new Map(); //map结构
map.set("first", "hello");//map结构的数据格式,本质上也是key/value的hash,first是key,hello是value
map.set("second", "world");
//直接解析键值
for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。参考地址

输入模块的指定方法

加载模块时,往往需要指定输入哪些方法。解构赋值使得输入语句非常清晰。

const { SourceMapConsumer, SourceNode } = require("source-map");

参考引用:

es6-变量的解构赋值

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86824.html

相关文章

  • es6学习笔记-顶层对象_v1.0_byKL

    摘要:学习笔记顶层对象虽然是笔记但是基本是抄了一次大师的文章了顶层对象顶层对象,在浏览器环境指的是对象,在指的是对象。之中,顶层对象的属性与全局变量是等价的。的写法模块的写法上面代码将顶层对象放入变量。参考引用顶层对象实战 es6学习笔记-顶层对象_v1.0 (虽然是笔记,但是基本是抄了一次ruan大师的文章了) 顶层对象 顶层对象,在浏览器环境指的是window对象,在Node指的是gl...

    Meils 评论0 收藏0
  • es6学习笔记-let,const和块级作用域_v1.0_byKL

    摘要:考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。函数声明语句函数表达式循环循环还有一个特别之处,就是循环语句部分是一个父作用域,而循环体内部是一个单独的子作用域。声明一个只读的常量。 es6学习笔记-let,const和块级作用域_v1.0 块级作用域 javascript 原来是没有块级作用域的,只有全局作用域和函数作用域 例子1 因为没有块级作用域,所以每次的i都是一...

    Youngdze 评论0 收藏0
  • es6学习笔记-箭头函数_v1.0_byKL

    摘要:因为箭头函数本身没有所以不可以当作构造函数,也就是说,不可以使用命令,否则会抛出一个错误。箭头函数不可以使用对象,该对象在函数体内不存在。 es6学习笔记-箭头函数_v1.0 箭头函数使用方法 var f = v => v; //普通函数配合箭头函数写法,这里并且是传参的 //相当于 var f = function(v) { return v; }; /*-----------...

    lushan 评论0 收藏0
  • es6学习笔记-字符串模板_v1.0_byKL

    摘要:学习笔记字符串模板实例模板编译先组成一个模板使用放置代码使用输出表达式。这被称为标签模板功能。该数组的成员与数组完全一致参考引用字符串扩展 es6学习笔记-字符串模板_v1.0 实例:模板编译 //先组成一个模板 var template = ` //使用放置JavaScript代码 //使用输出JavaScript表达式。 `; //这是编译模板的函数,将模...

    xiongzenghui 评论0 收藏0
  • es6学习笔记-函数扩展_v1.0_byKL

    摘要:学习笔记函数扩展函数参数的默认值如果参数默认值是变量,那么参数就不是传值的,而是每次都重新计算默认值表达式的值。属性函数的属性,返回该函数的函数名。箭头函数详细链接参考引用函数扩展 es6学习笔记-函数扩展_v1.0 函数参数的默认值 function Point(x = 0, y = 0) { this.x = x; this.y = y; } var p = ne...

    yuanzhanghu 评论0 收藏0

发表评论

0条评论

Aldous

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<