解构赋值
通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。简单理解就是等号的左边和右边相等。主要分为对象的解构和数组的解构,在没有解构赋值的时候,我们赋值是这样的
let arr = [0,1,2]
let a = arr[0]
let b = arr[1]
let c = arr[2]数组的解构赋值
数组解构的基本用法
let [a, b, c] = [1, 2, 3] // a=1, b=2, c=3
let [d, [e], f] = [1, [2], 3] // 嵌套数组解构 d=1, e=2, f=3
let [g, ...h] = [1, 2, 3] // 数组拆分 g=1, h=[2, 3]
let [i,,j] = [1, 2, 3] // 不连续解构 i=1, j=3
let [k,l] = [1, 2, 3] // 不完全解构 k=1, l=2变量声明并赋值时的解构
let arr = [0, 1, 2]
let [a, b, c] = arr
console.log(a) // 0
console.log(b) // 1
console.log(c) // 2变量先声明后赋值时的解
通过解构分离变量的声明,可以为一个变量赋值
var a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2undefined的对象,可以在表达式左边的数组中为任意对象预设默认值。let arr = [, 1, 2] // 等价于 let arr1 = [undefined, 1, 2]
let [a = '我是默认值', b, c] = arr
console.log(a) // '我是默认值'
console.log(b) // 1
console.log(c) // 2那么当a=null时呢?当a=null时,那么a就不会使用默认值,而是使用null
let arr1 = [null, 1, 2]
let [a = '我是默认值', b, c] = arr1
console.log(a) // null
console.log(b) // 1
console.log(c) // 2解析一个从函数返回的数组
从一个函数返回一个数组是十分常见的情况。解构使得处理返回值为数组时更加方便。在下面例子中,要让 [1, 2] 成为函数的 f() 的输出值,可以使用解构在一行内完成解析。
function f() {
return [1, 2];
}
var a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2
===============
// 忽略某些返回值
function f() {
return [1, 2, 3];
}
var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
===============
// 忽略全部返回值:
[,,] = f();
将剩余数组赋值给一个变量
如果剩余元素右侧有逗号,会抛出 SyntaxError,因为剩余元素必须是数组的最后一个元素。
var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
============
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma数组的拼接
let a = [0, 1, 2]
let b = [3, 4, 5]
let c = a.concat(b)
console.log(c) // [0, 1, 2, 3, 4, 5]
let d = [...a, ...b]
console.log(d) // [0, 1, 2, 3, 4, 5]数组的克隆
// 数组的克隆
// 假如我们简单地把一个数组赋值给另外一个变量
let a = [0,1,2,3]
let b = a
b.push(4)
console.log(a) // [0,1,2,3,4]
console.log(b) // [0,1,2,3,4]
// 这只是简单的把引用地址赋值给b,而不是重新开辟一个内存地址
// 所以a和b共享了同一个内存地址,
// 该内存地址的更改,会影响到所有引用该地址的变量let a = [0,1,2,3]
let b = [...a]
b.push(4)
console.log(a) // [0,1,2,3]
console.log(b) // [0,1,2,3,4]
对象的解构赋值
对象解构的基本用法:
let {a, b} = {a: 'aaaa', b: 'bbbb'} // a='aaaa' b='bbbb'
let obj = {d: 'aaaa', e: {f: 'bbbb'}}
let {d, e:{f}} = obj // 嵌套解构 d='aaaa' f='bbbb'
let g;
(g = {g: 'aaaa'}) // 以声明变量解构 g='aaaa'
let [h, i, j, k] = 'nice' // 字符串解构 h='n' i='i' j='c' k='e'let {length} = "hello swr"
console.log(length) // 9基本赋值
var o = {p: 42, q: true};
var {p, q} = o;
console.log(p); // 42
console.log(q); // true无声明赋值
一个变量可以独立于其声明进行解构赋值。
var a, b;
({a, b} = {a: 1, b: 2});给新的变量名赋值
可以从一个对象中提取变量并赋值给和对象属性名不同的新的变量名。
var o = {p: 42, q: true};
var {p: foo, q: bar} = o;
console.log(foo); // 42
console.log(bar); // true 默认值
变量可以先赋予默认值。当要提取的对象没有对应的属性,变量就被赋予默认值。
var {a = 10, b = 5} = {a: 3};
console.log(a); // 3
console.log(b); // 5
使用场景
变量赋值
先来看我们在平时开发中是怎么使用es5对变量赋值的:
var data = {userName: 'aaaa', password: 123456}
var userName = data.userName
var password = data.password
console.log(userName)
console.log(password)
var data1 = ['aaaa', 123456]
var userName1 = data1[0]
var password1 = data1[1]
console.log(userName1)
console.log(password1)const {userName, password} = {userName: 'aaaa', password: 123456}
console.log(userName)
console.log(password)
const [userName1, password1] = ['aaaa', 123456]
console.log(userName1)
console.log(password1)函数参数的定义
一般我们在定义函数的时候,如果函数有多个参数时,在es5语法中函数调用时参数必须一一对应,否则就会出现赋值错误的情况,来看一个例子:
function personInfo(name, age, address, gender) {
console.log(name, age, address, gender)
}
personInfo('william', 18, 'changsha', 'man')function personInfo({name, age, address, gender}) {
console.log(name, age, address, gender)
}
personInfo({gender: 'man', address: 'changsha', name: 'william', age: 18})交换变量的值
在es5中我们需要交换两个变量的值需要借助临时变量的帮助,来看一个例子:
var a=1, b=2, c
c = a
a = b
b = c
console.log(a, b)let a=1, b=2;
[b, a] = [a, b]
console.log(a, b)函数的默认参数
在日常开发中,经常会有这种情况:函数的参数需要默认值,如果没有默认值在使用的时候就会报错,来看es5中是怎么做的:
function saveInfo(name, age, address, gender) {
name = name || 'william'
age = age || 18
address = address || 'changsha'
gender = gender || 'man'
console.log(name, age, address, gender)
}
saveInfo()function saveInfo({name= 'william', age= 18, address= 'changsha', gender= 'man'} = {}) {
console.log(name, age, address, gender)
}
saveInfo()解构嵌套对象和数组
const metadata = {
title: 'Scratchpad',
translations: [
{
locale: 'de',
localization_tags: [],
last_edit: '2014-04-14T08:43:37',
url: '/de/docs/Tools/Scratchpad',
title: 'JavaScript-Umgebung'
}
],
url: '/en-US/docs/Tools/Scratchpad'
};
let {
title: englishTitle, // rename
translations: [
{
title: localeTitle, // rename
},
],
} = metadata;
console.log(englishTitle); // "Scratchpad"
console.log(localeTitle); // "JavaScript-Umgebung"For of 迭代和解构
var 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 (var {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"从作为函数实参的对象中提取数据
function userId({id}) {
return id;
}
function whois({displayName: displayName, fullName: {firstName: name}}){
console.log(displayName + " is " + name);
}
var user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
console.log("userId: " + userId(user)); // "userId: 42"
whois(user); // "jdoe is John"对象属性计算名和解构
let key = "z";
let { [key]: foo } = { z: "bar" };
console.log(foo); // "bar"解构对象时会查找原型链(如果属性不在对象自身,将从原型链中查找)
// 声明对象 和 自身 self 属性
var obj = {self: '123'};
// 在原型链中定义一个属性 prot
obj.__proto__.prot = '456';
// test
const {self, prot} = obj;
// self "123"
// prot "456"(访问到了原型链)