ES6(二):解构赋值、Symbol、Map和Set、数组的扩展方法

本文介绍了ES6中的解构赋值、Symbol的独特性质以及Map和Set数据结构的使用,包括数组和对象的解构、Symbol作为属性名的唯一性和Map/Set的键值对操作。同时,还讨论了数组的扩展方法,如from()和of()函数,以及数组遍历的不同方式。
摘要由CSDN通过智能技术生成

一、解构赋值

解构赋值是对赋值运算符的一种扩展,它针对数组和对象来进行操作。

优点:代码书写上简洁易读

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

这些都不是很详细,如果有不懂得,可以去看看文档。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值