ES6笔记

ES6

1.环境搭建
nodejs
下载地址nodejs
2.ES6介绍
1)ES5的版本升级
2)提供了简介的语法和新的特性
迭代器,Map、Set,Promise,箭头函数,异步函数…
3)ES6在浏览器上的兼容性比ES5差一点,但是在nodejs环境下完全兼容
有些代码在浏览器上没有效果,比如模态化
在js中做ajax、dom时,必须将代码运行在浏览器上
3.基础语法
参考书籍 阮一峰 《ES6 入门教程》有在线文档,可以不用下载或者购买书籍,网站上即可进行自学。

1.let命令
	ES6新增了let命令,用来声明变量,用法类似于var
	{
	    var a = 1;
	}
	console.log(a);	//1
	{
	    let b = 1;
	    console.log(b);	//1
	}
	    console.log(b);	//报错
	JS中只有函数作用域和全局作用域,没有块级作用域,{}限定不了var声明变量的范围
	通过let声明的变量,只有在块级作用域中使用,类似于局部变量

	实例(vscode测试)
	var date = new Date();
    function getDate(){
        console.log(date);
        if(false){
            var date = 2020/05/18;	//变量提升了
            console.log(date);
        }
    }
    getDate();	//undefined

	-->

	var date = new Date();
    function getDate(){
        console.log(date);
        if(false){
            let date = 2020/05/18;
            console.log(date);
        }
    }
    getDate();	//当前时间

	特点:
		1.存在块级作用域
		2.不允许变量的重复声明
			var a = 1;
            var a = 2;
            console.log(a); // 2

            let b = 1;
            let b = 2;
            console.log(b); // 'b' has already been declared
		3.不允许变量的提升
			console.log(a); // undefined
            var a = 1;

            console.log(b); // b is not defined
            let b = 2;
			使用let关键字声明的变量,不可以在声明之前被使用,否则会报错
		4.暂时性死区
			var temp = '123';
	        if(true){
	            temp = 'abc';
	            let temp;
	        }
	        console.log(temp)	//报错
	        在判断体中,使用了let声明了一个temp局部变量,在这个变量声明之前,都不可以操作该变量,这个现象叫“暂时性死区”

2.const命令
	声明一个只读的常量。一旦声明,常量的值就不能改变
	const a = 1;
	console.log(a);	//1
	
	const a = 1;
	a++;
	console.log(a);	//报错:Missing initializer in const declaration
	
	在使用第三方库的时候,一般会使用const
	
	特点:
		1.存在块级作用域
		2.不允许变量的重复声明
		3.存在暂时性死区
		4.变量的声明和初始化要同时进行
			const a = 1;
			console.log(a);	//1
			
			const b;
			b = 2;
			console.log(b);	//报错
	总结:
            声明方式        变量提升        暂时性死区     重复声明        块级作用域
           	var            允许            不存在         允许           不存在
            let           不允许            存在         不允许           存在
           const          不允许            存在         不允许           存在

3.解构(模式匹配)
	ES6中,允许按照一定的模式,从数组或对象中提取值,并且对其进行一些操作(赋值......1.数组的解构
		ES6之前,赋值
		var name = 'xpf';
        var age = 25;
        var gender = 'male';
        console.log(name,age,gender);
        ES6后,赋值
        let [name,age,gender] = ['xpf',25,'male'];
        console.log(name,age,gender); // xpf 25 male
		只要等号两边的模式相同,左边的变量就会被赋予等号右边对应位置上的值
		let [age,name,gender] = ['xpf',25,'male'];
        console.log(name,age,gender); // 25 xpf male
    
    案例
        等号的左边模式个数等于于右边的
            let [,,gender] = ['xpf',25,'male'];
            console.log(gender); // male

            let [a,b,c] = [1,2,[3,4]];
            console.log(a,b,c); // 1 2 [3,4]

        等号的左边模式个数大于右边的
            let [name] = [];
            console.log(name); // undefined

        等号的左边模式个数小于右边的
            let [gender] = ['xpf',25,'male'];
            console.log(gender); // xpf

        等号两边的模式不相同
            let [gender] = 'xpf';
            console.log(gender); // x

            let [gender] = true;
            console.log(gender); // 报错,true不可迭代

            可遍历
                Array、String、Map、Set、函数的arguments对象
            不可遍历
                true/falseNaN、undefined、null{}
    2.数组解构默认值
    	结构的时候,允许指定默认值
    	
    	let [name='xpf'] = [];
        console.log(name); // xpf

        let [name='xpf'] = ['张三'];
        console.log(name); // 张三

        1、只有当数组对应位置上的值为undefined时,默认值才会生效
        let [name='xpf'] = [null];
        console.log(name); // null

        let [name='xpf'] = [undefined];
        console.log(name); // xpf

        2、默认值可以引用解构赋值的其他变量,但是这个变量必须已经声明过,否则会报错
        let [name,age,gender=name] = ['xpf',25];
        console.log(name,age,gender); // xpf 25 xpf

        let [name='xpf',name2=name] = [];
        console.log(name,name2); // xpf xpf

        let [name=name2,name2='xpf'] = [];
        console.log(name,name2); // 报错,name2未定义,无法在初始化之前访问到name2
    3.对象的解构
    	var obj = {
        	name:'xpf',
            age:25,
            gender:'male'
        }
        /*var name = obj.name;
        var age = obj.age;
        var gender = obj.gender;
        */

        let {name,age,gender} = obj;
        console.log(name,age,gender); // xpf 25 male

        对象的解构与数组的解构不同点:
           1、数组的元素是按顺序排列的,变量的取值由它的位置决定(根据索引一一对应取值)
             对象的属性没有次序,变量必须与属性名同名,才能取到正确的值,跟变量的位置没有关系

            等号左边变量的次序,与等号右边同名属性的次序不一样,对取值没有影响
            let {age,name,gender} = obj;
            console.log(name,age,gender); // xpf 25 male

            变量与属性名不同名(解构失败,变量的值为undefined)
            let {name,age,address} = obj;
            console.log(name,age,address); // xpf 25 undefined
           2、对象解构的内部机制
            let {name,age,gender:address} = obj;
            console.log(name,age,address); // xpf 25 male
            ==>等价于
            let {name:name,age:age,gender:address} = obj;
            console.log(name,age,address); // xpf 25 male
            
            let {name:name,age:age,gender:address} = obj;
            console.log(name,age,gender); // 报错,gender is not defined
    4.对象解构默认值
		var obj = {
            name:'xpf',
            age:25,
            gender:undefined
        }
        let {name,age,gender='male'} = obj;
        console.log(name,age,gender); // xpf 25 male

        ===> 等价于
        var obj = {
            name:'xpf',
            age:25
        }
        let {name,age,gender='male'} = obj;
        console.log(name,age,gender); // xpf 25 male

        只有当对象的属性值为undefined的时候,默认值才生效

        var obj = {
            name:'xpf',
            age:25,
            gender:'female'
        }
        let {name,age,gender='male'} = obj;
        console.log(name,age,gender); // xpf 25 female
	5.解构的用途
		1、交换两个变量的值
            let a = 1;
            let b = 2;
            let temp;

            temp = a;
            a = b;
            b = temp;
            console.log(a,b); // 2 1

            ===> 等价于
            let a = 1;
            let b = 2;
            [a,b] = [b,a];
            console.log(a,b); // 2 1
        
        2、让函数返回多个值
            function math(a,b){
                var sub = a-b;
                var add = a+b;
                return {sub,add}
            }

            let res = math(1,2);
            console.log(res); 
            console.log(res.sub); // -1
            console.log(res.add); // 3
            此时取值不方便

            说明:如果希望函数同时返回多个参数,我们可以将这几个参数放在一个数组或者对象中返回

            function math(a,b){
                var sub = a-b;
                var add = a+b;
                return [add,sub]
            }

            let [add,sub] = math(1,2);
            console.log(add,sub); // 3 -1

        3、在对象中快速取值
            var obj = {
                name:'xpf',
                age:25,
                gender:'male'
            }
            /*var name = obj.name;
            var age = obj.age;
            var gender = obj.gender;
            */

            let {name,age,gender} = obj;
            console.log(name,age,gender); // xpf 25 male

            ~~~~

            let obj = {
                name:'xpf',
                age:25,
                gender:'male',
                address:{
                    province:'安徽省',
                    city:'合肥市'
                }
            }

            //var city = obj.address.city;
            let {name,address:{city}} = obj;
            console.log(name,city); // xpf 合肥市

        4、函数参数的定义
            ES6之前,不能直接为函数的参数设定默认值

            function ajax({url,method='get',data,success}){
                console.log(url);
                console.log(method);
                console.log(data);
                console.log(success);
            }

            ajax({
                url:'www.baidu.com',
                success:function(){

                },
                data:{
                    name:'xpf'
                }
            })

            使用es6的解构传参,此时method有了一个默认值,为get
            1、不传递method的时候,为默认的get,传递了method的时候,为传递的值
            2、传递参数的时候,参数的顺序可以随便写

4.对象的扩展
	ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法
	1)对象属性的简写
		ES6之前写对象
		let name = 'jack';
		let obj = {
			name:name
		}
		console.log(obj.name);	//jack
		
		ES6的简写
		let name = 'jack';
		let obj = {
			name
		}
		console.log(obj.name);	//jack
		错误写法:
        let gender = 'xpf';
        let obj = {
            name
        }
        console.log(obj.name); // name is not defined
        
        对象的解构
        var obj = {
        	name:'jack',
        	age:20,
        	gender:'male'
        }
        let {name.age,gender} = obj;

		===>等价于
		let {name:name,age:age,gender:gender} = obj;
     2)对象方法的简写
     	ES6之前写对象的方法   
     	let obj = {
     		id:1,
     		name:'jack',
     		address:'湖南省',
     		sayAddress:function(){
				console.log('my address is',this.address);
			}
     	}
     	let {sayAddress} = obj;
     	obj.sayAddress();
     	console.log(sayAddress);	//my address is 湖南省
     	
     	ES6的简写
		let obj = {
     		id:1,
     		name:'jack',
     		address:'湖南省',
     		sayAddress(){
				console.log('my address is',this.address);
			}
     	}
     	let {sayAddress} = obj;
     	obj.sayAddress();
     	console.log(sayAddress);	//my address is 湖南省
	           
	    注意:
	    	对象中简写的方法不能够当作构造函数,否则会报错
	    	let obj = {
                id:1,
                name:'xpf',
                address:'安徽省',
                sayAddress(){
                    console.log('my address is',this.address);
                }
            }
            let {sayAddress} = obj;
            new sayAddress(); // sayAddress is not a constructor

	3)构造函数的扩展	Object.xxx
		var obj = new Object();
	    obj     实例
        Object  构造函数
        Object.prototype   构造函数的原型
		
		实例能够调用构造函数原型中的方法,但是无法调用构造函数中的方法
		
		1.Object.is(value1,value2)
			判断两个值是否相等
			var res1 = Object.is(1,1);
            var res2 = Object.is(1,'1');
            var res3 = Object.is('1','1');
            var res4 = Object.is({},{});
            var res5 = Object.is(+0,-0);
            var res6 = Object.is(NaN,NaN);

            console.log(res1); // true
            console.log(res2); // false
            console.log(res3); // true
            console.log(res4); // false
            console.log(res5); // false
            console.log(res6); // true=== 类似,会进行数据类型的比较,但是也有不同
                1NaN使用Object.is判断的时候,等于自身
                2+0-0使用Object.is判断时,不相等
                
		2.Object.assign(target,source1,source2...)
            将所有可枚举属性的值从一个或多个源对象复制到目标对象中,并且返回目标对象
	             可枚举:一般指用户自己写的属性,不包含继承的属性
	             源对象:source1,source2...
	             目标对象:target
	         1、合并对象
                let obj1 = {
                    id:1
                }
                let obj2 = {
                    name:'xpf'
                }
                let obj3 = {
                    gender:'male'
                }

                let obj = Object.assign(obj1,obj2,obj3);

                console.log('obj',obj); // { id: 1, name: 'xpf', gender: 'male' }
                console.log('obj1',obj1); // { id: 1, name: 'xpf', gender: 'male' }

                此时,obj1是目标对象,obj2和obj3是源对象
                合并后目标对象自身也会改变

                注意:当合并的对象具有相同的属性名时,属性会被源对象当中具有相同属性名的值覆盖掉
                    let obj1 = {
                        id:1
                    }
                    let obj2 = {
                        name:'xpf'
                    }
                    let obj3 = {
                        name:'male'
                    }
                    let obj = Object.assign(obj1,obj2,obj3);
                    console.log('obj',obj); // { name: 'male', id: 1 }

            2、复制对象(克隆)
                let obj1 = {
                    name:'tom',
                    age:13,
                    gender:'male'
                }

                let obj = Object.assign({},obj1);

                console.log(obj); // { name: 'tom', age: 13, gender: 'male' }
                console.log(obj1); // { name: 'tom', age: 13, gender: 'male' }
                console.log(obj == obj1); // false

                案例:
                一、当源对象中某一个属性值为对象时(即对象嵌套对象)
                    let obj1 = {
                        name:'tom',
                        address:{
                            province:'安徽省',
                            city:'合肥市'
                        }
                    }

                    let obj2 = {
                        name:'tom',
                        address:{
                            province:'江苏省'
                        }
                    }
                    let obj = Object.assign(obj1,obj2);

                    console.log(obj); // { name: 'tom', address: { province: '江苏省' } }
                    
                    并不会出现如下所期望的结果
                    address:{
                        province:'江苏省',
                        city:'合肥市'
                    }
                    也就是说,obj1中的address是被完全替换掉的,这个现象叫做浅拷贝,
                    如果需要实现深拷贝,可以使用JSON.stringify或者第三方库(lodash)

                    let obj1 = {
                        name:'tom',
                        address:{
                            province:'安徽省',
                            city:'合肥市'
                        }
                    }

                    let obj2 = obj1;
                    let obj3 = JSON.parse(JSON.stringify(obj1));
                    let obj4 = Object.assign({},obj1);

                    obj1.address.city = '苏州市';

                    console.log('obj1',obj1); // 苏州市
                    console.log('obj2',obj2); // 苏州市
                    console.log('obj3',obj3); // 合肥市
                    console.log('obj4',obj4); // 苏州市

                    注意:如果对象中包含方法,使用JSON.stringify时,该方法会丢失
                    let obj1 = {
                        name:'tom',
                        address:{
                            province:'安徽省',
                            city:'合肥市',
                            sayAddress(){
                                console.log(111);
                            }
                        }
                    }
                    let obj3 = JSON.parse(JSON.stringify(obj1));
                    console.log(obj3); // { name: 'tom', address: { province: '安徽省', city: '合肥市' } }

			3. Object.setPrototypeOf(obj,prototype)
	            将一个对象的原型(prototype)设置到另一个对象obj中
	        
	        4. Object.getPrototypeOf(obj)
	            获取一个对象的原型(prototype)
	            
	            function Person(name){
	                this.name = name;
	            }
	
	            Person.prototype.sayName = function(){
	                console.log('你好');
	            }
	
	            var p1 = new Person();
	            p1.sayName();
	
	            function Dog(){
	
	            }
	            //ES5解决方案:子构造函数的原型指向父构造函数的实例,需要在实例创建之前
	            //Dog.prototype = new Person();
	            var dog1 = new Dog();
	            //ES6解决方案:Object.setPrototypeOf
	            Object.setPrototypeOf(dog1,Person.prototype);
	            dog1.sayName();
	
	            var res = Object.getPrototypeOf(dog1);
	            console.log(res); // Person { sayName: [Function] }
	
	        5. Object.keys(obj)
	            键
	            返回一个对象obj的可枚举属性名组成的数组
	        6. Object.values(obj)
	            值
	            返回一个对象obj的可枚举属性值组成的数组
	        7. Object.entries(obj)
	            键值对
	            返回一个对象obj的可枚举属性的键值对数组
	        
	            let obj = {
	                name:'xpf',
	                age:25,
	                gender:'male'
	            }
	
	            console.log(Object.keys(obj)); // [ 'name', 'age', 'gender' ]
	            console.log(Object.values(obj)); // [ 'xpf', 25, 'male' ]
	            console.log(Object.entries(obj)); // [ [ 'name', 'xpf' ], [ 'age', 25 ], [ 'gender', 'male' ] ]
	        
	            用途:将一个对象转换为Map集合
	                let obj = {
	                    name:'xpf',
	                    age:25,
	                    gender:'male'
	                }
	
	                //let map = new Map(obj); // 直接放进去会报错
	                let map = new Map(Object.entries(obj));
	                console.log(map);

5、函数的扩展
    1) 函数简写
        1. 函数声明在对象中
            let obj = {
                name:'xpf',
                sayName:function(){
                    console.log(1);
                }
            }
            ===>等价于
            let obj = {
                name:'xpf',
                sayName(){
                    console.log(1);
                }
            }

        2. 函数声明在参数中(回调函数/匿名函数)
            forEach(function(){})
            setInterval(function(){},1000)

            ES6中允许使用箭头 => 定义函数  
                function(){}
                ===>等价于
                ()=>{}
            
            let fun1 = function(item){
                return item;
            }
            let fun2 = item => item;

            console.log(fun1);
            console.log(fun2);

            箭头函数可以根据参数个数来省略(),可以根据函数体内部代码的行数来省略{}
                一个参数时,可以省略()
                    item => {}
                不要参数或者多个参数时,不可以省略()
                    () => {}
                    (item,index) => {}

                函数体内部只有一行代码的时候,可以省略{}
                多行代码时,不可以省略{}

            案例一:
                let arr = [{
                    name:'xpf',
                    gender:'male'
                },{
                    name:'tom',
                    gender:'male'
                },{
                    name:'xiaohong',
                    gender:'female'
                }]

                let res1 = arr.filter(function(item){
                    return item.gender == 'female';
                })

                let res2 = arr.filter( (item)=>{
                    return item.gender == 'female';
                } )
                console.log(res1);
                console.log(res2);

            案例二:
                let obj = {
                    name:'xpf',
                    age:25,
                    sayName:()=>{
                        console.log(this.name);
                    },
                    sayAge:function(){
                        console.log(this.age);
                    }
                }
                obj.sayName(); // undefined
                obj.sayAge(); // 25

                注意:箭头函数中的this指向该箭头函数的外部函数
                    如果箭头函数外部没有函数,那么这个this就全局指向对象

            案例三:
                let obj = {
                    list:[1,2,3,4],
                    add(){
                        this.list.forEach(function(){
                            console.log(this.list); // undefined
                        })
                    }
                }
                obj.add();

                解决方案一:手动更改this
                    let obj = {
                        list:[1,2,3,4],
                        add(){
                            var that = this;
                            this.list.forEach(function(){
                                console.log(that.list)
                            })
                        }
                    }
                    obj.add();

                解决方案二:使用箭头函数
                    let obj = {
                        list:[1,2,3,4],
                        add(){
                            this.list.forEach(()=>{
                                console.log(this.list)
                            })
                        }
                    }
                    obj.add();

                    箭头函数的this先指向了外部的add函数,由于add函数被obj对象调用,所有add方法中的this指向了obj
                    最终,箭头函数中的this指向了obj

    2) 函数参数的默认值
        在ES6之前,一般无法为函数的参数提供默认值
            function sayName(name,age,gender){
                console.log(gender); // undefined
            }
            sayName(name,age)

            如何设置默认值?
                function person(name,age){
                    age = age || 15;
                    console.log(name,age);
                }
                person('xpf'); // xpf 15
                person('xpf',25); // xpf 25
                person('xpf',''); // xpf 15ES6时,可以使用解构给函数参数提供默认值
            function sayName({name,age,gender='male'}){
                console.log(gender); // male
            }
            sayName({})
        
        应用:
            1、ajax参数默认
            2、可以规定函数必须要传递某一个参数(即该参数不可省略)
                function throwErr(){
                    throw new Error('该参数不可被省略!')
                }

                function sayName({name = throwErr,age}){
                    console.log(name,age);
                }

                sayName({name:'xpf',age:25}); // xpf 25
                sayName({name:'xpf'}); // xpf undefined
                sayName({age:25}); // 抛出错误 25

	3)参数rest ...变量名
		1.函数参数中
            在ES6之前,函数的所有参数存放在arguments中
            function sayMsg(name,age,gender){
                console.log(name,age,gender);
                console.log(arguments,'---');
            }
            sayMsg('xpf',25,'male','安徽合肥');

            ...变量名,该变量是一个数组,该变量将函数多余的参数都存放在数组中,就不需要arguments对象了
            function sayMsg(...params){
                console.log(params); // [ 'xpf', 25, 'male', '安徽合肥' ]
            }
            sayMsg('xpf',25,'male','安徽合肥');

            function sayMsg(name,age,...params){
                console.log(name,age,params); // xpf 25 ['male','安徽合肥']
            }
            sayMsg('xpf',25,'male','安徽合肥');

            注意:rest参数后面,不可以再有其他参数,否则会报错
                function sayMsg(...params,name){}  // 这个代码是错误的
        
        2.在对象中 (剥离)
            let obj1 = {
                name:'xpf'
            }
            let obj2 = {
                age:25,
                gender:'male'
            }
            //如何将obj1与obj2合并?

            //let obj = {obj1,obj2};
            //console.log(obj);

            //obj1.other = obj2;
            //console.log(obj1);

            //Object.assign(obj1,obj2);
            //console.log(obj1);

            ///var obj = Object.assign({},obj1,obj2);
            //console.log(obj);

            let obj = {...obj1,...obj2};
            console.log(obj); // { name: 'xpf', age: 25, gender: 'male' }
        
        3.在vue中
            computed:{
                ...mapState('home',['article'])
            }

6、数组的扩展
	      1) Array.from(v)
	          用于将两类对象转换为真正的数组:类数组对象、可遍历对象(Set、Map)
	
	          数组的创建方式
	              1. 数组字面量
	                  var arr = [1,2,3];
	              2. Array构造函数
	                  var arr = new Array('a'); // ['a']
	              3. [...str]
	                  let str = 'hello';
	                  let arr = [...str]; // [ 'h', 'e', 'l', 'l', 'o' ]
	              4. Array.from(v)
	                  v表示类数组对象、可遍历对象
	
	                  1、类数组对象(DOM操作返回的NodeList集合、函数内部的arguments对象)
	                      ES5的写法:
	                          let arr_like = {
	                              "0":"xpf",
	                              "1":"male",
	                              length:2
	                          }
	                          let arr = Array.prototype.slice.call(arr_like);
	                          console.log(arr); // [ 'xpf', 'male' ]
	
	                      ES6的写法:
	                          let arr_like = {
	                              "0":"xpf",
	                              "1":"male",
	                              length:2
	                          }
	                          let arr = Array.from(arr_like);
	                          console.log(arr); // [ 'xpf', 'male' ]
	
	                  2、可遍历对象
	                      String
	                          let str = 'hello';
	                          let arr = Array.from(str); // [ 'h', 'e', 'l', 'l', 'o' ]
	                      Set
	                          let set = new Set([1,2,3,3,2,1]);
	                          let arr = Array.from(set); // [ 1, 2, 3 ]
	                      ...
	                      
	                  注意:
	                      1、如果参数为一个真正的数组,Array.from会返回一个一模一样的新数组
	                      2、任何包含lenght属性的对象,都可以通过Array.from方法转换为一个数组
	
	      2) Array.of()
	          为了弥补Array构造函数的不足,由于Array构造函数在传递一个数字类型的参数时,会出现与我们预期不一样的结果
	              Array构造函数
	                  let arr1 = new Array(1,3); // [1,3]
	                  let arr2 = new Array(3); // [ <3 empty items> ]
	              Array.of()
	                  let arr3 = Array.of(1,3); // [1,3]
	                  let arr4 = Array.of(3); // [3]
	              
	      3) find()与findIndex()
	          Array.prototype.find()
	              找出第一个满足条件的元素并返回,如果没有满足条件的元素时,返回undefined
	
	              let arr = [1,2,3,4];
	              let res = arr.filter((item)=>{
	                  return item < 3;
	              })
	              console.log(res); // [1,2]
	
	              let arr = [1,2,3,4];
	              let res = arr.find((item)=>{
	                  return item < 3;
	              })
	              console.log(res); // 1
	
	          Array.prototype.findIndex()
	              返回第一个满足条件的元素的索引,如果没有满足条件的元素时,返回-1
	
	              let arr = [1,2,3,4];
	              let res = arr.findIndex((item)=>{
	                  return item < 3;
	              })
	              console.log(res); // 0
	
	              let arr = [1,2,3,4];
	              let res = arr.findIndex((item)=>{
	                  return item < 1;
	              })
	              console.log(res); // -1
	
	              数组有一个 indexOf()方法,能够找到元素首次出现时的索引,可以用来实现数组的去重
	                  findIndex是为了弥补indexOf的不足
	
	                  let arr = [1,2,3,NaN];
	                  let res = arr.indexOf(NaN); // -1
	                  也就是说,indexOf方法无法找出数组中的NaN元素
	
	                  findIndex方法也不能直接找到NaN出现的位置,但是可以借助Object.is来实现
	                  let arr = [1,2,3,NaN];
	                  let res = arr.findIndex((item)=>{
	                      return Object.is(item,NaN);
	                  })
	                  console.log(res); // 3
	
	      4) fill()
	          Array.prototype.fill()
	          使用给定值,填充数组
	
	          一个参数
	              let arr = [1,2,3];
	              arr.fill(4);
	              console.log(arr); // [4,4,4]
	              数组中原本已存在的元素,会被全部替换掉
	
	          三个参数
	              第一个参数 :填充的数
	              第二个参数 :填充的起始位置
	              第三个参数 :填充的结束位置(不包含)
	              let arr = [1,2,3,4,5,6];
	              arr.fill(7,2,4);
	              console.log(arr); // [1,2,7,7,5,6]
	
	          注意:
	              1、如果被填充的数组为空,被填充后仍然是空数组
	                  let arr = [];
	                  arr.fill(1);
	                  console.log(arr); // []
	              2、如果填充的为对象,被赋值的只是同一个内存的指针
	                  let arr = new Array(3);
	                  arr.fill({name:'xpf'});
	                  console.log(arr); // [ { name: 'xpf' }, { name: 'xpf' }, { name: 'xpf' } ]
	                  arr[1].name = 'tom';
	                  console.log(arr); // [ { name: 'tom' }, { name: 'tom' }, { name: 'tom' } ]
	
	      5) keys、values、entries
	          这三个方法都用于数组的遍历,返回的都是一个遍历器对象(迭代器对象),该遍历器对象可用于for-of循环
	          Array.prototype.keys()
	              对键名的遍历
	          Array.prototype.values()
	              对键值的遍历
	          Array.prototype.entries()
	              对键值对的遍历
	
	          let arr = ['tom','larry','xpf'];
	          console.log(arr.keys()); // Object [Array Iterator] {}
	          console.log(arr.values()); // Object [Array Iterator] {}
	          console.log(arr.entries()); // Object [Array Iterator] {}
	
	          案例一:
	              let arr = ['xpf','tom','larry'];
	              /*ES5的写法:
	              for(let key in arr){
	                  console.log(arr[key]); // xpf tom larry
	              }
	              */
	
	              //ES6的写法:
	              let values = arr.values();
	              for(let item of values){
	                  console.log(item); // xpf tom larry
	              }
	
	              let entry = arr.entries();
	              for(let item of entry){
	                  console.log(item,'---');
	              }
	
	          案例二:
	              let arr = ['xpf','tom','larry'];
	              let iterator = arr.values();
	              console.log(iterator.next()); // { value: 'xpf', done: false }
	              console.log(iterator.next()); // { value: 'tom', done: false }
	              console.log(iterator.next()); // { value: 'larry', done: false }
	              console.log(iterator.next()); // { value: undefined, done: true }
	
	              在遍历器对象中,提供一个next()方法,该方法会返回一个对象,表示当前数组的元素
	              value属性返回当前位置的元素
	              done属性是一个布尔值,表示遍历是否结束(即是否有必要再调用next方法)
	
	          案例三:
	              let arr = ['xpf','tom','larry];
	
	              //方法一
	              let value_iterator = arr.values();
	              let item;
	              while(!(item = value_iterator.next()).done){
	                  console.log(item.value); // xpf tom larry
	              }
	
	              //方法二
	              let values = arr.values();
	              for(let item of values){
	                  console.log(item); // xpf tom larry
	              }
	
	              //方法三
	              for(let key in arr){
	                  console.log(arr[key]); // xpf tom larry
	              }
	      
	      6) includes()
	          Array.prototype.includes()
	          表示数组是否包含给定的值,如果包含,返回true,否则返回false
	
	          includes是为了弥补indexOf方法的不足
	              1、不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观
	              2、它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判
	
	              let arr = [1,2,3,NaN];
	              console.log(arr.indexOf(NaN)); // -1
	              console.log(arr.includes(NaN)); // true
	              console.log(arr.includes(4)); // false

7、Set、Map集合
        1) Set集合
            类似于数组,但是成员的值都是唯一,不可重复

            1. 定义方式:Set构造函数
                let set = new Set();
                console.log(set); // Set {}  在浏览器中会显示一个[]

            2. 初始化:Set构造函数的参数必须为可遍历的数据
                let set1 = new Set(1);
                console.log(set1); // 1 is not iterable

                let set2 = new Set([1,2,3]);
                console.log(set2); // Set { 1, 2, 3 }
                
                let set3 = new Set('hello');
                console.log(set3); // Set { 'h', 'e', 'l', 'o' }

                也可以使用Set集合中的add()方法
                    let set = new Set();
                    let arr = [1,2,3,4];
                    arr.forEach((item)=>{
                        set.add(item);
                    })
                    console.log(set); // Set { 1, 2, 3, 4 }
                    
                    对比数组的push方法记忆
            
            3. 特点:
                1、Set构造函数的参数必须为可遍历的数据
                2、Set集合不会含有重复的值
                    let set = new Set([1,2,3,3,2,1]);
                    console.log(set); // Set { 1, 2, 3 }
            
            4. Set实例的属性
                Set.prototype.size
                    返回Set集合的所有成员总数
                    let set = new Set([1,2,3,3,2,1]);
                    console.log(set); // Set { 1, 2, 3 }
                    console.log(set.size); // 3

                Set.prototype.constructor
                    构造函数,也就是Set函数
                    let set = new Set([1,2,3,3,2,1]);
                    console.log(set.constructor); // [Function: Set]

            5. Set实例的方法
                Set.prototype.add(value)
                    向Set集合添加某个值,返回添加完值之后的Set集合
                    let set = new Set([1,2,3,3,2,1]);
                    set.add(4);
                    console.log(set); // Set { 1, 2, 3, 4 }

                Set.prototype.delete(value)
                    删除Set集合中的某个值,删除成功时返回true,否则返回false
                    let set = new Set([1,2,3,3,2,1]);
                    let res = set.delete(3);
                    console.log(res); // true
                    let res1 = set.delete(3);
                    console.log(res1); // false

                    注意:在浏览器下,返回被删除值之后的Set集合
                
                Set.prototype.has(value)
                    表示某个值是否属于Set集合,如果属于返回true,否则返回false
                    let set = new Set([1,2,3,3,2,1]);
                    let res = set.has(3);
                    console.log(res); // true
                    let res1 = set.has(4);
                    console.log(res1); // false
                
                Set.prototype.clear()
                    清空Set集合中所有的成员
                    let set = new Set([1,2,3,3,2,1]);
                    set.clear();
                    console.log(set); // Set {}

                Set.prototype.keys()
                    键名的遍历器
                Set.prototype.values()
                    键值的遍历器
                Set.prototype.entries()
                    键值对的遍历器

                Set集合中没有键名,只有键值(键名和键值是同一个值),所以keys方法和values方法行为完全一致
                    let set = new Set(['tom','larry','xpf']);
                    //值的遍历器对象
                    let value_iterator = set.values();
                    //键的遍历器对象
                    let key_iterator = set.keys();

                    for(let val of value_iterator){
                        console.log(val); // tom larry xpf
                    }

                    for(let key of key_iterator){
                        console.log(key); // tom larry xpf
                    }


                Set集合的实例默认可遍历,因为它的默认遍历器生成函数就是它values方法

                let set = new Set([1,2,3,4]);
                console.log(Set.prototype)
                console.log(Set.prototype[Symbol.iterator])
                console.log(Set.prototype.values)
                console.log(Set.prototype[Symbol.iterator] === Set.prototype.values) // true

                任何部署了iterator接口的数据,都可以完成遍历操作
                let set = new Set(['tom','larry','xpf']);
                for(let val of set){
                    console.log(val);
                }
			6.应用
				1. 将Set集合转换为数组 --> Array.from()
                let set = new Set([1,2,3,4]);
                console.log(set); // Set { 1, 2, 3, 4 }

                let arr = Array.from(set);
                console.log(arr); // [1,2,3,4]
            
	            2. 数组的去重
	                方法一:
			    indexOf
				let arr = [1,2,3,3,2,1];
				let newArr = [];
				for(let i = 0;i<arr.length;i++){
				    if(newArr.indexOf(arr[i])==-1){
					newArr.push(arr[i])
				    }
				}
				console.log(newArr);
	                方法二:
	                    function myFun(arr){
	                        let set = new Set(arr);
	                        let array = Array.from(set);
	                        return array;
	                    }
	                    let arr = [1,2,3,3,2,1];
	                    let newArr = myFun(arr);
	                    console.log(newArr); // [1,2,3]
	
	                    ===>简化
	
	                    function myFun(arr){
	                        return Array.from(new Set(arr));
	                    }
	
	                    let arr = [1,2,3,3,2,1];
	                    let newArr = myFun(arr);
	                    console.log(newArr); // [1,2,3]
	
	            3.(拓展) 对Set集合中的元素做一些操作后返回(加减乘除) map
	                let arr = [1,2,3,4];
	                let newArr = arr.map((item)=>{
	                    return item*2;
	                });
	                console.log(newArr); // [2,4,6,8]set集合中实现上述效果
	
	                方法一:
	                    let set = new Set([1,2,3,4]);
	                    let arr = Array.from(set,(item)=>{
	                        return item*2;
	                    })
	                    var newSet = new Set(arr);
	                    console.log(newSet); // Set { 2, 4, 6, 8 }
	
	                方法二:
	                    let set = new Set([1,2,3,4]);
	                    //通过扩展运算符将set集合转换为数组
	                    let arr = [...set];
	                    let res = arr.map((item)=>{
	                        return item*2;
	                    })
	                    let newSet = new Set(res);
	                    console.log(newSet); // Set { 2, 4, 6, 8 }
		2)Map集合
			JavaScript 的对象,本质上是键值对的集合,但是传统上只能用字符串当作键。这给它的使用带来了很大的限制
        为了解决这一局限性,ES6引入了Map集合

	        1) 定义方式:Map构造函数
	            let map = new Map();
	            console.log(map); // Map {}
	
	        2) 初始化:接受一个数组作为参数。该数组的成员是一个个表示键值对的数组
	            let map = new Map([
	                ['name','xpf'],
	                ['gender','male']
	            ]);
	            console.log(map); // Map { 'name' => 'xpf', 'gender' => 'male' }
	
	            还可以通过set方法向Map集合中设置键值对
	            let map = new Map();
	            map.set('name','xpf');
	            map.set('gender','male');
	            console.log(map); // Map { 'name' => 'xpf', 'gender' => 'male' }
	
	        3) 特点
	            1. 类似于对象,也是键值对的集合
	            2. Object结构提供了'字符串—值'的对应,Map结构提供了'值—值'的对应
	                即Map集合的键不仅仅局限于字符串了
	        
	        4) Map集合的属性
	            Map.prototype.size
	                返回Map集合的成员总数
	
	                let map = new Map();
	                map.set('name','xpf');
	                map.set('gender','male');
	                console.log(map.size); // 2
	
	        5) Map集合的方法
	            Map.prototype.set(key,value)
	                设置键值对,键名为key,键值为value,返回Map集合
	            Map.prototype.get(key)
	                获取key对应的键值,如果找不到,返回undefined
	
	                let map = new Map();
	                map.set('str',1); 
	                map.set(2,1); 
	                map.set(undefined,1); 
	                map.set(function(){},1); 
	
	                如果键名已存在,则键值会更新,否则就会就会生成新的键
	                map.set(2,5);  // {2 => 5}
	
	                console.log(map.get('str')); // 1
	                console.log(map.get('str123')); // undefined
	            
	            Map.prototype.has(key)
	                表示某个键是否属于Map集合,属于时返回true
	            Map.prototype.delete(key)
	                删除某个键,删除成功时返回true
	            Map.prototype.clear()
	                清空Map集合
	            Map.prototype.keys()
	            Map.prototype.values()
	            Map.prototype.entries()
	            Map.prototype.forEach()
	                遍历Map集合中的所有成员
	        
	        6) 应用
	            1. Map集合转换为数组
	                let map = new Map([
	                    [1,2],
	                    [2,3],
	                    [3,4]
	                ]);
	                console.log(map); // { 1 => 2, 2 => 3, 3 => 4 }
	
	                方法一:通过Array.from()
	                    let arr = Array.from(map);
	                    console.log(arr); // [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ]
	
	                方法二:...
	                    let map = new Map([
	                        [1,2],
	                        [2,3],
	                        [3,4]
	                    ]);
	                    console.log(map); // { 1 => 2, 2 => 3, 3 => 4 }
	                    let arr = [...map];
	                    console.log(arr); // [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ] ]
	            
	            2. 对象转换为Map集合
	                思路:
	                    Map构造函数的参数需要是二维数组
	                    ->
	                    如何将普通对象转换为二维数组的形式?
	                    ->
	                    Object.entries()可以拿到对象的键值对组成的数组
	                    ->
	                    作为参数传递给new Map();
	                    ->
	                    实现对象转Map集合
	                实现代码:
	                    let obj = {
	                        name:'xpf',
	                        age:25,
	                        gender:'male'
	                    }
	                    let entry = Object.entries(obj);
	                    let map = new Map(entry);
	                    console.log(map);
	            
	            3. 购物车
	                // 1. 初始化购物车
	                let shopCar = new Map();
	
	                // 2. 初始化商品
	                let product_one = {
	                    productId:1,
	                    productName:'雪碧',
	                    productPrice:4.5,
	                    number:1
	                }
	                let product_two = {
	                    productId:2,
	                    productName:'可乐',
	                    productPrice:4.0,
	                    number:1
	                }
	                // 3. 初始化添加至购物车事件
	                function addShopCar(item){
	                    console.log(item,'----');
	                    // 判断该商品是否已经存在于购物车
	                    // 如果有该id,说明已经存在该商品,只需要将该商品的数量改变即可
	                    if(shopCar.has(item.productId)){
	                        shopCar.get(item.productId).number += item.number;
	                    } else {
	                        shopCar.set(item.productId,item);
	                    }
	                }
	                // 4. 购买雪碧
	                addShopCar(product_one);
	                //addShopCar(product_one);
	                //addShopCar(product_one);
	                //addShopCar(product_one);
	                // 再次购买雪碧
	                addShopCar({productId:1,productName:'雪碧',productPrice:4.5,number:3});
	                addShopCar({productId:1,productName:'雪碧',productPrice:4.5,number:1});
	                // 购买可乐
	                addShopCar(product_two);
	
	                console.log(shopCar);
		
		3(拓展)Iterator(遍历器)
	        1) 介绍
	            数组、对象、Map和Set四种数据结构,需要一种统一的访问机制
	            遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
	            任何数据结构只要部署 Iterator 接口,就可以完成遍历操作。
	
	        2) 作用
	            1. 为各种数据结构提供统一的访问接口
	            2. 使得数据结构的成员能够按某种次序排列
	            3. Iterator接口可以用于for-of循环
	
	        3) next()方法
	            在遍历器对象Iterator中,有一个next方法,该方法会返回一个对象,对象中有两个属性value、done
	            let arr = ['xpf','tom','larry'];
	            let iterator = arr.values();
	            console.log(iterator.next()); // xpf
	            console.log(iterator.next()); // tom
	            console.log(iterator.next()); // larry
	            console.log(iterator.next()); // undefined
	        
	        4) 向类数组对象中添加遍历器
	            获取数组中的values方法
	                console.log(Array.prototype[Symbol.iterator])
	                console.log([][Symbol.iterator])
	
	            let arr_like = {
	                "0":"xpf",
	                "1":"25",
	                "2":"male",
	                length:3,
	                [Symbol.iterator]:[][Symbol.iterator]
	            }
	            console.log(arr_like);
	            for(let val of arr_like){
	                console.log(val);
	            }
	
	            function sayName(a,b){
	                console.log(arguments,'--')
	                for(let arg of arguments){
	                    console.log(arg)
	                }
	            }
	            sayName('xpf','male',25);
	        
	        注意:
	            1. 对于一般对象,就算添加了遍历器接口,也没有效果(不会报错,但是使用for-of遍历出来的值为undefined)
	                let obj = {
	                    name:'xpf',
	                    age:25,
	                    gender:'male',
	                    length:3,
	                    [Symbol.iterator]:[][Symbol.iterator]
	                }
	                for(let val of arr_like){
	                    console.log(val); // undefined undefined undefined
	                }
	                
	            2. Symbol是一个新的数据类型,表示独一无二的值,是第七种数据类型
	                undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)
	
	                let s = Symbol();
	                console.log(s); // Symbol()
	                console.log(typeof s); // 'symbol'
	
	                注意:
	                    1、Symbol函数不可以使用new关键字,否则会报错
	                    2、通过Symbol创建出来的变量,是独一无二的,这个变量可以用于向对象中添加一个属性,而不影响其他已存在的属性(即不会出现覆盖的情况)
	
	                    向对象中添加symbol
	                        let obj = {
	                            name:'xpf',
	                            age:25,
	                            gender:'male'
	                        }
	                        let symbol1 = Symbol('province');
	                        let symbol2 = Symbol('city');
	                        let symbol3 = Symbol('city');
	                        obj[symbol1] = '安徽';
	                        obj[symbol2] = '合肥';
	                        obj[symbol3] = '苏州';
	                        console.log(obj);
	                        console.log(obj.city); // undefined
	                        console.log(obj['city']); // undefined
	                        console.log(Object.getOwnPropertySymbols(obj));
	
	                        Object.getOwnPropertySymbols(obj)用于获取对象中所有通过symbol添加的属性名
	            
	            3. 获取遍历器
	                数组的遍历器对象
	                    Array.prototype[Symbol.iterator]
	                    [][Symbol.iterator]
	                类数组对象的遍历器对象
	                    arguments[Symbol.iterator]
	
	                    function sayName(a,b,c){
	                        let i = arguments[Symbol.iterator]();
	                        for(let item of i){
	                            console.log(item)
	                        }
	                    }
	                    sayName(1,2,3);
	                    ===>等价于
	                    function sayName(a,b){
	                        console.log(arguments,'--')
	                        for(let arg of arguments){
	                            console.log(arg)
	                        }
	                    }
	                    sayName('xpf','male',25);
	                Set
	                    let set = new Set();
	                    set[Symbol.iterator]
		
8.Promise对象
9.(拓展)Generator函数
10.****async函数 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值