ES语法扩展

时间:2023-01-09 08:55:32

剩余参数 

剩余参数本质

// 剩余参数的本质
    const add=(x,y,...args)=>{
        console.log(x,y,args);
    }
    add();
    add(1);
    add(1,2);
    add(1,2,3,4,5);

ES语法扩展

剩余参数的注意事项

  • 箭头函数的参数部分即使只有一个剩余参数,也不能省略圆括号
  • 使用剩余参数替代arguments获取实际参数
  • 剩余参数的位置只能是最后一个参数,之后不能再有其他参数,否则会报错
// const add=function (){
    //     console.log(arguments);
    // }
    
    // 箭头函数不能用arguments对象
    // const add=()=>{
    //     console.log(arguments);
    // }
    const add=(...args)=>{
        console.log(args);
    }
    add(1,2);

特别注意:arguments对象在箭头函数不能使用

剩余参数的应用

剩余参数可以是数组也可以是对象

// 与解构赋值一起使用
    // 剩余参数不一定非要作为函数参数使用
    // 必须是最后一个
    const [num,...args]=[1,2,3,4];
    console.log(num,args);

    const func=([n,...args])=>{
        console.log(n,args);
    };
    func([1,2,3]);

    // ...z代表剩余元素比较合适
    const {x,y,...z}={a:1,x:2,y:3,b:4};
    console.log(x,y,z); //z是一个对象

    const func1=({x,y,...z})=>{
        console.log(x,y,z); //z是一个对象
    };
    func1({a:1,x:2,y:3,b:4});

ES语法扩展

数组的展开运算符

Math.min()括号里面必须是参数列表,不能是数组,把它转为展开运算符即可使用

console.log(Math.min(...[1,2,3]));    //1
    console.log(Math.min(3,1,2));    //1

区分剩余参数和展开运算符

// 本质区别
    // 展开运算符
    // [3,1,2]->3,1,2
    // 剩余参数
    // 3,1,2->[3,1,2]
    const add=(...args)=>{
        console.log(args);  //剩余参数
        console.log(...args);   //展开运算符
    }
    add(1,2,3);
    // 二维数组转为一维数组
    console.log([...[1,2,3],4]);

ES语法扩展

数组展开运算符的应用

// 1.复制数组
    const a=[1,2];
    const b=[...a];
    a[0]=3;
    console.log(a);
    console.log(b);
    // 2.合并数组
    const c=[1,2];
    const d=[3];
    const e=[4,5];
    console.log([...d,...c,...e]);
    // 3.字符串转为数组
    // 字符串可以按照数组的形式展开
    console.log(...'alex');
    console.log('a','l','e','x');
    console.log([...'alex']);
    console.log('alex'.split(''));
    // 4.常见的类数组转化为数组
    // arguments和NodeList
    function func(){
        console.log(arguments);
        console.log([...arguments]);
    }
    func(1,2);
    // NodeList
    console.log(document.querySelectorAll('p'));
    console.log([...document.querySelectorAll('p')].push);

ES语法扩展

对象的展开运算符 

对象的展开:把属性罗列出来,用逗号分隔,放到一个{}中,构成新对象

// 1.展开对象
    // 对象不能直接展开,必须在花括号里展开
    const apple = {
        color: '红色',
        shape: '球形',
        taste: '甜'
    };
    // 新对象
    console.log({...apple});
    console.log({...apple} === apple);  //false
    // 2.合并对象
    const pen={
        color: '黑色',
        shape: '圆柱形',
        use:'写字'
    };
    // 新对象拥有全部属性,相同属性,后者覆盖前者
    console.log({...pen,...apple});

ES语法扩展

对象展开运算符的注意事项

// 1.空对象的展开
    // 如果展开一个空对象,则没有任何效果
    console.log({...{}});
    console.log({...{},a:2});

    // 2.非对象的展开
    // 如果展开的不是对象,则会自动将其转为对象,再将其属性罗列出来
    console.log({...1});
    console.log(new Object(1)); // 对象Number{1},里面没有任何属性
    console.log(new Object(undefined)); // {}.里面没有任何属性
    console.log(new Object(null)); // {},里面没有任何属性
    console.log(new Object(true)); // 对象Boolean{true},里面没有任何属性

    // 如果展开运算符后面是字符串/数组,它会自动转成一个类似数组的对象
    // 返回的不是空对象
    console.log({...'alex'});
    console.log([...'alex']);
    console.log({...[1,2,3]});

    // 3.对象中对象属性的展开
    // 特点:不会展开对象中的对象属性
    const apple={
        feature:{
            taste:'甜'
        }
    };
    const pen={
        feature: {
            color:'黑色',
            shape:'圆柱形'
        },
        use:'写字'
    };
    console.log({...apple});
    console.log({...apple,...pen});

ES语法扩展

对象展开运算符的应用

// 用户参数和默认参数
    const logUser=userParam=>{
        const defaultParam={
            username:'Alex',
            age:0,
            sex:'male'
        }
        // const param={...defaultParam,...useParam};
        // console.log(param.username,param.age,param.sex);
        const {username,age,sex}={...defaultParam,...userParam};
        console.log(username,age,sex);
    }
    logUser();
    logUser({username:'张三'});

ES语法扩展

调用logUser()方法,用户参数userParam为undefined,这时...userParam为{},所以{username,age,sex}跟默认参数一样 

Set和Map数据结构

Set数据结构

Set是一系列无序、没有重复值的数据集合 

方法有:add、has、delete、clear、forEach 属性有:size

const s=new Set();
    s.add(1);
    s.add(2);
    s.add(3);
    // Set中不能有重复的成员
    s.add(1);
    console.log(s);
    // Set没有下标去标示每一个值,所以Set是无序的,
    // 也不能像数组那样通过下标去访问Set的成员

    // 遍历(按照成员添加进集合的顺序遍历)
    s.forEach(function (value,key,set){
        // Set中value和key相等 为了统一
        console.log(value,key,set===s);
        //console.log(this);  // 非严格模式下undefined转为window
    })

ES语法扩展

Set构造函数的参数 

<p>1</p>
<p>2</p>
<p>3</p>
<script>
    // 1.数组
    const s = new Set([1, 2, 1]);
    console.log(s);
    // 2.字符串、arguments、nodeList、Set实例等
    console.log(new Set('hi'));

    function func() {
        console.log(new Set(arguments));
    }

    func(1, 2, 1);
    console.log(new Set(document.querySelectorAll('p')));
    console.log(new Set(s) === s);
</script>

ES语法扩展

Set的注意事项

  • 判断重复set方式
  • 什么时候使用set
// 1.判断重复的方式
    const s=new Set([1,2,1,NaN,NaN]);
    console.log(1===1);//true
    console.log(NaN===NaN);//false
    // Set对重复值的判断基本遵循严格相等(===)
    // 但是对于NaN的判断与===不同,Set中NaN等于NaN
    console.log(s);

    const s1=new Set();
    s1.add({}).add({});
    console.log({}==={});   //引用类型看内存地址是否相同
    console.log(s1);

    // 2.什么时候使用Set
    // (1)数组或字符串去重时
    // (2)不需要通过下标访问,只需要遍历时
    // (3)为了使用Set提供的方法和属性

ES语法扩展

Set的应用

// 1.数组去重
    const s=new Set([1,2,1]);
    console.log(s);
    console.log(...s);
    console.log([...s]);
    console.log([...new Set([1,2,1])]);

    // 2.字符串去重
    const s1=new Set('abcddcba');
    console.log(s1);
    console.log(...s1);
    console.log([...s1].join(''));

    // 3.存放dom元素
    console.log(document.querySelectorAll('p'));
    const s2=new Set(document.querySelectorAll('p'));
    console.log(s2);
    s2.forEach(function (element){
        console.log(element);
        element.style.color='red';
        element.style.backgroundColor='yellow';
    })

 ES语法扩展

Map数据结构 

Map和对象都是键值对的集合

对象一般用字符串当作键,因为是合法的标识符,通常引号可省略

const obj = {
        'name': 'alex',
        true: true,
        [{}]: 'object'
    };
    console.log(obj);
    console.log({}.toString());
    // 基本数据类型:数字、字符串。布尔值、undefined、null
    // 引用数据类型:对象([]、{}、函数、Set、Map等)
    // 以上都可以作为Map的键
    const m = new Map();
    m.set('name', 'alex');
    m.set(true, 'true');
    m.set({}, 'object');
    m.set(new Set([1, 2]), 'set');
    m.set(undefined, 'undefined');
    console.log(m);

ES语法扩展

// 1.set方法
    // 使用set添加的新成员,键名如果已经存在,后添加的键值对覆盖前面的
    const m=new Map();
    m.set('age',18).set(true,'true').set('age',20);
    console.log(m);
    // 2.get方法
    // get获取不存在的成员,返回undefined,不会报错
    console.log(m.get('age'));
    console.log(m.get(true));
    // 3.has方法
    console.log(m.has('age'));
    // 4.delete方法
    // 删除不存在的成员,什么都不会发生,也不会报错
    m.delete('age');
    m.delete('name');
    console.log(m);
    // 5.clear方法
    m.clear();
    console.log(m);
    // 6.forEach方法
    m.set('age',18).set(true,'true').set('age',20);
    m.forEach(function (value,key,map){
        console.log(value,key,map===m);
        console.log(this);
    })
    // size属性
    console.log(m.size);

ES语法扩展

Map构造函数的参数

// 1.二维数组
    console.log(new Map([
        ['name','alex'],
        ['age',18]
    ]));
    // 2.Set、Map等
    // Set也必须体现出键和值
    const s=new Set([
        ['name','alex'],
        ['age',20]
    ]);
    console.log(new Map(s));
    console.log(s);
    // Map
    const m1=new Map([
        ['name','alex'],
        ['age',22]
    ]);
    console.log(m1);
    const m2=new Map(m1);
    console.log(m2);
    console.log(m2===m1);

ES语法扩展

Map的注意事项

  • 判断键名是否相同的方式
  • 什么时候使用Map
// 1.判断键名是否相同的方式
    // 基本遵循严格相等(===)
    // 例外就是NaN,Map中NaN等于NaN
    const m=new Map();
    m.set(NaN,1).set(NaN,2);
    console.log(m);
    
    // 2.什么时候使用Map
    // (1)只需要key->value的结构
    // (2)需要字符串以外的值做键名

Map的应用

// 解构赋值
    const [p1, p2, p3] = document.querySelectorAll('p');
    //console.log(p1,p2,p3);
    const m = new Map([
        [p1, {
            color: 'red',
            backgroundColor: 'yellow',
            fontSize: '40px'
        }],
        [p2, {
            color: 'green',
            backgroundColor: 'pink',
            fontSize: '40px'
        }],
        [p3, {
            color: 'blue',
            backgroundColor: 'orange',
            fontSize: '40px'
        }]
    ]);
    m.forEach((propObj, element) => {
        for (const p in propObj){
            element.style[p]=propObj[p];
        }
    });

ES语法扩展

遍历

// 使用iterator 可遍历对象
    const it=[1,2][Symbol.iterator]();
    console.log(it.next());
    console.log(it.next());
    console.log(it.next());
    // Symbol.iterator: 可遍历对象的生成方法

 ES语法扩展

我们一般不会直接使用iterator去遍历(Symbol.iterator->it->next())

遍历数组:for循环和forEach方法

遍历对象:for in循环 

console.log([][Symbol.iterator]());
    console.log({}[Symbol.iterator]);

ES语法扩展

for…of用法 

  • 与break、continue一起使用
  • 在for…of中取得数组的索引
  • for...of循环只会遍历出那些done为false时对应的value值
// 1.for...of循环本质
    const arr=[1,2,3];
    // const it=arr[Symbol.iterator]();
    // let next=it.next();
    // //console.log(next);
    // while (!next.done){
    //     console.log(next.value);
    //     next=it.next();
    // }

    for (const item of arr) {
        console.log(item);
    }
    // 2.用法
    // 在for...of获得索引
    // keys()得到的是索引的可遍历对象,可以遍历出索引值
    console.log(arr.keys());
    for (const key of arr.keys()) {
        console.log(key);
    }
    // values()得到的是值的可遍历对象,可以遍历出值
    console.log(arr.values());
    for (const value of arr.values()) {
        console.log(value);
    }
    // entries()得到的是索引+值组成的数组的可遍历对象
    for (const entries of arr.entries()) {
        console.log(entries);
    }
    // 解构赋值
    for (const [index, value] of arr.entries()) {
        console.log(index,value);
    }

ES语法扩展 

原生可遍历与非原生可遍历 

只要有Symbol.iterator方法,并且这个方法可以生成可遍历对象,就是可遍历的 

原生可遍历的有:数组、字符串、Set、Map、函数的arguments对象、NodeList 

非原生可遍历的有:一般的对象、有length和索引属性的对象

const person={
        sex:'male',
        age:18
    };
    person[Symbol.iterator]=()=>{
        let index=0;
        return{
            next(){
                index++;
                if (index===1){
                    return{
                        value:person.age,
                        done:false
                    }
                }else if (index===2){
                    return {
                        value: person.sex,
                        done: false
                    }
                }else {
                    return {
                        done: true
                    }
                }
            }
        }
    };
    for (const item of person) {
        console.log(item);
    }

ES语法扩展

const obj={
        0:'alex',
        1:'male',
        length:2
    };
    // obj[Symbol.iterator]=Array.prototype[Symbol.iterator];
    obj[Symbol.iterator]=()=>{
        let index=0;
        return{
            next(){
                let value,done;
                if (index<obj.length){
                    value=obj[index];
                    done=false;
                }else {
                    value=undefined;
                    done=true;
                }
                index++;
                return{
                    value,done
                }
            }
        }
    };
    for (const item of obj) {
        console.log(item);
    }

使用了Iterator的场合

对原生可遍历的:数组、字符串、Set、Map、函数的arguments对象、NodeList 

  • 数组的展开运算符
  • 数组的解构赋值
  • Set和Map的构造函数
// 1.数组的展开运算符
    console.log(...[1,2,3]);
    console.log(...'str');
    console.log(...new Set([1,2,3]));
    // 2.数组解构赋值(不需要结构匹配)
    // 形式:[...]
    console.log([...'hi']);
    const [a,b]='hi';
    // 相当于const [a,b]=[...'hi'];
    console.log(a,b);

 ES语法扩展