一、解构赋值
解构赋值是对赋值运算符的一种扩展,它针对数组和对象来进行操作。
优点:代码书写上简洁易读
1.完全解构
在ES5中获取对象里的值,我们这样做:
let obj = {
name:'cgp',
age:20
}
let name=obj.name;
let age=obj.age;
console.log(name,age);
但是在ES6 中我们有更简便的写法:
let obj = {
name:'cgp',
age:20
}
// let name=obj.name;
// let age=obj.age;
// console.log(name,age);
let {name,age}=obj;
console.log(name,age);
2、不完全解构
剩余运算符:
let book = {
content: {
title: 'cgp',
sell: 5
},
author: 'ht',
page: 20
}
let { content, ...rest } = book;//剩余运算符
console.log(content); //{title: 'cgp', sell: 5}
console.log(rest); //{author: 'ht', page: 20}
3.重命名
如果想给某个属性重命名,可以使用冒号(之前的名字:变成的名字)
比如上面的案例可以这样:
let { content: a } = book;
console.log(a);
let { name: myname, age: myage } = obj;
console.log(myname, myage);
4、数组解构
let arr = [1, 2, 3];
let [a, b, c] = arr;
console.log(a, b, c); // 123
// 相当于把123赋值给abc
这里写的比较简便,可以再看看阮一峰文档。
二、symbol数据类型
ES6单独引入Symbol,其目的是防止对象的属性名冲突。
ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol
的原因。
1、相同参数的Symbol函数,也是不相等的:(独一无二)
let a = Symbol('cgp');
let b = Symbol('cgp');
console.log(b); //Symbol(cgp)
console.log(a); //Symbol(cgp)
console.log(a===b);//false 说明a不等于b,即使他们都是cgp但是他们都是独一无二的
2、如果参数是个对象,把obj给c
const obj = { name: 'cgp' };
const c = Symbol(obj);
console.log(c); //Symbol([object Object])
3、如果给上面的obj一个属性:obj[a] = '范小琴';
const c = Symbol(obj);
console.log(c); //Symbol([object Object])
obj[a] = '范小琴';
console.log(obj); //Object { name: "cgp", Symbol("cgp"): "范小琴" }
这段代码相当于:
let obj = {
name: 'cgp',
[a]: '范小琴'
};
console.log(obj); //{name: 'cgp', Symbol(cgp): '范小琴'}
4、获取对象中的Symbol属性值
获取对象中的Symbol属性值,必须用[symbol变量名]
,不能用点,因为用点意思就是obj里有个属性名叫做a,而这个Symbol不是属性名a,而是a对应的Symbol(cgp)
console.log(obj[a]); //张大仙
console.log(obj.a); //undefined
5.Symbol属性名是遍历不到的
Symbol 作为属性名,遍历对象的时候,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。
但是,它也不是私有属性,有一个Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名。该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
还有个Reflect.ownKeys()方法可以返回所有类型的键名,包括常规键名和 Symbol 键名。
const o = {};
const name = Symbol('name');
o[name] = 'cgp';
o['age'] = 20;
for (let i in o) {
console.log(i); // 只有age
}
console.log(Object.getOwnPropertyNames(o)); //['age']
console.log(Object.getOwnPropertySymbols(o)); // [Symbol(name)]
console.log(Reflect.ownKeys(o)); //['age', Symbol(name)]
暂时记了这么多,遇到其他的可以再看文档
三、Map和Set数据结构
这两个内置对象最大的区别,我认为是Set是只有值没有键,Map是键值对,而且键可以为任意类型(不局限于字符串,键可以是字符串、数组、undefined、甚至函数等等)
1.Set
Set实际上类似于数组,但是成员的值都是唯一的,没有重复的值。其本身是个构造函数,是个内置对象
(1)Set的属性和方法
属性:
Set.prototype.constructor:构造函数,默认就是Set函数。
Set.prototype.size:返回Set实例的成员总数。
方法:
Set.prototype.add(value):添加某个值,返回 Set 结构本身。
Set.prototype.delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
Set.prototype.has(value):返回一个布尔值,表示该值是否为Set的成员。
Set.prototype.clear():清除所有成员,没有返回值。
const s = new Set();
s.add(2);
s.add('4');
s.add([4, 3, 2]);
console.log(s); // {2, '4', Array(3)}
console.log(s.size); //3
s.delete('4');
console.log(s); // {2, Array(3)}
console.log(s.has('4')); //false
遍历操作:
Set.prototype.keys():返回键名的遍历器
Set.prototype.values():返回键值的遍历器
Set.prototype.entries():返回键值对的遍历器
Set.prototype.forEach():使用回调函数遍历每个成员
这里需要注意的是,Set 结构没有键名,只有键值(或者说键名和键值是同一个值),所以keys方法和values方法的行为完全一致。
//1.遍历Set中的键
let set1 = new Set(['red', 'green', 'blue']);
console.log(set1.keys()); //SetIterator {'red', 'green', 'blue'}
for (let i of set1.keys()) {
console.log(i);
// red
// green
// blue
}
//2.遍历Set中的值
console.log(set1.values()); //SetIterator {'red', 'green', 'blue'}
for (let i of set1.values()) {
console.log(i);
// red
// green
// blue
}
//3.遍历Set中的键值对
console.log(set1.entries()); //SetIterator {'red' => 'red', 'green' => 'green', 'blue' => 'blue'}
for (let i of set1.entries()) {
console.log(i);
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]
}
如果想遍历Set,直接这么写就行了
console.log(set1); //Set(3) {'red', 'green', 'blue'}
for (let i of set1) {
console.log(i);
// red
// green
// blue
}
Set 结构的实例与数组一样,也拥有forEach
方法,用于对每个成员执行某种操作,没有返回值。
let set = new Set([1, 4, 9]);
set.forEach((value, key) => console.log(key + ' : ' + value))
// 1 : 1
// 4 : 4
// 9 : 9
(2)Set实现数组去重
1.可以直接用剩余运算符进行数组去重,set接过来的是一个去重之后的{2, 3, 4, 5}这玩意儿,用剩余运算符拆开,然后再放进[]里面,就成数组了
const set = new Set([2, 3, 3, 3, 4, 5]);
console.log([...set]); //[2,3,4,5]
2.Array.from
方法可以将 Set 结构转为数组。
const items = new Set([1, 2, 3, 4, 5]);
const arr = Array.from(items);
这样就有了去重的另一种方法
function dedupe(arr) {
let s = new Set(arr);
return Array.from(s);
}
console.log(dedupe([1, 1, 2, 3])); // [1, 2, 3]
以上这两种方法原理是一样的,都是利用Set对象的去重能力。
(3)Set实现字符串去重
还是一样,都是利用Set对象的去重能力,只是我没想到Set的参数还可以是字符串
let str = new Set('aabbbcc');
console.log(str); //{'a', 'b', 'c'}
str = [...str].join('');
console.log(str); //'abc'
2.Map
和Set类似,Map解决的是传统Object对象里只能用字符串作为键的缺陷,它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
(1)Map的属性和方法
属性:
Map.prototype.size:返回Map实例的成员总数。
方法:
Map.prototype.set(key, value)
Map.prototype.get(key)
Map.prototype.has(key)has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
Map.prototype.delete(key)delete方法删除某个键,返回true。如果删除失败,返回false。
Map.prototype.clear()clear方法清除所有成员,没有返回值。
遍历操作:
Map.prototype.keys():返回键名的遍历器
Map.prototype.values():返回键值的遍历器
Map.prototype.entries():返回键值对的遍历器
Map.prototype.forEach():遍历 Map 的所有成员
大部分和Set一样,就不解释了,不懂了去翻文档好了
其中主要看下这个set和get
Map.prototype.set(key, value)
set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。.键可以是任何东西
const m = new Map();
m.set('name', 'zzy'); //键是字符串
m.set(undefined, 12); //键是undefined
m.set(666, 'ht'); //键是数值
m.set(function () { }, '不错'); //键是函数
console.log(m); //Map(4) {'name' => 'zzy', undefined => 12, 666 => 'ht', ƒ => '不错'}
Map支持链式写法:
const m = new Map().set(1, 'a').set(2, 'b');
console.log(m); //{1 => 'a', 2 => 'b'}
Map.prototype.get(key)
get方法读取key对应的键值,如果找不到key,返回undefined。
console.log(m.get(666)); //ht
console.log(m.get('age')); //undefined
除此之外Map也可以用多维数组设置默认值
const map = new Map([[1, 'a'], [2, 'b']]);
console.log(map); //{1 => 'a', 2 => 'b'}
四、数组的扩展方法
1.from()将伪数组转换为真数组
比如把arguments转换为一个真数组
function add() {
let arr = Array.from(arguments);
console.log(arr); //[1, 2, 3]
}
add(1, 2, 3);
比如ul里面的好多li的数组集合,转换为真正的数组
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
let lis = document.querySelectorAll('li');
console.log(lis); //NodeList(4) [li, li, li, li]
console.log(Array.from(lis)); // [li, li, li, li]
当然上面这个其实可以直接用扩展运算符
console.log([...lis]); // [li, li, li, li]
from()还可以有第二个参数,可以对每一个元素进行处理
let liContents = Array.from(lis, c => c.innerHTML);
console.log(liContents); //['1', '2', '3', '4']
2.of()将任意数据类型转换为数组
也不知道这个有啥用
console.log(Array.of('2', [2, 3], { 'a': 1 }, undefined));
//['2', Array(2), {…}, undefined]
3.find()和findiIndex()
find()是找出数组中符合条件的第一个数组成员
findexIndex()是找出数组中符合条件的第一个数组成员的索引
let num = [1, 2, -10, 23, -34].find(n => n < 0);
let numindex = [1, 2, -10, 23, -34].findIndex(n => n < 0);
console.log(num, numindex); //-10 2
4.数组中的keys()和values()和entries()遍历
它们都返回一个遍历器对象,可以用for…of循环进行遍历,唯一的区别是keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历。(数组中键名就是索引,键值就是元素)这个和前边Set,Map差不多
let arr = ['a', 3, 5]
for (let key of arr.keys()) {
console.log(key); //0 1 2
}
for (let value of arr.values()) {
console.log(value); // a 3 5
}
for (let [key, value] of arr.entries()) {
console.log(key, value);
//0 'a'
//1 3
//2 5
}
注意理解这三个方法返回的是一个遍历器对象,我们也可以用遍历器对象的next方法对其遍历
//返回一个遍历器对象
let item = arr.entries();
console.log(item.next()); //{value: [0,'a'], done: false}
console.log(item.next().value); //[1,3]
console.log(item.next().value); //[2,'b']
console.log(item.next().value); //undefined
5.includes()判断某个元素是否在数组中
这个其实是为了替代之前的indexOf,省的再去写判断条件indexOf() === -1了,如果忘了就去翻数组内置对象的数组去重那个案例。
let a = ['zzy', 23, 'ht', 18];
console.log(a.includes('z')); //false
console.log(a.includes(23)); //true
这些都不是很详细,如果有不懂得,可以去看看文档。