解构赋值
ES6允许按照一定模式从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)
- 基本用法
{
let name = 'bob', age = 18, sex = 'man';
console.log(name, age, sex);// bob 18 man
}
{
let [name, age, sex] = ['bob', 18, 'man'];
name='lucy';
console.log(name, age, sex);// lucy 18 man
}
{
let [...rest] = ['bob', 18, 'man'];
console.log(rest); // [ 'bob', 18, 'man' ]
}
- 对象的解构赋值
{
let {name, age, sex} = {name: 'bob', age: 18, sex: 'man'};
console.log(name, age, sex);// bob 18 man
}
//复杂对象解构赋值
{
let {name, age, sex, friends, pet} = {
name: 'john',
age: 18,
sex: 'man',
friends: ['bob', 'lucy'],
pet: {name: 'dog', age: 4}
};
console.log(name, age, sex, friends,pet);// john 18 man (2) ["bob", "lucy"] {name: "dog", age: 4}
}
{
let { ...rest } = {
name: 'john',
age: 18,
sex: 'man',
friends: ['bob', 'lucy'],
pet: { name: 'dog', age: 4 }
};
console.log(rest); // { name: 'john', age: 18, sex: 'man', friends: [ 'bob', 'lucy' ], pet: { name: 'dog', age: 4 } }
}
- 数组解构赋值
{
let [name, age, sex] = ['bob', 18, 'man'];
name = 'lucy';
console.log(name, age, sex);// lucy 18 man
}
//复杂对象解构赋值
{
let [arr1, [arr2, arr3, [arr4, arr5]]] = [1, [2, 3, [4, 5]]];
console.log(arr1, arr2, arr3, arr4, arr5);// 1 2 3 4 5
}
{
let [arr]=[];
console.log(arr);//undefined
}
{
let [a,,b,c]=[1,2,3];
console.log(a, b, c);// 1 3 undefined
}
- 基本类型的解构赋值(实际应用比较少)
{
let [a,b,c,d,e]='bob';
console.log(a, b, c, d, e);// b o b undefined undefined
}
{
let [a,b,c,d,e]=12345;
console.log(a, b, c, d, e);// error: 12345 is not iterable(number类型没有构造器 string类型有构造器)
}
用途
- 交换变量的值
let [x, y] = [1, 2];
[x, y] = [y, x]
console.log(x, y)// 2 1
- 从函数返回多个值
// 返回数组
function f1 () {
return [1, 2, 3]
}
let [a, b, c] = f1()
console.log(a, b, c)// 1 2 3
// 返回对象
function f2 () {
return {
foo: 1,
bar: 2
}
}
let { foo, bar } = f2()
console.log(foo, bar)// 1 2
- 函数参数的定义
// 参数是一组有次序的值
function f1 ([x, y, z]) { ... }
f1([1, 2, 3])
// 参数是一组无次序的值
function f2 ({ x, y, z }) { ... }
f2({ z: 3, x: 1, y: 2 })
- 提取 JSON 数据
let json = {
name: 'john',
age: 18,
gender: '男',
hobbies: ['游戏', '追剧']
}
let { name, age, gender, hobbies } = json
console.log(name, age, gender, hobbies)// john 18 男 ["游戏", "追剧"]
- 遍历 Map 结构
let map = new Map()
map.set('bob', 12)
map.set('lucy', 22)
for (let [key, value] of map) {
console.log(key + ' is ' + value)
}
// bob is 12
// lucy is 22
// 如果想单独遍历
// 键名
for (let [key]of map) {
console.log(key)// bob lucy
}
// 键值
for (let [, value]of map) {
console.log(value)
}
- 输入模块的指定方法
const { SourceMapConsumer, SourceNode } = require('source-map')
for of
- for … of:遍历获取键值,无法直接遍历对象
- for … in:遍历获取键名,可以直接遍历对象,获取键名
let obj = ['a', 'b', 'c']
for (let i of obj) {
console.log(i)// a b c
}
for (let i in obj) {
console.log(i)// 0 1 2
}
// 针对 for ... of 无法遍历对象,用 Object.keys() 将对象的键名生成一个数组,再遍历
let obj = { a: '1', b: '2', c: '3' }
for (let i in obj) {
console.log(i)// a b c
}
for (let i of Object.keys(obj)) {
console.log(i)// a b c
}
// 或者自己封装遍历对象
function * f1 (obj) {
let keys = Reflect.ownKeys(obj)
for (let key of keys) {
yield [key, obj[key]]
}
}
let obj = { a: '1', b: '2', c: '3' }
for (let [key, value] of f1(obj)) {
console.log(key, value)
}
// 另一种写法:将 Generator 函数添加到对象的 Symbol.iterator 属性上
function * f1 () {
let keys = Object.keys(this)
for (let key of keys) {
yield [key, this[key]]
}
}
let obj = { a: '1', b: '2', c: '3' }
obj[Symbol.iterator] = f1
for (let [key, value] of obj) {
console.log(key, value)
}
遍历具有 Iterator 接口的数据结构,原生具备 Iterator 接口的数据结构如下
- Array
- Map
- Set
- String
- TypedArray
- 函数的 arguments 对象
- NodeList 对象
Iterator 基本原理:调用 next 方法访问并返回数据结构的当前成员信息,具体就是返回具备 value 和 done 两个属性的对象,value 是当前成员的值,done 是布尔类型表示遍历是否结束
基本原理:
let it = Iterator(['a', 'b'])
console.log(it.next())// {value: "a", done: false}
console.log(it.next())// {value: "b", done: false}
console.log(it.next())// {value: undefined, done: true}
function Iterator (arr) {
let nextIndex = 0
return {
next: function () {
return nextIndex < arr.length ?
{ value: arr[nextIndex++], done: false } :
{ value: undefined, done: true }
},
}
}
Iterator 接口:
function Obj (value) {
this.value = value
this.next = null
}
Obj.prototype[Symbol.iterator] = function () {
let iterator = { next }
let current = this
function next () {
if (current) {
let value = current.value
current = current.next
return { done: false, value: value }
} else {
return { done: true }
}
}
return iterator
}
let one = new Obj(1)
let two = new Obj(2)
let three = new Obj(3)
one.next = two
two.next = three
for (let i of one) {
console.log(i)// 1 2 3
}
数组的 iterator 接口
let arr = {
data: ['a', 'b', 'c'],
[Symbol.iterator] () {
const self = this
let index = 0
return {
next () {
if (index < self.data.length) {
return {
value: self.data[index++],
done: false,
}
} else {
return { value: undefined, done: true }
}
},
}
},
}
for (let i of arr) {
console.log(i)// a b c
}
伪数组的 iterator 接口
对于伪数组的对象,部署 Iterator 接口有个简便方法,即使用 Symbol.iterator 方法直接引用数组的 Iterator 接口
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator]
// 或者
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator]
实例:
let pseudo_arr1 = {
0: 'a',
1: 'b',
2: 'c',
length: 3,
[Symbol.iterator]: [][Symbol.iterator],
}
for (let i of pseudo_arr1) {
console.log(i)// a b c
}
// 注意:普通对象部署无效
let pseudo_arr2 = {
a: 'a',
b: 'b',
c: 'c',
length: 3,
[Symbol.iterator]: [][Symbol.iterator],
}
for (let i of pseudo_arr2) {
console.log(i)// undefined undefined undefined
}
字符串的 Iterator 接口
let str = 'hello'
let iterator = str[Symbol.iterator]()
console.log(iterator.next())// {value: "h", done: false}
console.log(iterator.next())// {value: "e", done: false}