解构赋值(Destructuring Assignment)是一个在ES6的新特性,用于提取(extract)阵列或物件中的资料,这是一种对原本语法在使用上的改进,过去要作这件事可能需要使用回圈或迭代的语句才行,新语法可以让程式码在撰写时更为简短与提高阅读性。
解构赋值的解说只有一小段英文:
The destructuring assignment syntax is a JavaScript expression that makes it possible to extract data from arrays or objects using a syntax that mirrors the construction of array and object literals.
这句后面的mirrors the construction of array and object literals,代表这个语法的使用方式- 如同"镜子"一般,对映出阵列或物件字面的结构。也就是一种样式(pattern)对映的语法。
解构赋值如果你能抓得住它的基本概念,就可以很容易理解与使用。不过与ES6其他的特性配合时,会显得复杂比较难理解。
在使用时有以下几种常见的情况:
destructuring: 变性、破坏性。使用"解构"是对照de-字头有"脱离"、"去除"的意思。assignment: 赋值、指派。赋值通常指的是程式中使用等号(=)运算符的语句。
从阵列解构赋值没太多学问,唯一比较特别的是可以用其余运算符(Rest Operator)的语法,既然是其余运算符,最后就会把其余的对应值集合成一个阵列之中。下面是几个几个范例:
//基本用法
const [a, b] = [1, 2] //a=1, b=2
//先宣告後指定值,要用let才行
let a, b
[a, b] = [1, 2]
// 略過某些值
const [a, , b] = [1, 2, 3] // a=1, b=3
// 其餘運算
const [a, ...b] = [1, 2, 3] //a=1, b=[2,3]
// 失敗保護
const [, , , a, b] = [1, 2, 3] // a=undefined, b=undefined
// 交換值
const a = 1, b = 2;
[b, a] = [a, b] //a=2, b=1
// 多維複雜陣列
const [a, [b, [c, d]]] = [1, [2, [[[3, 4], 5], 6]]]
// 字串
const str = "hello";
const [a, b, c, d, e] = str
用法就是这么简单,用来赋值的等号符号(=)左边按照你写的变数或常数样式,然后在右边写上要对映数值,就像之前说的"镜子"般的对应。当没有对应的值时,就会得到undefined。
物件除了有使用特别的字面符号,也就是花括号({})来定义,其中也会包含属性。按照基本的原则,也是用像"镜子"般的样式对应,一样看范例就很容易理解:
// 基本用法
const { user: x } = { user: 5 } // x=5
// 失敗保護(Fail-safe)
const { user: x } = { user2: 5 } //x=undefined
// 賦予新的變數名稱
const { prop: x, prop2: y } = { prop: 5, prop2: 10 } // x=5, y=10
// 屬性賦值語法
const { prop: prop, prop2: prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
// 相當於上一行的簡短語法(Short-hand syntax)
const { prop, prop2 } = { prop: 5, prop2: 10 } //prop = 5, prop2=10
// ES7+的物件屬性其餘運算符
const {a, b, ...rest} = {a:1, b:2, c:3, d:4} //a=1, b=2, rest={c:3, d:4}
下面的语法是个有陷阱的语法,这是错误的示范:
// 錯誤的示範:
let a, b
{ a, b } = {a: 1, b: 2}
注: 这个语法如果使用const来宣告常数是根本不能使用,只能用let来宣告变数。而且eslint检查工具一定会回报语法错误。
因为在Javascript语言中,虽然使用花括号符号({})是物件的宣告符号,但这个符号用在程式叙述中,也就是前面没有let、const、var这些宣告字词时,则是代表程式码的区块(block)。在外面再加上括号符号(())就可以改正,括号符号(())有表达式运算的功能,正确的写法如下:
let a, b
({ a, b } = {a: 1, b: 2}) //a=1, b=2
注: 在大部份情况,你应该是在定义常数或变数时,就进行解构赋值。
复杂的物件或混合阵列到物件,如果你能记住之前说的镜子样式对映基本原则,其实也很容易就能理解:
// 混用物件與陣列
const {prop: x, prop2: [, y]} = {prop: 5, prop2: [10, 100]}
console.log(x, y) // => 5 100
// 複雜多層次的物件
const {
prop: x,
prop2: {
prop2: {
nested: [ , , b]
}
}
} = { prop: "Hello", prop2: { prop2: { nested: ["a", "b", "c"]}}}
console.log(x, b) // => Hello c
从其他的资料类型进行阵列或物件解构,一开始是null或undefined这两种时,你会得到错误:
const [a] = undefined
const {b} = null
//TypeError: Invalid attempt to destructure non-iterable instance
如果是从其他的原始资料类型布林、数字、字串等作物件解构,则会得到undefined值。
const {a} = false
const {b} = 10
const {c} = 'hello'
console.log(a, b, c) // undefined undefined undefined
从其他的原始资料类型布林、数字、字串等作阵列解构的话,只有字串类型可以解构出字元,在上面的例子有看到这种情况,其他也是得到undefined值:
const [a] = false
const [b] = 10
const [c] = 'hello' //c="h"
console.log( a, b, c)
注: 字串资料类型的值只能用在阵列的解构赋值,无法用在物件的解构赋值。
以上会有出现这样的结果,是当一个值要被进行解构时,它会先被转成物件(或阵列),因为null或undefined无法转成物件(或阵列),所以必定产生错误,这是第一阶段。下一个阶段如果这个值转换的物件(或阵列),没有附带对应的迭代器(Iterator)就无法被成功解构赋值,所以最后回传undefined。
在等号左边的样式(pattern)中是可以给定预设值的,作为如果没有赋到值时(对应的值不存在)的预设数值。
const [missing = true] = []
console.log(missing)
// true
const { message: msg = 'Something went wrong' } = {}
console.log(msg)
// Something went wrong
const { x = 3 } = {}
console.log(x)
// 3
要作一个简单的陷阱题满简单的,你可以试看看下面这个范例中到底是赋到了什么值:
const { a ='hello' } = 'hello'
const [ b ='hello' ] = 'hello'
console.log( a, b)
在函式传入参数定义中也可以使用解构赋值,因为函式的传入参数本身也有自己的预设值设定语法,这也是ES6的一个特性,所以使用上会容易与解构赋值自己的预设值设定搞混。这地方会产生不少陷阱。
一个简单的解构赋值用在函式的参数里,这是正常情况的语法:
function func({a, b}) {
return a + b
}
func({a: 1, b: 2}) // 3
当你用上了预设值的机制,而且前面的a有预设值,后面的b就没有,这时候因为没有赋到值时,都会是undefined值,任何数字加上undefined都会变成NaN,也就是非数字的意思:
function func({a = 3, b}) {
return a + b
}
func({a: 1, b: 2}) // 3
func({b: 2}) // 5
func({a: 1}) // NaN
func({}) // NaN
func() // Cannot read property 'a' of undefined
当a与b两个都有预设值时,NaN的情况不存在:
function func({a = 3, b = 5}) {
return a + b
}
func({a: 1, b: 2}) // 3
func({a: 1}) // 6
func({b: 2}) // 5
func({}) // 8
func() // Cannot read property 'a' of undefined
实际上函式传入参数它自己也可以加预设值,但这情况会让最后一种func()呼叫时与func({})相同结果:
function func({a = 3, b = 5} = {}) {
return a + b
}
func({a: 1, b: 2}) // 3
func({a: 1}) // 6
func({b: 2}) // 5
func({}) // 8
func() // 8
另一种情况是在函式传入参数的预设值中给了另一套预设值,这只会在func()时发挥它的作用:
function func({a = 3, b = 5} = {a: 7, b: 11}) {
return a + b
}
func({a: 1, b: 2}) // 3
func({a: 1}) // 6
func({b: 2}) // 5
func({}) // 8
func() // 18
你可以观察一下,当对某个变数赋值时你给他null或void 0,到底是用预设值还是没有值,这个范例的g()函式是个对照组:
function func({a = 1, b = 2} = {a: 1, b: 2}) {
return a + b
}
func({a: 3, b: 5}) // 8
func({a: 3}) // 5
func({b: 5}) // 6
func({a: null}) // 2
func({b: null}) // 1
func({a: void 0}) // 3
func({b: void 0}) // 3
func({}) // 3
func() // 3
function g(a = 1, b = 2) {
return a + b
}
g(3, 5) // 8
g(3) // 5
g(5) // 7
g(void 0, 5) // 6
g(null, 5) // 5
g() // 3
注:所以在函式传入参数中作解构赋值时,给定null值时会导致预设值无用,请记住这一点。当数字运算时,null相当于0。
这个范例用了for...of语法。出自Destructuring assignment:
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 (let {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"
这个范例混用了一些ES6的语法,出自Several demos and usages for ES6 destructuring.:
// 結合其他ES6特性
const ajax = function ({ url = 'localhost', port: p = 80}, ...data) {
console.log('Url:', url, 'Port:', p, 'Rest:', data)
}
ajax({ url: 'someHost' }, 'additional', 'data', 'hello')
// => Url: someHost Port: 80 Rest: [ 'additional', 'data', 'hello' ]
ajax({ }, 'additional', 'data', 'hello')
// => Url: localhost Port: 80 Rest: [ 'additional', 'data', 'hello' ]
这个例子相当于Underscore.js函式库中的_.pluck,把深层的属性值往上拉出来。
var users = [
{ user: "Name1" },
{ user: "Name2" },
{ user: "Name2" },
{ user: "Name3" }
]
var names = users.map( ({ user }) => user )
console.log(names)
// => [ 'Name1', 'Name2', 'Name2', 'Name3' ]
这个是React Native的一个教学,里面有用了解构赋值的语法。出自React Native Tutorial: Building Apps with JavaScript:
var React = require('react-native')
var {
StyleSheet,
Text,
TextInput,
View,
TouchableHighlight,
ActivityIndicatorIOS,
Image,
Component
} = React
箭头函数是ES6中非常重要的性特性。它最显著的作用就是:更简短的函数,并且不绑定this,arguments等属性,它的this永远指向其上下文的 this。它最适合用于非方法函数,并且它们不能用作构造函数。
js模块化的开发并不是随心所欲的,为了便于他人的使用和交流,需要遵循一定的规范。目前,通行的js模块规范主要有两种:CommonJS和AMD
ES6中添加了一个新属性解构,允许你使用类似数组或对象字面量的语法将数组和对象的属性赋给各种变量。用途:交换变量的值、从函数返回多个值、函数参数的定义、提取JSON数据、函数参数的默认值...
ES6中let变量的特点:1.let声明变量存在块级作用域,2.let不能先使用再声明3.暂时性死区,在代码块内使用let命令声明变量之前,该变量都是不可用的,4.不允许重复声明
ES6的7个实用技巧包括:1交换元素,2 调试,3 单条语句,4 数组拼接,5 制作副本,6 命名参数,7 Async/Await结合数组解构
ES6装饰器(Decorator)是一个函数,用来修改类的行为 在设计阶段可以对类和属性进行注释和修改。从本质上上讲,装饰器的最大作用是修改预定义好的逻辑,或者给各种结构添加一些元数据。
Query作为曾经Web前端的必备利器,随着MVVM框架的兴起,如今已稍显没落。用ES6写了一个基于class简化版的jQuery,包含基础DOM操作,支持链式操作...
ES6 中的一些技巧:模版字符串、块级作用域、Let、Const、块级作用域函数问题、扩展运算符、函数默认参数、解构、对象字面量和简明参数、动态属性名称、箭头函数、for … of 循环、数字字面量。
Rest/Spread 属性:rest操作符在对象解构中的使用。目前,该操作符仅适用于数组解构和参数定义。spread操作符在对象字面量中的使用。目前,这个操作符只能在数组字面量和函数以及方法调用中使用。
ES6使您的代码更具表现力和可读性。而且它与React完美配合!现在您已了解更多基础知识:现在是时候将你的ES6技能提升到一个新的水平!嵌套props解构、 传下所有props、props解构、作为参数的函数、列表解构
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!