ES 6学习笔记

目录

本次笔记的视频教程:腾讯课堂

1、let:

2、const(常量)特性和let一样

3、数组不可修改,可以使用freeze方法

4、解构赋值 (非常有用,特别在做数据交互,ajax)

5、字符串模板:

6、函数

函数新变化

7、数组

8、对象

9、promise

10、模块化

11、类和继承

12、Symbol & generator

13、async、await

14、Set和WeakSet

15、Map和WeakMap

16、数字新增和Math新增的

17、ES2018(ES9)新增

18、Proxy的使用(非常非常有用,但不常用)

19、Reflect的使用

20、补充


本次笔记的视频教程:腾讯课堂

1、let:

  1. 没有预解析,不存在变量提升(未定义使用会报错)

    var a=12;
    function a(){
      console.log(a);
      let a=5;
    }
    a();
    //输出报错,Uncaught TypeError: a is not a function
  2. 同一作用域不能重复定义变量

    let a=12;
    
    
    
    
    let a=5;
    console.log(a);
    //输出报错:Uncaught SyntaxError: Identifier 'a' has already been declared
  3. for循环,for循环里面是父级作用域,里面又一个

    for(let i=0;i<2;i++){
      let i='abc';
      console.log(i);
    }
    console.log(i);
    //1、for循环里面的i输出两次‘abc’
    //2、for循环外面的i会报错,Uncaught ReferenceError: i is not defined

2、const(常量)特性和let一样

  1. 定义变量不允许修改

    const a=123;
    let a=456;
    console.log(a);
    //输出报错:Uncaught SyntaxError: Identifier 'a' has already been declared
  2. 定义变量后必须有值,不能之后修改

    const a
    console.log(a);
    //输出报错:Uncaught SyntaxError: Missing initializer in const declaration
    const a
    a=12;
    console.log(a);
    //输出报错:Uncaught SyntaxError: Missing initializer in const declaration
  3. 数组等引用类型,可以通过本身的方法修改

    const arr=['apple','banana'];
    arr=[];
    console.log(arr);
    //输出报错:Uncaught TypeError: Assignment to constant variable
    const arr=['apple','banana'];
    arr.push('orange');
    console.log(arr);
    //输出["apple", "banana", "orange"]
  4. 应用场景:

    const http=require('http');

3、数组不可修改,可以使用freeze方法

const arr=Object.freeze(['apple','banana']);
arr.push('orange');
console.log(arr);
//输出报错:Uncaught TypeError: Cannot add property 2, object is not extensible

4、解构赋值 (非常有用,特别在做数据交互,ajax)

  1. 解构赋值
    let [a,b,c]=[10,12,15];
    console.log(a,b,c);
    //输出:10 12 15
  2. 左右两边,结构保持一致
    /*
    *  结构不一致
    */
    let [a,b,c]=[10,[12,15]];
    console.log(a,b,c);
    //输出:10 (2) [12, 15] undefined
    /*
    *  结构一致
    */
    let [a,[b,c]]=[10,[12,15]];
    console.log(a,b,c);
    //输出:10 12 15
  3. json
    let json={
      name:'xxx',
      age:18,
    }
    let{name,age}=json;
    console.log(name,age);
    //输出:xxx 18
  4. 可以起别名
    let json={
      name:'xxx',
      age:18,
    }
    let{name:n,age:a}=json;
    console.log(n,a);
    //输出:xxx 18
  5. 可以给默认值
    let [a,b,c]=['aa','bb'];
    console.log(a,b,c);
    //输出:aa bb undefined
    let [d,e,f='暂无数据']=['aa','bb'];
    console.log(d,e,f);
    //输出:aa bb 暂无数据
    let [j,h,k='暂无数据']=['aa','bb','cc'];
    console.log(j,h,k);
    //输出:aa bb cc
    let [i,g,l='暂无数据']=['aa','bb',null];
    console.log(i,g,l);
    //当对应的值为null时,输出:aa bb null
    //可以增加判断
    let [i,g,l='暂无数据']=['aa','bb',null];
    console.log(i,g,(l==null?'暂无数据':l));
    //输出:aa bb 暂无数据
  6. 可以交互两个数的值
    let a=15;
    let b=2;
    [a,b]=[b,a];
    console.log(a,b);
    //输出:2 15

5、字符串模板:

  1. 字符串模板:``,优点:1、可以随意换行2、${变量名称}
    let name='xxx';
    let age=16;
    let person=`我叫${name},年龄是${age}`;
    console.log(person);
    //输出:我叫xxx,年龄是16
  2. 字符串查找:includes()返回true或false
    let str='apple banana pear';
    console.log(str.includes('apple'));
    //输出:true
    //可以用来判断浏览器
    if(navigator.userAgent.includes('Chrome')){
    	console.log('yes');
    }else{
    	console.log('no');
    }
    //谷歌浏览器,输出yes
    //火狐浏览器,输出:no
    //360浏览器,输出:yes,以上判断对于双核浏览器不怎么有用
  3. 检测字符串以谁开头:startsWith();检测字符串以谁结尾:endsWith()
    let str='aaaa.png';
    console.log(str.startsWith('a'),1);
    //true 1
    console.log(str.startsWith('b'),2);
    //false 2
    console.log(str.endsWith('png'),3);
    //true 3
    console.log(str.endsWith('jpg'),4);
    //false 4
  4. 重复次数:repeat(次数)
    let str='我是lxq';
    console.log(str.repeat(2),1);
    //输出:我是lxq我是lxq 1
  5. 填充字符串:padStart(整个字符串长度,'填充内容');padEnd(整个字符串长度,'填充内容')
    let str='我是';
    let padStr='你好';
    let padEnd='lxq';
    console.log(str.padStart(padStr.length+str.length,padStr),2);
    //输出:你好我是 2
    console.log(str.padEnd(padEnd.length+str.length,padEnd),3);
    //我是lxq 3

6、函数

函数新变化

  1. 函数可以有默认参数
    /*无默认值*/
    function show(a,b){
    		console.log(a,b);
    }
    show('xx',2);
    //输出:xx 2
    show('xx','');
    //输出:xx
    show('xx');
    //输出:xx undefined
    show( ,2);
    //输出报错:Uncaught SyntaxError: Unexpected token ,
    show('',2);
    //输出:空格 2
    /*有默认值*/
    function show(a='wo',b=1){
        console.log(a,b);
    }
    show('xx',2);
    //输出:xx 2
    show('xx','');
    //输出:xx
    show('xx');
    //输出:xx 1
    show( ,2);
    //输出报错:Uncaught SyntaxError: Unexpected token ,
    show('',2);
    //输出:空格 2
  2. 函数参数默认已经定义,不能使用let,const声明
    function show(a=18){
        let a=101;
        // var a=101;
        console.log(a);
    }
    show();
    //输出报错:Uncaught SyntaxError: Identifier 'a' has already been declared
    //可以使用var 声明,但是会引起作用域的问题
  3. 扩展运算符、reset运算符('...':展开数组)
    let arr=['apple','banana','cx'];
    console.log(arr);
    //输出:(3) ["apple", "banana", "cx"]
    console.log(...arr);
    //输出:apple banana cx
    /*在函数中的应用*/
    function show(...a){
        console.log(a);
    }
    show(1,2,3,4,5);
    //输出:[1, 2, 3, 4, 5]
    /*在函数中的应用*/
    function show(...a){
        console.log(a.sort());
    }
    show(9,8,3,4,5);
    //输出:[3, 4, 5, 8, 9]
    /*在函数中的应用*/
    function show(a,b,c){
    	console.log(a,b,c);
    }
    show(...[1,2,3]);
    //输出:1 2 3
    /*在函数中的应用,剩余运算符必须放在最后一个参数*/
    function show(a,b,...c){
    	console.log(a,b);
    	console.log(c);
    }
    show(1,2,3,4,5);
    //输出:1 2
    //输出:(3) [3, 4, 5]
  4. 箭头函数
    /*
     *   箭头函数
     *   let show=()=>1此种形式实用性不高,箭头左边(变量),箭头右边相当于return返回值
    */
    let show=()=>1;
    console.log(show());
    //输出:1
    let show=(a,b)=>a+b;
    console.log(show(12,5));
    //输出:17
    let show=(a,b)=>{
    	console.log(a,b,a+b);
    	return a+b;
    };
    show(12,5);
    //输出:12 5 17
    注意事项:箭头函数可以改变this指向,没有arguments,不能当构造函数
    /*
    *    1、箭头函数可以改变this指向
    *    this:定义函数所在的对象,不在是运行时所在的对象
    */
    var id=1;
    var j={
    	id:21,
    	show:function(){
    		setTimeout(function(){
    		console.log(this.id);
    	    },2000);			
    	}
    }
    j.show();
    //输出:1
    var id=1;
    var j={
    	id:21,
    	show:function(){
    		    setTimeout(()=>{
    		    console.log(this.id);
    		},2000);			
    	}
    }
    j.show();
    //输出:21
    /*
    *    2、箭头函数没有arguments
    *   解决方法:使用'...'+参数,我在此处仍然使用了arguments
    */
    function show(){
    	console.log(arguments);
    }
    show(1,2,3,4,5);
    //输出:Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    let show=()=>{
    	console.log(arguments);
    }
    show(1,2,3,4,5);
    //输出:js.html:15 Uncaught ReferenceError: arguments is not defined
    let show=(...argument)=>{
    	console.log(argument);
    }
    show(1,2,3,4,5);
    //输出:(5) [1, 2, 3, 4, 5]
    /*
    *    3、箭头函数不能当构造函数
    */
    function show(){
        this.name='abc';
    }
    let s=new show();
    console.log(s.name);
    //输出:abc
    let show=()=>{
    	this.name='abc';
    }
    let s=new show();
    console.log(s.name);
    //输出:Uncaught TypeError: show is not a constructor
  5. ES2017(ES8)规定:函数参数最后的逗号可以有
    function show(a,b,c,d,){
    	console.log(a,b,c,d);
    }
    show(1,2,3,4,);
    //输出:1 2 3 4

7、数组

  • 数组循环:
  1. 常用for、while
  2. ES5新增循环:数组方面forEach、map、filter、some、every、reduce、reduceRight
    /*
    *    forEach(无返回值,方法最后输出undefined)
    *    1、不指定this
    */
    let arrary=['a','b'];
    let newArrary=arrary.forEach(function(val,index,arrary){
    	console.log(this,val,index,arrary);
    });
    console.log(newArrary);
    //输出1:Window "a" 0 (2) ["a", "b"]
    //输出2:Window "b" 1 (2) ["a", "b"]
    //输出3:undefined
    /*指定this,不经常用*/
    let arrary=['a','b'];
    	arrary.forEach(function(val,index,arrary){
    	console.log(this,val,index,arrary);
    },123);
    //输出1:Number {123} "a" 0 (2) ["a", "b"]
    //输出2:Number {123} "b" 1 (2) ["a", "b"]
    /*
    *    还可以使用箭头函数
    *    使用箭头函数后,第二个参数this的指向就不生效了
    */
    let arrary=['a','b'];
    	arrary.forEach((val,index,arrary)=>{
    	console.log(this,val,index,arrary);
    });
    //输出1:Window "a" 0 (2) ["a", "b"]
    //输出2:Window "b" 1 (2) ["a", "b"]
    let arrary=['a','b'];
    	arrary.forEach((val,index,arrary)=>{
    	console.log(this,val,index,arrary);
    },123);
    //输出1:Window "a" 0 (2) ["a", "b"]
    //输出2:Window "b" 1 (2) ["a", "b"]
    
    
    /*
    *	map:非常有用,可以做数据交互"映射"
    *	正常情况下,需要配合return,返回的是一个新数组,否则与forEach无异
    *	没有返回值,会返回[undefined, undefined, undefined]
    */
    let arr=[
    	{'title':'aaa',num:12},
    	{'title':'bbb',num:13},
    	{'title':'ccc',num:14}
    ];
    let newArr=arr.map((val,index,arr)=>{
    	console.log(val,index,arr);
        //没有返回值,会返回[undefined, undefined, undefined]
    });
    console.log(newArr);
    //输出: [undefined, undefined, undefined]
    /*
    *	map:非常有用,可以做数据交互"映射"
    *	有返回值,会返回一个新数组
    */
    let arr=[
    	{'title':'aaa',num:12,hot:true},
    	{'title':'bbb',num:13,hot:false},
    ];
    let newArr=arr.map((val,index,arr)=>{
    	let obj={};
    	obj.t=val.title;
    	obj.n=val.num;
    	obj.h=val.hot==true&&'good!';
    	return obj;
    });
    console.log(newArr);
    //输出:(3) [{…}, {…}]
    //展开1:0: {t: "aaa", n: 12, h: "good!"}
    //展开2:1: {t: "bbb", n: 13, h: false}
    /*
    *	filter:过滤,过滤一些不合格元素,如果回调函数返回true
    */
    let arr=[
    	{'title':'aaa',num:12,hot:true},
    	{'title':'bbb',num:18,hot:false},
    	{'title':'ccc',num:11,hot:true},
    	{'title':'ddd',num:18,hot:false},
    ];
    let newArr=arr.filter((val,index,arr)=>{
    	return !val.hot;
    });
    console.log(newArr);
    //输出:(2) [{…}, {…}]
    //展开1:0: {title: "bbb", num: 18, hot: false}
    //展开2: 1:{title: "ddd", num: 18, hot: false}
    /*
    *    some:类似查找,数组里面某一个元素符合条件,返回true
    *    every:要数组里面的所有元素都符合条件,才返回true
    */
    let arr=['a','xx','c'];
    let newArr=arr.some((val,index,arr)=>{
    	return val==='xx';
    });
    console.log(newArr);
    //输出:true
    let arr=['a','xx','c'];
    let newArr=arr.some((val,index,arr)=>{
    	return val==='x';
    });
    console.log(newArr);
    //输出:false
    /*every*/
    let arr=[1,3,5,7];
    	let newArr=arr.every((val,index,arr)=>{
    	return val%2==1;
    });
    console.log(newArr);
    //输出:true
    let arr=[1,3,5,7,10];
    	let newArr=arr.every((val,index,arr)=>{
    	return val%2==1;
    });
    console.log(newArr);
    //输出:false
    
    /*
    *	reduce接收参数('前一个值','当前值','当前索引','循环数组'),从左往右计算
    *	reduceRight 从右往左计算
    */
    let arr=[1,3,5,7];
    	let newArr=arr.reduce((prev,cur,index,arr)=>{
    	return prev+cur;
    });
    console.log(newArr);
    //输出:16
    let arr=[2,2,3];
    let newArr=arr.reduce((prev,cur,index,arr)=>{
    	return Math.pow(prev,cur);
    	//ES2017新增求幂的运算符
    	// return Math.pow(2,3);//输出:8
    	// return 2**3;			//输出:8
    });
    console.log(newArr);
    //输出:64
    /*reduceRight*/
    let arr=[2,2,3];
    let newArr=arr.reduceRight((prev,cur,index,arr)=>{
    	return Math.pow(prev,cur);
    });
    console.log(newArr);
    //输出:81
  • ES6 数组新增
  1. for...of...循环
    /*
    *	for...of...循环
    */
    let arr=['a','b'];
    //默认循环 arr.values()可不写,直接写成for(let val of arr){}
    for(let val of arr.values()){
    	console.log(val);
    }
    //输出:a,b
    for(let index of arr.keys()){
    	console.log(index);
    }
    //输出:0,1
    for(let item of arr.entries()){
    	console.log(item);
    }
    //输出1:(2) [0, "a"]
    //输出2:(2) [1, "b"]
    for(let [key,val] of arr.entries()){
    	console.log(key,val);
    }
    //输出1:0 "a"
    //输出2:1 "b"
  2. from Array.from()作用:将类数组对象转成数组
    /*
    *	Array.from()
    *	作用:将类数组对象转成数组
    */
    show(1,2,3,4);
    function show(a,b,c,d){
    	console.log(arguments,'类数组');
    	//输出:Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ] "类数组"
    	let arr=Array.from(arguments);
    	console.log(arr,'from后');
        //输出:(4) [1, 2, 3, 4] "from后"
    	let arr2=[...arguments];
    	console.log(arr2,'...后');
    	//(4) [1, 2, 3, 4] "...后"
    }
  3. of Array.of()作用:把一组值,转成数组
    let arr3=Array.of('aa','bb','cc');
    console.log(arr3);
    //输出:["aa", "bb", "cc"]
  4. find\findIndex:查找\查找位置
    /*
    *	Array.find()作用:查找,找出第一个符合条件的成员,如果有,返回该值,没有,返回undefined; 
    *	Array.findIndex()作用:查找位置,找出第一个符合条件的成员位置,如果有,返回该值下表,没有,返回-1; 
    */
    let arr=[23,90,102,80,105];
    let newArr=arr.find((val,index,arr)=>{
    	return val>1000;
    })
    console.log(newArr);
    //输出:102
    let index=arr.findIndex((val,index,arr)=>{
    	return val>100;
    })
    console.log(index);
    //输出:2
  5. fill:填充内容
    /*
    *	arr.fill('填充内容','开始位置','结束位置');
    *	规定起始位置的,填充内容包含开始位置,不包含结束位置	
    */	
    let arr=new Array(3);
    arr.fill('默认值',1,2);
    console.log(arr);
    //输出:(3) [empty, "默认值", empty]
  6. includes:
    let arr=['a','b','c'];
    console.log(arr.includes('a'));
    //输出:true
    console.log(arr.includes('aa'));
    //输出:false

8、对象

  1. 对象简洁语法
    let name='ss';
    let age=18;
    let obj={
    	name, //等价于name:name,
    	age,  //等价于age:age
    	showA(){
    			return this.name;
    	},//等价于 function showA(){return this.name;},最好不要用箭头函数,会引发作用域问题
    	showB(){
    			return this.age;
        }//等价于 function showB(){return this.name;},最好不要用箭头函数,会引发作用域问题
    };
    console.log(obj.showA(),obj.showB());
  2. is:Object.is() 作用:比较两个值是否相等
    console.log(NaN==NaN);				//输出:false
    console.log(Object.is(NaN,NaN)); 	//输出:true
    console.log(+0==-0);				//输出:true
    console.log(Object.is(+0,-0)); 		//输出:false
    console.log(Object.is('aaa','aa'));//输出:false
    console.log(Object.is('aaa','aaa'));//输出:true
  3. assign:Object.assign() 作用:合并对象(复制一个对象,合并参数)
    let o={
    	a:1
    }
    let o1={
    	b:2,
    	a:100
    }
    let o2={
    	c:3
    }
    console.log(Object.assign({},o,o1,o2));
    //输出:{a: 100, b: 2, c: 3},注意a的值被o1的a的值覆盖
    /**/
    let arr=['a','b','c'];
    let arr2=Object.assign([],arr);
    arr2.push('d');
    console.log(arr2);
    //输出:["a", "b", "c", "d"]
    console.log(arr);
    //输出: ["a", "b", "c"]
  4. Object的keys(),values(),entries()

    let {keys,values,entries}=Object; //解构
    let obj={
    	a:1,
    	b:2
    }
    for(let key of keys(obj)){
    	console.log(key);
    }
    //输出1:a
    //输出2:b
    for(let val of values(obj)){
    	console.log(val);
    }
    //输出1:1
    //输出2:2
    for(let entr of entries(obj)){
    	console.log(entr);
    }
    //输出1:(2) ["a", 1]
    //输出2:(2) ["b", 2]
  5. Object的扩展运算符(...)的使用

    let obj={
    	a:1,
    	b:2
    }
    let obj2={...obj};
    console.log(obj2);
    //输出:{a: 1, b: 2}
    delete obj2.a;
    console.log(obj2);
    //输出:{b: 2}
    console.log(obj);
    //输出:{a: 1, b: 2}

9、promise

  1. 基本语法
    let a=12;
    new Promise(function(resolve,reject){
    	//resolve,成功的时候调用
    	//reject,失败的时候调用
    	if(a==10){
    		resolve(true)
    	}else{
    		reject(false);
    	}//ajax请求
    }).then(res=>{
    	console.log(res);
    }).catch(err=>{ //reject发生错误,别名
    	console.log(err);
    });
    //输出:false
  2. 快速转成Promise对象

    Promise.resolve('aa'); //将现有东西,转成一个promise对象,resolve成功状态
    //等价于
    new Promise(resolve=>{resolve('aa')});
    Promise.reject('aaa'); //将现有东西,转成一个promise对象,resolve成功状态
    //等价于
    new Promise((resolve,reject)=>{reject('aaa')});
  3. Promise.all(): Promise.all([p1,p2,p3]):把promise打包,扔到一个数组里面,打包完还是promise对象,必须确保所有promise对象都是resolve成功状态

    let p1=Promise.resolve('aa');
    let p2=Promise.resolve('bb');
    let p3=Promise.resolve('cc');
    Promise.all([p1,p2,p3]).then(res=>{
    	console.log(res);
        //输出:["aa", "bb", "cc"]
        let [res1,res2,res3]=res; //解构
    	console.log(res1,res2,res3);
        //输出:aa bb cc
    }).catch(err=>{
    	console.log(err);
    });
    //输出:["aa", "bb", "cc"]
    //输出:aa bb cc
  4. Promise.race():Promise.race([p1,p2,p3]):

    let p1=Promise.resolve('aa');
    let p2=Promise.reject('bb');
    let p3=Promise.resolve('cc');
    Promise.race([p1,p2,p3]).then(res=>{
    		console.log(res,1);
    }).catch(err=>{
    		console.log(err,2);
    });
    //输出:aa 1

10、模块化

  • 注意:需要放到服务器环境
  • 如何定义模块 export
  • 如何使用 import
  1. import可以是相对路径
  2. import模块只会导入一次,无论引入多少次
  3. import './xx.js';这么用,相当于引入文件
  4. import 有提升效果
  5. 导出去的模块内容,如果有定时器更改,外面也会改动,与Common规范不同(Common规范会缓存)
  6. import 类似node里面require,可以动态引入,默认import语法不能写到if之类的里面
    /*1*/
    export const a=12;
    //对应
    import './xx.js';
    /*
    *    2   export时可以取别名 
    */
    const a=12;
    const b=12;
    const c=12;
    export{
        a as aaa,
        b as banana,
        c as cup
    }
    //对应
    import {aaa,banana,cup} from './xx.js';
    console.log(aaa,banana,cup);
    /*
    *    3  import时也可以取别名 
    */
    import {aaa as a,banana as b,cup as c} from './xx.js';
    console.log(a,b,c);
    /*
    *    4  可以简写    *
    */
    import * as modTwo from './xx.js';
    console.log(modTwo.aaa);
    /*
    *    5  只有default时,import时不用加{}
    */
    export default a=12;
    //对应
    import a from './xx.js';
    console.log(a);
    /*
    *    6  试题
    */
    import mod,{show, sum,a,b} from './xx.js';
    let p1=new mod.Person('xx');
    console.log(p1.showName());
    show();
    sum();
    console.log(a,b);
    //对应
    const a=12;
    const b=5;
    const sum=()=>{
        return a+b;
    }
    const show=()=>{
       console.log(1,2); 
    }
    class Person{
        constructor(name,age){
            this.name=name;
            this.age=age;
        }
        showName(){
            return this.name;
        }
    }
    export {
        a,
        b,
        sum,
        show
    }
    export default {
        Person
    }
    /*
    *    7  导出去的模块内容,如果有定时器更改,外面也会改动,与Common规范不同(Common规范会缓存)
    */
    //导出
    let a=12;
    let a=b;
    setTimeout(()=>{
        a=11111;
    },2000);
    export {
        a,
        b
    }
    //引入
    import {a,b} from './xx.js';
    console.log(a);
    //输出:12
    setTimeout(()=>{
        console.log(a);
    },3000);
    //输出:11111
    /*
    *    8  import 类似node里面require,可以动态引入,默认import语法不能写到if之类的里面
    *    优点:1.按需加载2.可以写if中3.路径可以动态
    */
    import('./xx.js').then(res=>{
        console.log(a,b);
    })

11、类和继承

  1. ES6之前,js没有类,程序员用function来模拟类
    function Person(name,age){
    	this.name=name;
    	this.age=age;
    }
    Person.prototype.showName=function(){
    	console.log(`我的名字是${this.name}`);
    }
    Person.prototype.showAge=function(){
    	console.log(`我的年龄是${this.age}`);
    }
    let p1=new Person('xx',18);
    p1.showName();
    p1.showAge();
    //输出:我的名字是xx
    //输出:我的年龄是18
    /****************另一种写法*******************************/
    function Person2(name,age){
    	this.name=name;
        this.age=age;
    }
    Object.assign(Person2.prototype,{
    	showName(){
    		console.log(`我的名字是${this.name}`);
    	},
    	showAge(){
    		console.log(`我的年龄是${this.age}`);
    	}
    })
    let p2=new Person2('xx',18);
    p2.showName();
    p2.showAge();
    //输出:我的名字是xx
    //输出:我的年龄是18
  2. ES6 class形式
    class Person{
    	constructor(name,age){//构造函数,调用new,自动执行
    		// console.log(`${name},${age}`); //xx,18
    		this.name=name;
    		this.age=age;
    	}
    	showName(){
    		console.log(`${this.name}`);
    	}
    	showAge(){
    		console.log(`${this.age}`);
    	}
    }
    let p1=new Person('xx',18);
    p1.showName();
    p1.showAge();
    //输出:xx
    //输出:18
    /************************************************第二种:表达式形式,不推荐*/
    let Person=class{
    	constructor(name,age){//构造函数,调用new,自动执行
    		// console.log(`${name},${age}`); //xx,18
    		this.name=name;
    		this.age=age;
    	}
    	showName(){
    		console.log(`${this.name}`);
    	}
    	showAge(){
    		console.log(`${this.age}`);
    	}
    }
    let p1=new Person('xx',18);
    p1.showName();
    p1.showAge();
    //输出:xx
    //输出:18
  3. 属性名可以使用变量
    let a='yy';
    let b='xx';
    class Person{
    	//constructor构造函数,调用new,自动执行
    	constructor(){}
    	[a+b](){
    		console.log(1+2);
    	}
    }
    let p1=new Person('xx',18);
    p1[a+b]();
    //输出:3
  4. ES6里面函数没有预解析,不能提升;ES5函数模拟类,有提升
    let p1=new Person('xx',18);
    p1[a+b]();
    let a='yy';
    let b='xx';
    class Person{
    	//constructor构造函数,调用new,自动执行
    	constructor(){}
    	[a+b](){
    		console.log(1+2);
    	}
    }
    //输出报错:Uncaught ReferenceError: Person is not defined
  5. this问题:ES6里面的this比之前轻松多了
    class Person{
    	constructor(){
    		this.name='yy';
    	}
    	showName(){
    		console.log(`this=`+this);
    		console.log(`${this.name}`);
    	}
    }
    let p1=new Person();
    let {showName}=p1;
    console.log(showName());
    //输出:this=undefined
    //输出报错:Uncaught TypeError: Cannot read property 'name' of undefined
    /***************************************************矫正this*************************/
    class Person{
    	constructor(){
    		this.name='yy';
            //矫正this bind:只矫正this,call、apply:调用方法
    		this.showName=this.showName.bind(this);
    	}
    	showName(){
    		console.log(`this=`+this);
    		console.log(`${this.name}`);
    	}
    }
    let p1=new Person();
    let {showName}=p1;
    console.log(showName());
    //输出:this=[object Object] 
    //输出:yy
  6. class里面的取值函数(getter)、存值函数(setter)
    class Person{
    	constructor(){
    	}
    	//返回值
    	get aaa(){
    		return(`getAaa`);
    	}
    	//设置值
    	set aaa(val){
    		console.log(`设置aaa为:${val}`,1);
    	}
    }
    let p1=new Person();
    p1.aaa='123';//设置值
    console.log(p1.aaa);//取值
    //输出:设置aaa为:123 1
    //输出:getAaa
  7. 静态方法static:类自身上的方法,调用方式类名.静态方法名
    class Person{
    	constructor(){}
    	static aaa(){
    		console.log(`我是静态类,可以用自身+“.”来调用`);
    	}
    }
    Person.aaa();
    //输出:我是静态类,可以用自身+“.”来调用
  8. 继承
    /****************************************之前继承****/
    //父类
    function Person(name){
    	this.name=name;
    }
    Person.prototype.showName=function(){
    	console.log(`${this.name}`);
    }
    //子类
    function Student(name,skill){
    	Person.call(this,name);//继承属性
    	this.skill=skill;
    }
    Student.prototype=new Person();//继承方法
    // * Student的constructor有问题,需要矫正
    //调用
    let stu1=new Student('ss','迟到');
    stu1.showName();
    //输出:ss
    /****************************************ES6继承简化版****/
    //父类
    class Person1{
    	constructor(name){
    		this.name=name;
    	}
    	showName(){
    		console.log(`${this.name}`);
    	}
    }
    //子类
    class Student1 extends Person1{}
    //调用
    let stu2=new Student1('yy');
    stu2.showName();
    //输出:yy
    /****************************************ES6继承完整版****/
    //父类
    class Person1{
    	constructor(name,age){
    		this.name=name;
    		this.age=age;
    	}
    	showName(){
    		console.log(`${this.name}`);
    	}
    	showAge(){
    		console.log(`${this.age}`);
    	}
    }
    //子类
    class Student1 extends Person1{
    	constructor(name,age,skill){ //子类也需要有子类的属性和方法
    		super(name,age);//如果没有super,子类的constructor会覆盖父级的constructor,报错:Uncaught ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor
    		this.skill=skill;
    	}
    	showSkill(){
    		console.log(`今天又${this.skill}`);
    	}
    }
    //调用
    let stu2=new Student1('yy',18,'迟到');
    stu2.showName();
    stu2.showAge();
    stu2.showSkill();
    //输出:yy
    //输出:18
    //输出:今天又迟到
  9. 子类继承父类某方法,并在某方法中写自己的内容
    //父类
    class Person1{
    	constructor(name){
    		this.name=name;
    	}
    	showName(){
    		console.log(`父类showName`);
    	}
    }
    //子类
    class Student1 extends Person1{
    	constructor(name){ //子类也需要有子类的属性和方法
    		super(name);
    	}
    	showName(){
    		super.showName();//父类方法执行
    		//TODO 做子类的事情
    		console.log(`子类showName`,`${this.name}`);
    	}
    }
    //调用
    let stu2=new Student1('yy');
    stu2.showName();
    输出:父类showName
    输出:子类showName yy

12、Symbol & generator

symbol:

symbol使用情况一般,node底层可能会用到

let sym=Symbol('aaa');
console.log(sym);
//输出:Symbol(aaa)
/*
*    注意:
*    1、Symbol不能new
*/
let sym=new Symbol('aaa');
console.log(sym);
//输出报错:Uncaught TypeError: Symbol is not a constructor
/*
*    注意:
*    2、Symbol返回的是一个唯一的值。做一个Key,定义一些唯一或者私有的东西
*    3、symbol是一个单独数据类型,typeof检测出来就是symbol类型,基本类型
*/
let sym=Symbol('aaa');
console.log(typeof sym);
//输出:symbol
/*
*    注意:
*    4、symbol作为key,for...in循环,值出不来
*/
let symbol=Symbol('aaa');
let json={
	a:1,
	b:2,
	[symbol]:'aaa'
}
for(let key in json){
	console.log(key);
}
//输出:a
//输出:b

generator函数(生成器):

 解决异步深度嵌套,现在多使用async

Generator 函数有多种理解角度。语法上,首先可以把它理解成,Generator 函数是一个状态机,封装了多个内部状态。

执行 Generator 函数会返回一个遍历器对象,也就是说,Generator 函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。

形式上,Generator 函数是一个普通函数,但是有两个特征。一是,function关键字与函数名之间有一个星号;二是,函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

/* 
*generator函数语法
*/
//定义
function * gen(){
	yield 'ww';
	yield 'to';
	return 'xx';
}
/*
*    调用1:
*    手动调用,太麻烦
*/
let t=gen();
console.log(t.next());
//输出:{value: "ww", done: false}
console.log(t.next());
//输出:{value: "to", done: false}
console.log(t.next());
//输出:{value: "xx", done: true}
/*
*    调用2:
*    还可以使用for...of自动遍历gennerator,
*    但是return的东西,for...of不会遍历出来
*/
let t=gen();
for(let val of t){
	console.log(val);
}
//输出:ww
//输出:to
/*
*	调用3:
*	可以使用解构,return的东西,不会解构出来
*/
let [a,b]=gen();
console.log(a,b);
//输出:ww to
/*
*	调用4:
*	可以使用拓展运算符(...),return的东西,不会拓展出来
*/
let [c,...d]=gen();
console.log(c,d);
//输出:ww ["to"]

yield 关键字使生成器函数执行暂停,yield 关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器的版本的 return 关键字。javascript中的yield就是类似lisp中的continuation(田春把他翻译成了续延) On Lisp​​​​​​​中文版里也有提到,LISP语言是1958年发明的。

yield 关键字实际返回一个 IteratorResult 对象,它有两个属性,value 和 donevalue 属性是对 yield 表达式求值的结果,而 done 是 false,表示生成器函数尚未完全完成。

一旦遇到 yield 表达式,生成器的代码将被暂停运行,直到生成器的 next() 方法被调用。每次调用生成器的 next() 方法时,生成器都会恢复执行,直到达到以下某个值:

  • yield,导致生成器再次暂停并返回生成器的新值。下一次调用 next() 时,在 yield 之后紧接着的语句继续执行。
  • throw 用于从生成器中抛出异常。这让生成器完全停止执行,并在调用者中继续执行,正如通常情况下抛出异常一样。
  • 到达生成器函数的结尾。在这种情况下,生成器的执行结束,并且 IteratorResult 给调用者返回 value 的值是 undefined 并且 done 为 true
  • 到达 return 语句。在这种情况下,生成器的执行结束,并将 IteratorResult 返回给调用者,其 value 的值是由 return 语句指定的,并且 done 为 true

yield表达式本身没有返回值,或者说总是返回undefinednext方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

generator面试题

function* f(): Generator<number, boolean, boolean> {
  for (let i = 0; true; i++) {
    console.log('i-----:', i)
    let reset: boolean = yield i
    if (reset) {
      i = -1
      console.log('--i--:', i)
    }
  }
}

let g = f()
console.log(g.next())
console.log(g.next())
console.log(g.next(true))

上面代码先定义了一个可以无限运行的 Generator 函数f,如果next方法没有参数,每次运行到yield表达式,变量reset的值总是undefinednext方法带一个参数true时,变量reset就被重置为这个参数(即true),因此i会等于-1,下一轮循环就会从-1开始递增

​​​​​​​这个功能有很重要的语法意义。Generator 函数从暂停状态到恢复运行,它的上下文状态(context)是不变的。通过next方法的参数,就有办法在 Generator 函数开始运行之后,继续向函数体内部注入值。也就是说,可以在 Generator 函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数行为。

知识点:

  1. 异步:不连续操作,上一个操作没有执行完,下一个操作照样开始
  2. 同步:连续执行,上一个操作没有执行完,不会执行下有一个操作
  3. 异步解决方案:1):回调函数;2):事件监听;3):发布/订阅;4)Promise对象

13、async、await

  • asyn:ES2017规定的
    /*
    *	用node做例子,分别用promise,generator,async异步读取文件
    */
    //data文件夹有文件a.txt,b.txt,c.txt读取这三个文件
    const fs=require('fs');
    //将fs进行一个简单的promise封装
    const readFile=function(fileName){
    	return new Promise((resolve,reject)=>{
    		fs.readFile(fileName,(err,data)=>{
    			if(err) reject(err);
    			resolve(data);
    		});
    	});
    }
    /*
    *	promise	
    */
    readFile('data/a.txt').then(res=>{
    	console.log(res);
    	return readFile('data/b.txt')
    }).then(res=>{
    	console.log(res);
    	return readFile('data/c.txt')
    });
    /*
    *	generator	
    */
    function * gen(){
    	yield readFile('data/a.txt');
    	yield readFile('data/b.txt');
    	yield readFile('data/c.txt');
    }
    let g1=gen();
    g1.next().value.then(res=>{
    	console.log(res); //输出a.txt
    	return g1.next().value; //请求b.txt
    }).then(res=>{
    	console.log(res);//输出b.txt
    	return g1.next().value;//请求c.txt
    }).then(res=>{
    	console.log(res);//输出c.txt
    });
    /*
    *	async	
    */
    async function fn(){
    	//await:表示后面结果需要等待
    	let f1= await readFile('data/a.txt');
    	console.log(f1); 
    	let f2= await readFile('data/b.txt');
    	console.log(f2); 
    	let f3= await readFile('data/c.txt');
    	console.log(f3); 
    }
    fn();
  • async特点:
  1. await只能放到async方法里面
  2. 相比generator语义化更强
  3. await后面可以是promise对象,也可以是数字、字符串、布尔值
  4. async函数返回的是一个promise对象
    async function fn(){
    	return 'welcome';
    }
    console.log(fn());
    //输出:Promise {<resolved>: "welcome"}
    fn().then(res=>{
    	console.log(res);
    });
    //输出:welcome
    async function fnErr(){
    	throw new Error('出错了');
    }
    fnErr().then(res=>{
    	console.log(res);
    },err=>{
    	console.log(err);
    });
    //输出:Error: 出错了
    fnErr().then(res=>{
    	console.log(res);
    }).catch(err=>{
    	console.log(err);
    });
    //输出:Error: 出错了
  5. 只要await语句后面promise状态变成reject,整个函数会中断执行
    /*
    *	注释出错语句
    */
    async function fn(){
    	let a=await Promise.resolve('成功1');
    	console.log(a);
    	// await Promise.reject('出错了');
    	let b=await Promise.resolve('成功2');
    	console.log(b);
    }
    fn().then(res=>{
    	// console.log(res);
    }).catch(err=>{
    	console.log(err);
    });
    //输出:成功1
    //输出:成功2
    /*
    *	不注释出错语句
    */
    async function fn(){
    	let a=await Promise.resolve('成功1');
    	console.log(a);
    	await Promise.reject('出错了');
    	let b=await Promise.resolve('成功2');
    	console.log(b);
    }
    fn().then(res=>{
    	// console.log(res);
    }).catch(err=>{
    	console.log(err);
    });
    //输出:成功1
    //输出:出错了
  6. 解决只要await语句后面promise状态变成reject,整个函数会中断执行
    /*
    *	方法一:
    */
    async function fn(){
    	try{
    		await Promise.reject('出错了');
    	}catch(e){
    		let a=await Promise.resolve('成功1');
    		console.log(a);
    		let b=await Promise.resolve('成功2');
    		console.log(b);
    	}	
    }
    fn().then(res=>{
    	// console.log(res);
    }).catch(err=>{
    	console.log(err);
    });
    //输出:成功1
    //输出:成功2
    /*
    *	方法二:
    */
    async function fn(){
    	await Promise.reject('出错了').catch(err=>{
    		console.log(err);
    	});
    	let a=await Promise.resolve('成功1');
    	console.log(a);
    	let b=await Promise.resolve('成功2');
    	console.log(b);	
    }
    fn().then(res=>{
    	// console.log(res);
    }).catch(err=>{
    	console.log(err);
    });
    // 输出:出错了
    // 输出:成功1
    // 输出:成功2
    /*
    *	方法三:个人建议将await都放在try..catch中
    */
    async function fn(){
    	try{
    		let f1= await readFile('data/a.txt');
    		let f2= await readFile('data/b.txt');
    		let f3= await readFile('data/c.txt');
    	}catch(e){}
    }

14、Set和WeakSet

  1. SetES6新增的数据结构,类似数组,但是里面不能有重复值
    /*
    *	set:一种新的数据结构
    */
    let s=new Set(['a','b']);
    console.log(s);
    //输出:Set(2) {"a", "b"}
    /*
    *	set:类似数组,但是里面不能有重复值
    */
    let s1=new Set(['a','b','a','b',1,'1']);
    console.log(s1);
    //输出:Set(4) {"a", "b", 1, "1"}
    /*
    *	set:方法一:add
    */
    s1.add('c');
    console.log(s1);
    //Set(5) {"a", "b", 1, "1", "c"}
    /*
    *	set:方法二:delete
    */
    s1.delete('c');
    console.log(s1);
    //输出:Set(4) {"a", "b", 1, "1"}
    /*
    *	set:方法三:has,判断s1有没有该值
    */
    console.log(s1.has('a'));
    //输出:true
    console.log(s1.has('c'));
    //输出:false
    /*
    *	set:属性一:size
    */
    console.log(s1.size);
    //输出:4
    /*
    *	set:方法四:clear()
    */
    s1.clear();
    console.log(s1);
    //输出:Set(0) {}
  2. set循环及用途
    /*
    *	set:循环
    */
    let s2=new Set(['a','b','c','d']);
    for(let item of s2){ //默认是values
    	console.log(item);
    }
    //输出1:a,输出2: b,输出3: c,输出4: d
    for(let item of s2.keys()){
    	//keys与values结果一致
    	console.log(item);
    }
    //输出1:a,输出2: b,输出3: c,输出4: d
    for(let item of s2.values()){
    	//
    	console.log(item);
    }
    //输出1:a,输出2: b,输出3: c,输出4: d
    for(let item of s2.entries()){
    	console.log(item);
    }
    //输出1: (2) ["a", "a"],输出2: (2) ["b", "b"],
    //输出3: (2) ["c", "c"],输出4: (2) ["d", "d"]
    for(let [k,v] of s2.entries()){
    	console.log(k,v);
    }
    //输出1: a a,输出2: b b,
    //输出3: c c,输出4: d d
    s2.forEach((k,v)=>{
    	console.log(v,k);
    });
    //输出1: a a,输出2: b b,
    //输出3: c c,输出4: d d
    /*
    *	set:可链式调用
    */
    let s3=new Set().add('a').add('b').add('c');
    /*
    *	set:用途1:可数组去重
    */
    let arr=[1,2,3,1,2,3];
    let newArr=[...new Set(arr)];
    console.log(newArr);
    //输出:(3) [1, 2, 3]
    /*
    *	set:用途2:使用数组map方法改变值
    */
    let s4=new Set([1,2,3]);
    s4=new Set([...s4].map(val=>val*2));
    console.log(s4);
    //输出:Set(3) {2, 4, 6}
    /*
    *	set:用途3:使用数组filter方法过滤值
    */
    let s5=new Set([1,2,3]);
    s5=new Set([...s5].filter(val=>val%2!=0));
    console.log(s5);
    //输出:Set(2) {1, 3}
    /*
    *	set:里面放置数组,也可以存放对象,但是最好放数组
    */
    let s6=new Set();
    let json={a:1,b:2};
    let json2={a:1,b:2};
    s6.add(json).add(json2);
    console.log(s6);
    //输出:Set(2) {{…}, {…}}
    s6.forEach(val=>{
    	console.log(val);
    })
    //输出:{a: 1, b: 2}
    //输出:{a: 1, b: 2}
  3. WeakSet:新增的数据结构,在初始状态,直接添加对象会报错,需要用add,用处不大,也没有size、clear()。最好用Set
    let s=new WeakSet({a:1,b:2});
    console.log(s);
    //输出报错:Uncaught TypeError: #<Object> is not iterable
    let s1=new WeakSet();
    let json={
    	a:1,
    	b:2
    }
    s1.add(json);
    console.log(s1);
    //输出:WeakSet {{…}}

15、Map和WeakMap

  1. map:类似于json,但是json的key只能是字符串,map的key可以是任意类型。
    /*
    *	map:设置值
    */
    let m=new Map();
    let j={a:'b'}
    m.set('a','aaaaa');
    m.set(j,1);
    m.set('c',j);
    console.log(m);
    //输出:Map(3) {"a" => "aaaaa", {…} => 1, "c" => {…}}
    /*
    *	map:获取值
    */
    console.log(m.get(j));
    //输出:1
    /*
    *	map:循环,也可以循环keys(),values(),entries()
    */
    for(let [k,v] of m){ //默认entries
    	console.log(k,v);
    }
    //输出:a aaaaa,输出: {a: "b"} 1,输出: c {a: "b"}
    m.forEach((v,k)=>{
    	console.log(v,k);
    });
    /*
    *	map:删除一项
    */
    m.delete('a');
    console.log(m);
    //输出:Map(2) {{…} => 1, "c" => {…}}
    /*
    *	map:判断有没有某一项
    */
    console.log(m.has(j));
    //输出:true
    /*
    *	map:clear()
    */
    m.clear();
    console.log(m);
    //输出:Map(0) {}
  2. WeakMap:key只能是对象
    let wm1=new WeakMap();
    wm1.set({'a':'b'},'aaaa');
    console.log(wm1);
    //输出:WeakMap {{…} => "aaaa"}
    let wm=new WeakMap();
    wm.set('a','aaaa');
    console.log(wm);
    //输出报错:Uncaught TypeError: Invalid value used as weak map key

总结:

  1. Set里面是数组,不重复,没有key,没有get()
  2. Map对json的扩展,key是任意类型的值

16、数字新增和Math新增的

  1. 进制变化
    /*二进制*/
    let a=0b010101; 
    console.log(a);
    //输出:21
    /*八进制*/
    let b=0o666; 
    console.log(b);
    //输出:438
  2. 数值变化
    /*ES6将部分数字操作方法都挂到Number上*/
    let a=12;
    console.log(isNaN(a)); //输出:false
    console.log(Number.isNaN(a));//输出:false
    /*isFinite():判断是否是数字*/
    console.log(Number.isFinite(a));//输出:true
    /*isInteger():判断数字是否是整数*/
    console.log(Number.isInteger(a));//输出:true
    /*
    *	安全整数:
    *	min:-(2^53-1),负的2的53次方减1
    *	max:2^53-1,2的53次方减1
    */
    console.log(Number.isSafeInteger(2**53));//输出:false
    console.log(Number.isSafeInteger(2**53-1));//输出:true
    console.log(Number.isSafeInteger(-(2**53)));//输出:false
    console.log(Number.isSafeInteger(-(2**53-1)));//输出:true
    console.log(Number.MAX_SAFE_INTEGER);//输出:9007199254740991
    console.log(Number.MIN_SAFE_INTEGER);//输出:-9007199254740991
  3. Math的变化
    /*trunc():截取,只保留整数位*/
    console.log(Math.trunc(4.56)); //输出:4
    /*sign():判断一个数是整数(返回1)还是负数(返回-1)0返回0,-0返回-0*/
    console.log(Math.sign(-4.56)); //输出:-1
    console.log(Math.sign(4.56)); //输出:1
    console.log(Math.sign(-0)); //输出:-0
    console.log(Math.sign(0)); //输出:0
    /*cbrt():计算一个数的开立方根*/
    console.log(Math.cbrt(27)); //输出:3

17、ES2018(ES9)新增

  1. 命名捕获:?<名字>
    let str='2018-03-20';
    let reg=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    var data=str.match(reg)
    let {year,month,day}=str.match(reg).groups;
    console.log(year,month,day);
    //输出:2018 03 20
  2. 反向引用命名捕获:\k<名字>
    let str='a-a';
    let str2='xx-xx';
    let str3='welcome-welcome';
    let str4='welcome-welcome-welcome';
    let reg=/^(?<xx>welcome)-\k<xx>$/;
    console.log(reg.test(str),reg.test(str2),reg.test(str3),reg.test(str4));
    //输出:false false true false
    let reg2=/^(?<xx>welcome)-\k<xx>-\1$/;
    console.log(reg.test(str4));
    //输出:false
  3. 替换:$<名字>
    let str='2018-03-20';
    let reg=/(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    str=str.replace(reg,'$<year>/$<month>/$<day>');
    console.log(str);
    //输出:2018/03/20
    /*************************************************结合回调函数*/
    str=str.replace(reg,(...args)=>{
    	let {year,month,day}=args[args.length-1];
    	return `${day}/${month}/${year}`;
    });
    console.log(str);
    //输出:20/03/2018
  4. dotAll模式(之前'.'在正则里匹配任意东西,不包括/n)
    let str='welcome32\nroot';
    let reg=/^\w+.\w+$/;
    console.log(reg.test(str));
    //输出:false
    let reg1=/^\w+.\w+$/m;
    console.log(reg1.test(str));
    //输出:true
    let reg2=/^\w+.\w+$/s;
    console.log(reg2.test(str));
    //输出:true
  5. 标签函数
    function fn(args){
    	// console.log(args); //输出:["welcome", raw: Array(1)]
    	console.log(args[0].toUpperCase());
    }
    fn`welcome`;
    //输出:WELCOME

18、Proxy的使用(非常非常有用,但不常用)

  1. proxy:代理,扩展(增强)对象一些功能,还有预警、上报、统计等等,是设计模式的一种,代理模式
    //假如obj对象用户看不到,实现代理
    let obj={name:'a'};
    let newObj=new Proxy(obj,{
    	get(target,property){
    		console.log(target,property);
    		return target[property]
    	}
    });
    newObj.name;
    //输出:{name: "a"} "name"
    console.log(newObj.name);
    //输出:a
    /*拦截:实现一个,访问对象属性,不存在的时候默认undefine,如果不存在,返回错误信息*/
    let newObj2=new Proxy(obj,{
    	get(target,property){
    		if(property in target){
    			return target[property];
    		}else{
    			throw new ReferenceError(`key值${property}不存在`)
    		}
    	}
    });
    console.log(newObj2.age);
    //输出报错:Uncaught ReferenceError: key值age不存在
  2. proxy的方法示例
    /*
    *    get()
    */
    const DOM=new Proxy({},{
    	get(target,property){
    		//property是DOM.xx的xx
    		return function(attr={},...children){
    			const el=document.createElement(property);
    			//添加属性
    			for(let key of Object.keys(attr)){
    				el.setAttribute(key,attr[key])
    			}
    			//添加子元素
    			for(let child of children){
    				if(typeof child=='string'){
    					child=document.createTextNode(child)
    				}
    				el.appendChild(child)
    			}
    			return el;
    		}
    	}
    });
    let oDiv=DOM.div({id:'div1',class:'odiv'},'我是div','hahaha');
    console.log(oDiv);
    //放到页面上
    document.body.appendChild(oDiv);
    /*
    *	set():设置,拦截
    */
    const obj=new Proxy({},{
    	set(target,property,value){
    		if(property=='age'){
    			if(!Number.isInteger(value)){
    				throw new TypeError(`年龄必须为整数`);
    			}
    			if(value>150){
    				throw new RangeError(`年龄超出限制`);
    			}
    		}
    		target[property]=value;
    	}
    });
    obj.a=3;
    obj.name='qq';
    obj.age=18;
    console.log(obj);
    //输出:Proxy {a: 3, name: "qq", age: 18}
    /*
    *	deleteProperty:删除,拦截
    *	has:检测有没有某个属性
    */
    let json={a:1,b:2}
    const newJson=new Proxy(json,{
    	deleteProperty(target,property){
    		delete target[property];
    	},
    	has(target,property){
    		//TODO
    		return property in target;
    	}
    });
    delete newJson.a;
    console.log(newJson,'b' in newJson);
    //输出:Proxy {b: 2} true

19、Reflect的使用

  1. Reflect:反射,Reflect.apply('调用的函数','this指向','参数数组')与fn.apply()类似
    /*
    *	apply:拦截方法
    */
    function sum(a,b){
    	return a+b;
    }
    const newSum=new Proxy(sum,{
    	apply(target,context,args){
    		//console.log(target,context,args);
    		/*
    		*	Reflect:反射
    		*	Reflect.apply与fn.apply('调用的函数','this指向','参数数组')类似
    		*/
    		return Reflect.apply(...arguments)**2;
    	}
    });
    console.log(newSum(2,3));
    //输出:25
  2. call()、apply()、Reflect.apply的用法
/*
*	Reflect:不太成熟,未来新东西放到Reflect上
*	Reflect:通过Reflect对象拿到语言内部的东西
*/
function show(...args){
	console.log(this,args);
}
show(1,2);
//输出:window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} (2) [1, 2]
show.call('ab',1,2);
//输出:String {"ab"} (2) [1, 2]
show.apply('ab',[1,2]);
//输出:String {"ab"} (2) [1, 2]
Reflect.apply(show,'ab',[1,2]);
//输出:String {"ab"} (2) [1, 2]

20、补充

  1. Array.prototype.at(index)比用array[index]方法表示简洁

at() 方法接收一个整数值并返回该索引的项目,允许正数和负数。负整数从数组中的最后一个项目开始倒数。

mdn​​​​​​​

console.log([5, 12, 8, 130, 44].at(-1))//输出:44
console.log(['5', 12, 8, 130, 44].at(0))//输出:'5'
//找不到指定的索引,则返回undefined
console.log(['5', 12, 8, 130, 44].at(5))//输出:undefined

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
elasticsearch 学习笔记包括以下内容: 一、Elasticsearch概述: - Elasticsearch是一种开源的分布式搜索和分析引擎,可以用于快速搜索、分析和存储大量的结构化和非结构化数据。 - Elasticsearch与Solr相比有一些区别,包括用户、开发和贡献者社区的规模和成熟度等方面。 二、Elasticsearch安装: 1. 下载Elasticsearch,可以从官方网站或华为云镜像下载。 2. 安装Elasticsearch。 三、安装head插件: - head插件是一个可视化的管理界面,可以方便地管理和监控Elasticsearch集群。 四、安装Kibana: 1. Kibana是一个开源的数据可视化工具,用于展示和分析Elasticsearch中的数据。 2. 下载Kibana并安装。 3. 启动Kibana并进行访问测试。 4. 可选的汉化操作。 五、ES核心概念理解: - 学习ES的核心概念,包括索引、文档、映射、查询等。 以上是elasticsearch学习笔记的主要内容,希望对你有帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Elasticsearch 学习笔记(上)](https://blog.csdn.net/m0_52691962/article/details/127064350)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值