变量的解构赋值

标签: ES6


  • ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值
  • 本质上属于“模式匹配”,只要等号两边模式相同,左边的变量就会被赋予相应的值

数组的解构赋值

基本用法

var [a, b, c] = [1, 2, 3]
a   // 1
b   // 2
c   // 3
  • 解构不成功,则解构不成功的变量的值为undefined
  • 不完全解构,即等号左边的模式只匹配等号右边数组的一部分,则解构依然成功
let [x, y] = [1, 2, 3]
x   // 1
y   // 2

对于数组解构赋值,如果等式右边不是可遍历结构(本身 / 转化后的对象具备Iterator接口),将会报错

// 报错,转化后的对象不具备Iterator接口
let [a] = 1
let [b] = false
// 报错,对象本身不具备Iterator接口
let [c] = {}        
// 解构成功,字符串能转换成类似数组的对象
let [d, e, f, g, h] = 'hello'

默认值

  • 解构允许指定默认值
var [x, y = 2] = [1]    // x=1,y=2
  • 使用严格相等运算符(===)判断一个位置是否有值,仅在严格等于undefined时,默认值生效
var [x = 1] = [undefined]   // x=1
var [y = 1] = [null]        // y=null,默认值不生效
由于`(null===undefined)`的值为false,所以默认值不生效,`y`的值为null
  • 如果默认值为一个表达式,那么这个表达式是惰性求值的,只有用到的时候才会求值
function f() {
    console.log(123)
}
let [x = f()] = [1]     // 无输出
  • 默认值可以引用解构赋值的其他变量,但该变量必须已经声明
let [x = 1, y = x] = []     // x=1,y=1
let [a = b, b = 1] = []     // 报错

对象的解构赋值

基本用法

var { foo, bar } = { foo: 123, bar: 345 }
foo // 123
bar // 345
  • 数组解构,变量的取值取决于它的位置
  • 对象解构,变量必须与属性同名,才能得到正确的值
var { abc } = { foo: 123, bar: 345 }
abc // undefined

对象的解构赋值实际上是以下形式的简写

var { foo, bar } = { foo: 123, bar: 345 }   // 简写
var { foo: foo, bar: bar } = { foo: 123, bar: 345 }

对象解构赋值的内部机制,是先找到同名属性,然后再赋给相应的变量。
真正被赋值的是后者,而不是前者

var { foo: baz } = { foo: 123, bar: 345 }
baz // 123
foo // Error:foo is not defined

对一个已经声明的变量解构赋值,不能将大括号 { } 写在行首,避免 javascript 将其解析为代码块

var x
({ x } = { x: 1 })  // 正确写法
{ x } = { x: 1 }    // 错误写法

默认值

默认值生效的条件是,对象的属性严格等于undefined

var { message: msg = 123, x } = { message: undefined, x: null }
msg     // 123
x       // null

解构嵌套结构的对象

var node = {
    loc: {
        start: {
            line: 1,
            column: 5
        }
    }
}
var { loc: { start: { line, column } } } = node
line    // 1
column  // 5
loc     // Error
start   // Error

注意:loc 和 start 是模式,不是变量,因此不会被赋值

解构对象是嵌套的对象,而且子对象所在的父对象不存在,会报错

var { foo: { bar } } = {}

foo为父对象,bar为子对象,foo不存在,报错
原因很简单:foo这时为undefined,再取子属性bar就会报错

其他类型的解构赋值

字符串的解构赋值

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

let [d, e, f, g, h] = 'hello'
var { length: len } = 'hello'
len     // 5

数值和布尔值的解构赋值

解构赋值时,如果等号右边是数值或布尔值,则先转为对象
undefinednull无法转为对象,会报错

let { toString: s } = 123
s === Number.prototype.toString     // true
let { toString: s } = true
s === Boolean.prototype.toString    // true

函数参数的解构赋值

function add([x, y]) {
    return x + y
}
add([1, 2])     // 3

注意区分以下两种情况:

function move({ x = 0, y = 0 } = {}) {
    return [x, y]
}
move({ x: 3, y: 1 })    // { x: 3, y: 1 }
move({ x: 3})           // { x: 3, y: 0 }
move({})                // { x: 0, y: 0 }
move()                  // { x: 0, y: 0 }

为解构设置默认值,当解构失败时使用默认值
move()使用了函数默认值{},然后解构,解构失败,使用解构默认值

function move({} = { x = 0, y = 0 }) {
    return [x, y]
}
move({ x: 3, y: 1 })    // { x: 3, y: 1 }
move({ x: 3})           // { x: 3, y: undefined }
move({})                // { x: undefined, y: undefined }
move()                  // { x: 0, y: 0 }

为函数设置默认值,仅当函数没有传参的时候才使用默认值
move({})传入了空对象,所以没有使用函数默认值{},接下来是解构,解构失败,由于没有解构默认值,其值为undefined

变量解构的用途

交换变量的值

[x, y] = [y, x]

从函数返回多个值

function example() {
    return [1, 2, 3]
}
var [a, b, c] = example()
function example() {
    return {
        foo: 1,
        bar: 2
    }
}
var { foo, bar } = example()

函数参数的定义

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

提取JSON数据

var jsonData = {
    id: 1,
    is_error: false,
    result: [123, 456]
}
let { id, is_error, result } = jsonData

函数参数的默认值

jQuery.ajax = function(url, {
    async = true,
    beforeSend = function() {},
    cache = true,
    complete = function() {},
    corssDomain = false,
    global = true
    // ... more config
}) {
    // ... do stuff
}

遍历Map结构

任何部署了 Iterator接口的对象,都可以用 for...of 循环遍历

var map = new Map()
map.set('first', 'hello')
map.set('second', 'world')
for (let [key, value] of map) {
    console.log(key, value)
}
// first hello
// second world

输出模块的指定方法

const { SourceMapConsumer, SourceNode } = require("source-map")
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,793评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,567评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,342评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,825评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,814评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,680评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,033评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,687评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,175评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,668评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,775评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,419评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,020评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,206评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,092评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,510评论 2 343

推荐阅读更多精彩内容