• 前端开发之ES6(ECMAscript6)语法以及ES6++快速学习入门(前端必备了解知识)


    ES6++(ES6---- ES9)

    什么是ECMA

    // 中文名称是欧洲计算机制造商协会,这个组织的目的是评估,开发和认可电信和计算机标准。1994年后该组织改名为ECMA国际
    
    • 1

    什么是ECMAscript

    // ECMAscript是由ECMA 国际通过ECMA-262标准化的脚本程序设计语言
    
    • 1

    1,ES6

    1.1 let变量声明以及声明特性

    //变量不能重复声明
    let star = 'zll';
    let star = 'wxl';//此时会报错
    
    //块级作用域有效 全局、函数、ecal
    { //if for else while
        let str='zzl';
    }
    console.log(str);//此时会报错,因为拿不到
    
    // 不存在变量提升
    console.log(name);//会报错,不能使用name这个变量
    let name='zzl';
    
    //不影响作用域链
    {
        let name='zzl';//虽然是块级作用域,但是不影响作用域链的效果
        function fn(){
            console.log(name);
        }
        fn();//可以拿到
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    1.1.1 let const和var的区别?
    // var   存在变量提升(在声明语句代码之前可以使用,不会报错)  let  const 存在暂时性死区(声明之后在声明语句后面代码才可以用)
    
    console.log(a)             console..log(a)   报错        console.log(a) 报错
    var a = 10                   let  a = 10                     const a = 10
    
    // vat 声明的变量可以重复声明   let const声明的变量不能重复声明
    var  a  = 10                let a = 10                  const  a = 10
    var  a  = 20			   let a = 20 报错             const  a = 14 报错
    // var 没有块级作用域     let const 有块级作用域(例如:在while  for 循环中)
    for(var i = 0;i<10;i++){}          for(let i = 0;i<10;i++){}
    i泄漏为全局变量,存在于全局变量中       i有块级作用域
    
    // var let 是声明变量,变量值可以改变     cosnt 声明常量,值不能改(准确来说,内存地址不能变),而且声明时必须赋值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    1.2 const 声明常量以及特点

    1const声明常量
    2,一定要赋初始值
    3,常量的值不能再修改
    4,也是块级作用域,
    5,声明常量
    
    const CL='zzl';
    // 对于数组和对象的元素修改,不算2中的常量修改,不会报错
    const SZ=['zzl','wxl'];
    SZ.push('ll');//此时不会报错,因为只是修改数据,并没有修改地址
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.3 变量的解构赋值

    //数组解构赋值
        const nameS=['zzl','wxl','ll'];
        let [name1,name2,name3]=nameS;
        console.log(name1);//输出zzl
    
    //对象的结构赋值
        const data={
            name:'zzl',
            age:'22',
            active:function(){
                console.log('我会飞');
            }
        }
        let {name,age,active}=data;
        console.log(name); // 输出zzl
        active(); // 调用方法,输出我会飞
    
    let {active} = data;
    active();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1.4 模板字符串

    let str=`字符串`
    
    // 它可以支持换行
    // 变量拼接
    
    let name='zzl';
    let data=`${name}是个人`   //  'zzl是个人'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    1.5 对象简化写法

    // es6允许在大括号里面直接写入变量名和函数名,作为对象的属性和方法
    
    let name='zzl';
    let fun=function(){
        console.log('我是人');
    }
    const data={
        name, //可以直接写变量名,不用再写值了
        fun
    }
    console.log(data);    // 结果输出  name:'zzl',fun()
    
    
    const data={
        // 旧的方法定义
        // act:function(){
        //     console.log('我会动');
        // }
        //新的方法定义
        act(){
            console.log('我会动');
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    1.6 箭头函数以及声明特点

    // 声明一个函数
    let fn=function(a,b){
    }
    // 箭头函数声明一个函数
    let fn=(a,b)=>{
    }
    fn(1,2);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    1.6.1 特点
    // 箭头函数的额this是静态的,this始终指向函数声明时所在作用域下的this的值
    function getname(){
        //name是zzl,直接调用的话this值指向window
    }
        console.log(this.name);//zzl
    let getname2=()=>{
        //而这个箭头函数是在全局作用域下声明的,所以this也是指向window
        console.log(this.name);//zzl
    }
    
    window.name='zzl';
    const data={
        name:'wxl'
    }
    
    //直接调用
    getname();//name是zzl,直接调用的话this值指向window
    getname2();//而箭头函数是在全局作用域下声明的,所以this也是指向window
    
    // call方法调用
    getname.call(data);//此时普通函数this的值已经变为data了。
    getname2.call(data);
    //输出wxl,因为它的this依然指向函数getname2声明时所在作用域下的this的值window.name='zzl';
    
    
    
    // 不能作为构造实例化对象
    let Person=(name,age)=>{
        this.name=name;
        this.age=age;
    }
    let me=new Person('zzl','22');//此时会报错,箭头函数不能作为实例化对象。
    
    
    
    //不能使用arguments变量
    // arguments:用来保存实参的
    let fn=()=>{
        console.log(arguments);
    }
    fn(1,2,3);//会报错,不用用来保存实参
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    1.6.2 简写箭头函数
    // 省略小括号
    let add=(n)=>{
        return n+n;
    }
    console.log(add(9));
    
    //简写为下面----------
    
    //当形参有且只有一个的时候,可以省略小括号
    let add=n=>{
        return n+n;
    }
    console.log(add(9));
    
    
    
    //省略花括号
    //当代码体只有一条语句的时候
    
    let sum=(n)=>{
        return n*n;
    };
    console.log(sum(9));
    
    //简写为下面----------
    
    //当代码体只有一条语句的时候,此时return必须省略,而且语句的执行结果就是函数的返回值
    let sum=(n)=>n*n;
    console.log(sum(9));
    
    //小括号和花括号同时省略----------
    let sum=n=>n*n;
    console.log(sum(9));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    1.6.3 箭头函数注意事项
    // 箭头函数适合与this无关的回调,比如定时器,数组的方法回调。
    // 箭头函数不适合与this有关的回调,比如DOM元素的事件回调、对象的方法。
    
    btn.addEventListener("click",function(){
        //此时普通函数的this指向事件缘
        //如果使用箭头函数,事件源将变成外部作用域的this值,即这个函数所在的作用域
    })
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.6.4 箭头函数中的this
    // 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this
    
    function Person() {
      this.age = 0;
    
      setInterval(function growUp() {
        this.age++;   // 定时器中使用普通函数,this永远指向window,因为是window调用定时器  所以this.age 值得是Nan 
      }, 1000);
    }
    
    var p = new Person();
    // '------------------------------------'
    function Person() {
      this.age = 0
      setInterval(()=> {   // 箭头函数没有自己this,只能往上一层去找
        console.log(this)  // Person对象
        this.age++;
        console.log(this.age)
      }, 1000);
    }
    var p = new Person();
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    1.6.5 笔试题
    var myObject = {
      foo: "bar",
      func: function () {
        var self = this;  // self = myObject
        console.log(this.foo);  // 'bar'
        console.log(self.foo);  // 'bar'
        (function () {
          console.log(this.foo); // undefined  // 立即执行函数里面this永远指向window
          console.log(self.foo); // 'bar'
        }());
      }
    };
    myObject.func(); 
    
    // ----------------------------------------------------------------------------
    
    function plugin () {
        this.a = 1
        this.b = {
            x: 1,
            confirm: function(title, callback) {
                this.title = title
                console.log(this, '2')  
                callback()
            }
        }
        console.log(this, '1')
    }
    var obj = new plugin()
    obj.b.confirm('弹窗', () => {
        console.log(this, '3')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    1.6.6 箭头函数与普通函数的区别?
    1,this 的指向问题
    	// 箭头函数没有自己的作用域,所以没有自己的this,箭头函数中的this指向箭头函数当前函数声明时的作用域链的上一层
    	// 普通函数有自己的作用域
    2,call() 和apply()
    	// 箭头函数里this的指向不受call,apply的指向,只跟定义位置作用域链的上一层有关,而普通函数可以
    3,箭头函数不能当构造函数,而且没有Prototype属性,而普通函数可以
    4,箭头函数没有arguments对象,普通函数有arguments对象,箭头函数中的参数可以用...参数名称来获取剩余参数
    5,箭头函数不能作为generator函数,普通函数可以
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.6.7 箭头函数的this的指向?
    // 箭头函数里的this指向沿着其作用域链往上找
    
    • 1
    代码的执行结果是什么?

    1.7 函数参数初始值

    function add(a,b,c=10){
    }
    
    //函数参数初始值与结构赋值结合使用
    function data({name,age='22'}){
        console.log(name);
        console.log(age);
    }
    
    data({
        name='zzl',
        // age='23'
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1.7.1 rest参数
    // 用于获取函数的实参,可以代替arguments。
    
    function data(){
        console.log(arguments); // 输出的是一个对象
    }
    data('zzl','wxl');
    
    // rest参数
    function data(...args){
        console.log(args); //输出的是一个数组,可以使用filter some...
    }
    data('zzl','wxl');
    
    
    // --------------------------------------------------------------
    
    // rest参数必须放在参数最后。
    
    function data(a,b,...args){
        console.log(a);//1
        console.log(b);//2
        console.log(args);//   [3,4,5]
    }
    data(1,2,3,4,5)
    
    // --------------------------------------------------------------------------------------
    
    const obj1={
        q:'zzl'
    }
    const obj2={
        s:'wxl'
    }
    const data={...obj1,...obj2}; //相当于合并了两个对象
    console.log(data);  //  {q:'zzl',s:'wxl'}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    1.8 扩展运算符

    // 它能将数组转换为逗号分隔的参数序列
    
    const names=['zzl','wxl','ll'];
    function data(){
        console.log(arguments);
    }
    
    //不用扩展运算符
    data(names); // 只输出一个结果,是一个数组
    // 用扩展运算符
    data(...names); // 输出3个结果,等价于:data('zzl','wxl','ll'),即参数序列
    
    // --------------------------------------------------------
        // 如果数组里面有引用类型的话,扩展呢运算符也只是浅拷贝。
        // 可以用来数组的合并
        // 数组的克隆
        // 伪数组转为真正的数组
        // 数组的合并
    
    const a=['zzl'];
    const b=['wxl'];
    const c=[...a,...b];  //  c=['zzl','wxl']
    
    //将伪数组转为真正的数组
    const divs=document.querySelectorAll('div');  // 得到伪数组
    const divdata=[...divs];  //  转为真正的数组
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    1.8 symbol

    // 它一种新的数据类型,表示独一无二的值,类似于字符串的数据类型。
    
    // 它的值是唯一的,用来解决命名冲突的问题。
    // 它的值不能于其他数据进行运算。
    // 它定义的对象属性不能使用for…in 循环遍历,但是可以使用Reflect.ownKeys来获取对象的所有键名。
     
    // 创建symbol
    let s = Symbol();
    
    // 下面的两个symbol对象时不一样的
    let s2 = Symbol('aini')
    let s3 = Symbol('sini')
    
    // symbol.for创建
    let s4 = Symbol.for('aini')
    let s5 = Symbol.for('aini')
    
    
    let game={
        //假如有很多代码很多变量名
    }
    
    //声明一个对象
    let data={
        //Symbol保证了up和down的属性名是独一无二的,
        // 所以添加进去也不怕也不怕有属性名冲突
        
        up:Symbol(),  
        //up属性的数据类型为Symbol
        
        down:Symbol()
    };
    
    //第一种添加方式
    //把这个Symbol添加到game方法中
    game[data.up]=function(){
        console.log('我会飞'); //安全的向这个对象中添加了两个方法
    }
    game[data.down]=function(){
        console.log('我会爬');
    }
    console.log(game);
    
    //
    
    //第二种添加方式
        let play={
            name='run',
            [Symbol('say')]:function(){
                console.log('我会说话');
            },
            [Symbol('sleep')]:function(){
                console.log('我会睡觉');
            }
        }
        console.log(paly);
    
    //补充代码
        const title1 = Symbol("title")
        const title2 = Symbol("title")
        const info={
            [title1]:'zzl',
            [title2]:'wxl'
        }
    Symbol有很多内置方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    1.8.1 Symbol的数据类型及特性?
    // 数据类型的声明
    let sym = Symbol()
    // 作用:保证每一个对象的名字都是独一无二的
    
    // 可以接受字符串作为参数,作位对Symbol实例的描述
    let sym = Symbol('aini')
    // symbol 的参数是一个对象,可以调用该对象的toString 方法将其转换为字符串,然后生成一个symbol值
    // symbol函数的参数只是对当前Symbol 值的描述,因此相同参数的Symbol函数返回的值是不相等的
    let s1 = SYmbol('s1')  s2 = Symbol('s1')  cosnole.log(s1 === s2)  // false
    
    // symbol值不能与其他类型的值进行运算,否则会报错
    
    //symbol 值可以显示转换为字符串和Boolean 但是不能转换为Number
    
    // Object.getOwnPropertySymbol 方法可以获取指定对象的所有Symbol属性名
    
    // symbol声明的属性是没办法通过Object.key() 拿到,所以可以实现私有属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1.8.2 Symbol.iterator的作用?
    // Symbol.iterator 为每一个对象定义了默认的迭代器。该迭代器可以被for ... of 循环使用
    
    • 1

    1.9 迭代器

    任何数据结构只要部署了Iterator接口,就可以使用for…of 来遍历.

    1.9.1 具备iterator接口的数据类型
    // Array
    // Argunments
    // Set
    // Map
    // String
    // TypedArray
    // NodeList
    
    // 这个接口就是对象里面的一个属性,属性的名字叫Symbol.iterator,也可以自己对结构进行布置iterator接口。
    
    // -------------------------------------------------------------------------------------------
    
    for( let i in data){
    	i是键名
    }
    for( let i of data){
    	i是键值
    }
    const arr=['zzl','wxl'];
    console.log(arr);
    //arr里面就有Symbol.iterator这个属性。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    1.9.2 工作原理
    // 先创建一个指针对象,指向当前数据结构的起始位置
    // 第一次调用对象的next方法,指针自动指向数据结构的第一个成员
    // 接下来不断调用next方法,指针一直往后移动,直到指向最后一个成员
    // 每次调用next方法就会返回一个包含value和done属性(是否完成)的对象
    
    let xiyou = ['唐曾','孙悟空','猪八戒','沙僧']
    
    let iterator = xiyou[Symbol.iterator]();
    
    // 调用对象的next方法
    console.log(iterator.next())  // {value:'唐曾',done: false}
    console.log(iterator.next()) // {value:'孙悟空',done: false}
    console.log(iterator.next()) // {value:'猪八戒',done: false}
    console.log(iterator.next()) // {value:'沙僧',done: false}
    console.log(iterator.next()) // {value:undefined,done: true}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1.9.3 手写迭代器
    //声明一个对象
    const data={
        name:'zzl',
        lis:[
            'wxl',
            'll',
            'hll'
        ],
        
        //自己给某些结构加上iterator接口
        [Symbol.iterator](){
            //索引变量
            let index=0;
            let _this=this;
            return {
                //返回一个指针对象,即创建一个指针对象
                next:function(){
                    //创建对象的next方法
                    // 返回一个包含value和done属性(是否完成)的对象
                    if(index < _this.lis.length){
                        const result =  { value:_this.lis[index], done:false};
                        index++;
                        return result;
                    }else{                   
                        return {value: undefined, done:true};
                    }
                }
            };
        }
    }
    
    //自定义遍历这个对象
    for(let v of data){
        console.log(v);
    }
    console.log('--------------------')
    console.log(data);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    1.9.4 iterator接口的作用?
    // Iterator 是一个接口,用于处理所有不同的数据结构遍历器。只要数据结构定义了Iterator接口时可以用for of 来循环遍历
    
    // for of 循环的执行过程
        var arr = ['blue','green','yellow','balck','orange']
        let it = iterator(arr)
        console.log(it.next())
        console.log(it.next())
        console.log(it.next())
        console.log(it.next())
    
        function iterator(arr){
          let nextIndex = 0
          return {
            next: function() {
              return nextIndex < arr.length ? {
                value: arr[nextIndex ++] ,done: true
              } : {
                value : undefined,done : false
              }
            }
          }
        }
    
    // Iterator 接口部署在数据结构的Symbol.iteratro属性
    // 一个数据结构只要具有Symbol.Iterator属性,就可以认为是'可遍历的'
    // Symbol.Iterator 属性是一个函数,每次运行会返回一个生成器对象包含俩属性value和done
    
    // 原生具备Iterator接口的数据结构
    // Array   Map   Set   String   函数的arguments对象
    
    // 伪数组转换为真正数组的方法
    1Array.prototype.slice.call(arguments)
    2, Array.from(arguments)
    
    // 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    1.10 数组的常用方法

    1.10.1 forEach()
    // 第一个参数:数组元素;
    // 第二个参数:数组索引;
    // 第三个元素:数组对象本身
    
    var numbers = [1,2,3,4,5,4,3,2,1];
    numbers.forEach(function(item,index,array){
        console.log(item,index,array[index]);
    });
    
    // -----------------------------------------------------------
    // 为每个元素加 1
    var data = [1,2,3,4];
    data.forEach(function(v,i,a){
    	a[i] = v + 1; 
        //会改变原数组元素
    });
    console.log(data);
    
    // 如果只关心数组元素的值,可以只使用一个参数,额外的参数将被忽略
    
    // ------------------------------------------------------------------
    // 求和
    var data = [1,2,3,4];
    var sum = 0;
    data.forEach(function(value){ //第一个参数数组元素,相当于遍历多有元素;
        sum += value; 
        //不会改变原数组元素;
    });
    console.log(sum);
    
    // -------------------------------------------------------------------
    
    // (1)forEach()方法无法在所有元素都被传递给调用的函数之前终止遍历,即没有像 for 循环中使用的 break 语句;
    // (2)如果要提前终止,必须把 forEach()方法放在 try 块中,并能抛出一个异常:
    function foreach(a,f,t){
        try{
            a.forEach(f, t);
        }
        catch(e){
            if(e === foreach.break) return;
            else throw e;
        }
    }
    foreach.break = new Error("StopIteration");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    1.10.2 every() ------------ some()
    //(1)最相似的是 every()和 some(),它们都是数组的逻辑判定:用于判定数组元素是否满足某个条件;
    //(2)对 every(),传入的函数必须对每一项都返回 true,这个方法才返回 true;
    //(3)而 some()是只要传入的函数对数组中的某一项返回 true,就会返回 true,否则返回 false;
    
    var numbers = [1,2,3,4,5,4,3,2,1];
    var everyResult = numbers.every(function(item,index,array){
        return (item > 2);
    });
    console.log(everyResult); // false
    
    var someResult = numbers.some(function(item,index,array){
    	return (item > 2);
    });
    console.log(someResult); // true
    
    // (4)一旦 every()和 some()确定该返回什么值时,它们就会停止遍历数组元素;
    // (5)(some()在判定函数第一次返回 true 后就返回 true,但如果判定函数一直返回 false,它将会遍历整个数组;every()恰好相反,它在判定函数第一次返回 false 后就返回 false,但如果判定函数一直返回 true,它将会遍历整个数组)。
    // (6)根据数学上的惯例,在空数组上调用时,every()返回 true,some()返回 false;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    1.10.3 filter()
    //(1)返回的是数组元素是调用的数组的一个子集;
    //(2)回调函数是用来逻辑判定的,该函数返回 true 或 false;如果返回的是 true 或真值,则该函数处理的数组元素就被添加到返回的子集数组中;
    //(3)filter()方法会跳过稀疏数组中缺少的元素,它的返回数组总是密集的
    
    var numbers = [1,2,3,4,5,4,3,2,1];
    var filterResult = numbers.filter(function(item,index,array){
    	return item>2;
    });
    console.log(filterResult);
    
    var evenResult = numbers.filter(function(value,index){
    	return index % 2 == 0; // [1, 3, 5, 3, 1] index 是索引
    });
    console.log(evenResult);
    
    // 压缩稀疏数组
    var sparse = [1,,,4];
    var dense = sparse.filter(function(){
    	return true; //过滤稀疏元素
    });
    console.log(dense);
    
    // 压缩并删除 undefined 和 null 元素
    var sparse = [1,null,3,undefined,,6];
    var dense = sparse.filter(function(v){
    	return v !== undefined && v != null;
    });
    console.log(dense);
    
    //(注:该方法返回的是符合条件的数组元素;)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    1.10.4 map()
    //(1)将调用的数组的每个元素传递给回调函数,并将调用的结果组成一个新数组返回;
    //(2)其不会修改原始数组,如果是稀疏数组,返回的也是相同方式的稀疏数组,即具有相同的长度、相同的缺失元素;
    
    var numbers = [1,2,3,4,5,4,3,2,1];
    var mapResult = numbers.map(function(item,index,array){
    	return item*2;
    });
    console.log(mapResult);
    
    //-------------------------------------------------
    var a = [1,null,3,undefined,5];
    var b = a.map(function(v){
    	return v * v;
    });
    console.log(b);
    // --------------------------------------------
    
    //不做任何处理
    var spare = [1,,4,null,undefined,NaN,6];
    var dense = spare.map(function(v,i,a){
    });
    console.log(dense);
    
    // ----------------------------------------------------
    // 返回所有数组元素
    var spare = [1,,4,null,undefined,NaN,6];
    var dense = spare.map(function(v,i,a){
    	return v;
    });
    console.log(dense);
    
    // -----------------------------------------------------------
    //能处理的元素进项处理,空元素返回空元素;
    var spare = [1,,4,null,undefined,NaN,6];
    var dense = spare.map(function(v,i,a){
    	return v*v; //进行数据类型转换,由于 null 和 undefined 不能进行数据类型转换});
    console.log(dense) //,所以都返回 NaN
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    1.10.5 reduce() --------------------- reduceRight()
    //(1)reduce()和 reduceRight();这两个方法都会迭代数组的所有项,然后构建一个最终返回的值;
    //(2)其中,reduce()方法从数组的第一项开始,逐个遍历到最后;而 reduceRight 则从数组的最后一项开始,向前遍历到第一项;
    //(3)这两个方法都接收两个参数:调用的函数 callbackfn 和作为归并基础的初始值initialValue(可选的);
    //(4)这个函数接收 4 个参数:前一个值、当前值、项的索引和数组对象;其返回的任何值都会作为第一个参数自动传给下一项;第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项
    
    
    // 求和
    var values = [1,2,3,4];
    var sum = values.reduce(function(prev,cur,index,array){
    	return prev + cur;
    });
    console.log(sum); // 10
        // 第一次遍历:prev=1 cur=2;
        // 第二次遍历:prev=3 cur=3;
        // 第三次遍历:prev=6 cur=4;
        // 第四次遍历:prev=10
    /*
        说明:第一次执行回调函数,prev 与 cur 分别为数组的第 1 和第 2 项,即 prev 是 1,cur 是 2;第二次,
        prev 是第一次执行的结果,即 3(1+2 的结果),cur 是数组的第三项,即是 3,以此类推;
        reduce()参数函数的参数也可以只使用两个参数,如:
    */
    
    //-------------------------------------------------------------------------------
    // 求和
    var values = [1,2,3,4];
    	var sum = values.reduce(function(prev,cur){
    return prev + cur;
    });
    console.log(sum); // 10
    
    // ----------------------------------------------------------------------------------
    // 求积
    var product = values.reduce(function(prev,cur){
    	return prev * cur;
    });
    console.log(product); // 24
    
    //------------------------------------------------------------------------------
    // 求最大值
    var max = values.reduce(function(prev,cur){
    	return prev > cur ? prev : cur;
    });
    console.log(max); // 4
    // reduce()方法的第二个参数 initialValue 是回调函数的第一个参数 previousValue 的初始值;如:
    // 把以上所有示例添加第二个参数,如:
    var values = [1,2,3,4];
    var sum = values.reduce(function(prev,cur){
    return prev + cur;
    },2); // 12
    
    /*
    意思就是 pre 不是第一项,而是给 pre 赋一个值,cur 从第一项开始迭代说明,第一次调用时,prev 为 initialValue 值,即为 2,cur 为数组第一项,即为 1;第二次调用,prev 为 3,cur 为 2,以此类推;reduceRight()的作用类似,只不过方向相反,即按照数组索引从高到低(从右到左)处理数组;如:
    */
    var values = [1,2,3,4,5];
    var sum = values.reduceRight(function(prev,cur,index,array){
    	return prev + cur; //21
    },6); 
    //pre 的初始值为 6;
    console.log(sum); // 15
    
    
    // ---------------------------------------------------------------------
    // 求 2^(3^4),乘方操作的优先顺序是从右到左
    var a = [2,3,4];
    var big = a.reduceRight(function(accu, value){
    	return Math.pow(value, accu);
    });
    console.log(big);
    
    //在空数组上,不带初始值参数的 reduce()将导致类型异常;如果数组只有一个元素并且没有指定初始值,或者一个空数组并且指定了一个初始值,该方法只是简单的返回那个值而不会调用回调函数;
    
    var a = [];
    // var b1 = a.reduce(function(x,y){return x + y}); // no initial value 会报错
    // var b2 = a.reduce(function(x,y){return x + x}); / /也会报错
    var b3 = a.reduce(function(x,y){return x + y},3); //只返回初始值
    console.log(b3); // 3
    
    // (1)使用 reduce()还是 reduceRight(),主要取决于要从哪头开始遍历数组;除此之外,它们完全相同。
    //(2)reduce()和 reduceRight()是典型的函数式编程;有些地方,会把其回调函数称为化简函数,这个化简函数的作用就是用某种方法把两个值组合或化简为一个值,并返回化简后的值;如以上的示例,化简函数通过各种方法,组合了两个值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79

    1.11 生成器

    // 生成器就是一个特殊的函数,是异步编程新的解决方案。分别通过以下代码可知运行逻辑。
    
    function * fun(){
        console.log('zzl');
    }
    let a=fun();
    // console.log(a);//输出一个迭代器对象(有next方法)
    a.next(); // 输出zzl
    
    // --------------------------------------------
    function * fun(){
        console.log('zzl');
        console.log('wxl');
    }
    let a=fun();
    console.log(a);
    //输出一个迭代器对象(有next方法)
    a.next();
    //输出zzl wxl 即全部输出
    
    // -------------------------------------------------------------
    function * fun(){
        console.log('zzl');
        yield '我要暂停'
        console.log('wxl');
    }
    let a=fun();
    console.log(a);
    //输出一个迭代器对象(有next方法)
    a.next();
    //输出zzl 我要暂停
    
    // -----------------------------------------------------------------------------
    function * fun(){
        console.log('zzl');
        yield '我要暂停'
        console.log('wxl');
    }
    let a=fun();
    // console.log(a);//输出一个迭代器对象(有next方法)
    a.next();//输出zzl
    a.next();//输出wxl
    function * fun(){
        // console.log('zzl');
        yield '我要暂停'
        // console.log('wxl');
    }
    let a=fun();
    console.log(a);
    //输出一个迭代器对象(有next方法)
    for(i of fun()){
        console.log(i);//我要暂停
    }
    
    // -----------------------------------------------------
    function * fun(){
        // console.log('zzl');
        yield '我要暂停'
        // console.log('wxl');
    }
    let a=fun();
    console.log(a.next()); //输出 {value: '我要暂停', done: false}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    1.11.1 生成器函数的参数传递
    function * fun(arg){
        console.log(arg); //输出aaa
        let one = yield 111;
        console.log(one); //输出bbb
        let two = yield 222;
        console.log(two); //输出ccc
        let three = yield 333;
        console.log(three); //输出ddd
    }
    let a=fun('aaa');
    console.log(a.next());//第一次调用next
    //next方法可以传入实参
    //第二次调用next的实参将作为第一个yield的整体返回结果
    console.log(a.next('bbb')) // 输出{value: 222, done: false}
    console.log(a.next('ccc')) // 输出{value: 333, done: false}
    console.log(a.next('ddd')) // 输出{value: undefined, done: true}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    1.11.2 生成器函数实例
    // 实例1:在控制台每隔一秒分别打印111,222,333
    // 回调地狱
    
        setTimeout(() => {
            console.log(111);
            setTimeout(() => {
               console.log(222);
                setTimeout(() => {
                   console.log(333);
               }, 3000);
           }, 2000);
         }, 1000);
    
    // 解决方法
        function one(){
            setTimeout(()=>{
                console.log(111);
                a.next(); //定时器运行完调用下一个,实现了异步编程
            },1000)
        }
        function two(){
            setTimeout(()=>{
                console.log(222);
                a.next();
            },2000)
        }
        function three(){
            setTimeout(()=>{
                console.log(333);
                a.next();
            },3000)
        }
    
        function *fun(){
            yield one();
            yield two();
            yield three();
        }
    
    //调用生成器函数
    let a=fun();
    a.next();
    结果演示
    
    // -------------------------------------------------------------------------------------------------
    // 实例2 模拟获取用户数据,订单数据,商品数据
        function one(){
            setTimeout(()=>{
                let data='用户数据';
                a.next(data);//第二次调用next的实参将作为第一个yield的整体返回结果
            },1000)
        }
        function two(){
            setTimeout(()=>{
                let data='订单数据';
                a.next(data);
            },1000)
        }
        function three(){
            setTimeout(()=>{
                let data='商品数据';
                a.next(data);
            },1000)
        }
        function *fun(){
            let users= yield one(); 
            console.log(users); //用户数据 作为第一个yield的整体返回结果
            let orders= yield two();
            console.log(orders); // 订单数据
            let goods= yield three();
            console.log(goods); // 商品数据
        }
        //调用生成器函数
        let a=fun();
        a.next();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75

    1.12 Promise

    // 它是es6中异步编程的新的解决方案。相当于一个构造函数。
    
    function fun(){
        return new Promise((resolve,reject)=>{
            //如果成功就调用resolve
            let data='数据库中的数据';
            resolve(data); 
            //promise状态变为成功
            
            //如果失败就调用reject
            let err='数据库读取失败';
            reject(err);//promise状态变为失败
        })
    }
    
    var promise = fun()
    promise.then(
        //调用then方法
        function(success){
            // promise状态变为成功后then会调用第一个回调函数
            console.log(success);
        },function(err){
            // promise状态变为失败后then会调用第二个回调函数
            console.log(err);
        }
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1.12.1 promise封装读取文件
    cosnt fs = require('fs')
    
    fs.readFile('./aini.txt',(err,data) => {
        // 如果失败,则抛出异常
        if(err) throw err;
        // 如果没哟出错,则输出内容
        console.log(data.toString())
    })
    
    // 使用Promise封装
    cosnt p = new Promise(function(resolve,reject){
        fs.readFile('./aini.txt',(err,data) => {
            // 如果失败,则抛出异常
            if(err) reject(err)
            // 如果没哟出错,则输出内容
            resolve(data)
    	})
    })
    
    p.then(function(value){
        console.log(value.toString())
        
    },function(resson){
        console.log('读取失败!!!')
        
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1.12.2 Promise 封装Ajax请求
    const p = new Promise(function(resolve,reject){
        
        cosnt xhr = new XMLHttpRequest()
    
        xhr.open('GET','https://api.apiopen.top/getJoke')
    
        xhr.send()
    
        xhr.onreadystatechange = function(){
            if (xhr.randyState == 4){
                // 判断状态码
                if (xhr.status >= 200 && xhr.status <300){
                    // 表示成功
                    resolve(xhr.response)
                }else{
                    reject(xhr.status)
                }
            }
        }
    })
    
    p.then(function(value){
        console.log(value.toString())
        
    },function(resson){
        console.log(reason)  
    })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    1.12.3 Promise.property.then()
    const p = new Promise((resolve,reject){
       setTimeout(() => {
        resolve('用户数据')
    	}1000)                   
    })
    
    // 调用,then方法的结果也是promise对象,结果由回调函数的结果决定
    // 1,如果回调函数返回的结果是非promise类型的数据,状态为成功,返回值为对象的成功值,如果不写return,默认返回undefined,也是成功的promise
        const p1 = p.then(value => {
           console.log(value) 
           return '11232'  // 成功的Promise
        }.err => {
           console.warn(reason)   
        })
    
    // 2,如果返回的是promise对象,则这个promise对象的返回结果决定,then方法返回的结果
        const p1 = p.then(value => {
           console.log(value) 
           return new Promise(funtion(resolve,reject){
                resolve('ok')  // 成功,则then方法返回结果是成功
                reject('失败了')  // 失败,则then方法返回的结果是失败的
            )
        }.err => {
           console.warn(reason)   
        })
    
    // 如果抛出错误,then 也是个失败的结果
        const p1 = p.then(value => {
           console.log(value) 
           throw new Error('出错啦') // then的状态为rejected
        }.err => {
           console.warn(reason)   
        })
        
        
    // 链式调用
    p.then(value=> {
        return new Promise(function(resoleve,reject){
            resolve()
        })
    },reason => {
       
    }).then(value=> {
             return new Promise(function(resoleve,reject){
            resolve()
        })
    },reason => {
        
    }).then(value=> {
             return new Promise(function(resoleve,reject){
            resolve()
        })
    },reason => {
        
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    1.12.4 Promsie 多个文件内容读取
    // 回调地狱
    cosnt fs = require('fs')
    
    fs.readFile('./aini.txt',(err,data1) => {
        fs.readFile('./norah.txt',(err,data2) => {
        	 fs.readFile('./dilnur.txt',(err,data3) => {
        		let reault = data1 + data2 + data3
    		})
    	})
    })
    
    // 使用promise实现
    const p = new Promise(function(resolve,reject){
        fs.readFile('./aini/txt',(err,data) => {
            resolve(data)
        })
    })
    
    p.then(value => {
        return new Promise((resolve,reject) => {
           fs.readFile('./norah.txt',(err,data) => {
        		resolve([value,data])
    		})  
        }) 
    }).then(value => {
          return new Promise((resolve,reject) => {
           fs.readFile('./dilnur.txt',(err,data) => {
               value.push(data)
        	   resolve(data)
    		})  
        }) 
    }).then(value => {
        console.log(value.join('\r\n'))
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    1.12.5 Promise对象的catch()方法
    const p = new Promise((reslove,reject)=>{
        setTimeout(() => {
          reject('出错了')  
        },1000)
    })
    
    
    // 第一种
        p.then(function(value){
           // 成功的结果 
        },function(reason){
            // 失败的结果
        })
    
     // 第二种
        p.then(function(value){
            // 成功的结果
        }).catch(function(reason){
            //失败的结果
        })
    
    // 第三种
        p.then(function(value){
            // 成功的结果
        })
    
        p.catch(function(reason){
            //失败的结果
        })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    1.13 Set

    Set的数据类型及特性?
    // set 是ES6新增的复杂数据类型,类似于数组,但是值没有重复分
    // 新建
    	const s = new Set()
    // 可以接受数组或字符串当参数
        const s = new Set([1,2,3,4,2,3])
        const s1 = new Set('abcdeftg')
    // set 可以转化成数组,通过...扩展运算符或者Array.from()方法
        let arr = [...s]     // 等同于  Array.from(s)
        let arr1 = [...s1]   // 等同于  Array.from(s1)
    // set 用于数组去重
        
    // set 里面的判断机制是 === 运算符 (NaN 例外)
    let set = new Set()
    set.add(5) 
    set.add('5')  // 5 '5' 是两个元素
    
    // set 实例的属性和方法
    1,size() 返回长度
    2, has() 判断是否包含某个元素
    2,forEach  方法
        let set = new Set([1,3,2,3,54,3,2])
        console.log(set)
        set.forEach((item,index) => console.log(item + '-----------'  + index))
    	// item 和 key 值一样
    // 并集
    let arr = [1,2,3,4]
    let arr1 = [2,3,4,5,6]
    let a = new Set(arr)
    let b = new Set(arr1)
    let set = new Set([...a,...b])
    
    // 交集
    let arr = [1,2,3,4]
    let arr1 = [2,3,4,5,6]
    let a = new Set(arr)
    let b = new Set(arr1)
    
    let intersect = new Set([..a].filter(x => b.has(a)))
    
    // 差集
    let arr = [1,2,3,4]
    let arr1 = [2,3,4,5,6]
    let a = new Set(arr)
    let b = new Set(arr1)
    
    let chaji = new Set([..a].filter(x => !b.has(a)))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    1.14 Map

    Map的数据类型及特性?
    // Map 是ES6新增的复杂数据类型,类似于对象,也是键值对集合,但是键的范围不限于字符串,各种类型的值都可以当做键
    // Map 是值与值的对应,是更完美的键值对结构的提现
    
    // 新建Map数据的方法 
    1const m = new Map()
    
    // Map 的方法
    1, set()  m.set({x: 1}, 22)
    2, get    m.get({x: 1})
    3, has() 判断某个键是否存在  m.has({x:1})
    4, delete() 删除某个键值对
    
    // 判断是不是Map类型的数据结构
    let map = new Map() 
    1, map instanceof Map     //  true 通过原型链查找
    2, Object.prototype.toString.call(map) // [object, Map]
    
    // 为什么 Object.prototype.toString.call() 用的是原型链顶端的toString方法呢?
    // 因为数组和对象对toString方法都进行了改写
    
    // 可以接受数组作为参数
    // 注意的是:数组成员是一个个表示键值对的数组
    	let map = new Map(
          [
            ['name','aini'],
            ['age',22],
            [{name:'norah'},'这是一个对象']
          ]
        )
          // 一个坑
        map.get({name:'norah'})   // undefined  是因为 {} 与 {} 不是同一个对象
    
    // 解决办法:
    let obj = {name:'norah'}
    let map = new Map(
          [
            ['name','aini'],
            ['age',22],
            [obj,'这是一个对象']
          ]
        )
    map.get(obj)  // 这样才能获取正确的key值
    
    
    // map参数的扩展
    // 任何具有 Iterator 接口,且每个成员都是一个双元素的数组的数据结构,都可以当做map函数的参数
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    1.15 Class类

    // 以手机类为例
    function Phone(brand,price){
        this.brand = brand
        this.price = price
    }
    // 静态成员
    //相当于 python里的staticmethod
    Phone.name = '手机'
    Phone.change = function(){
        console.log('我可以改变世界')
    }
    
    // 相当于Python里的classmethod
    Phone.ptototype.size = "5.5英寸"
    Phone.prototy.call = function() {
        console.log('我可以打电话')
    }
    
    ler Huawei = new Phone('华为',5999)
    
    // ES6语法
    class Phone{
        // 构造函数方法
        constructor(brand,price){
            this.brand = brand
            this.call = call
        }
        
        // 语法必须使用这个方法,不能用ES5老语法
        call() {
            console.log('我可以打电话')
        }
    }
    
    ler Huawei = new Phone('华为',5999)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    1.15.1 构造函数继承
    function Phone(brand,price){
        this.brand = brand
        this.price = price
    }
    
    Phone.prototype.call = function(){
        console.log('我可以打电话')
    }
    
    //智能手机
    function SmartPhone(brand,price,color,size){
        Phone.call(this,brand,price){
            this.color = color
            this.size = size
        }
    }
    
    // 设置子级构造函数的原型
    SmartPhone.prototype = new Phone
    SmartPhone.prototype.constructor = SmartPhone
    
    // 声明子类的方法
    SmartPhone.prototype.photo = function(){
        console.log('我可以拍照')
    }
    
    SmartPhone.prototype.playGame = function() {
        console.log('我可以打游戏')
    }
    
    const chuzi = new SmartPhone("锤子",2499,'黑色','505')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    1.15.2 ES6里类的继承
    class Phone{
        constructor(brand,price){
            this.brand = brand
            this.price = price
        }
        
        call(){
            console.log('我可以打电话')
        }
    }
    
    class SmartPhone extends Phone{
        constructor(brand,price,color,size){
            super(brand,price)
            this.color = color
            this.size = size
        }
        photo() {
            console.log('我可以拍照')
        }
        playGame() {
            console.log('我可以打游戏')
        }
    }
    
    const xioami = new SmartPhone('xiaomi',2499,'黑色','505')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    1.15.3 子类对父类方法的重写
    class Phone{
        constructor(brand,price){
            this.brand = brand
            this.price = price
        }
        
        call(){
            console.log('我可以打电话')
        }
    }
    
    class SmartPhone extends Phone{
        constructor(brand,price,color,size){
            super(brand,price)
            this.color = color
            this.size = size
        }
        photo() {
            console.log('我可以拍照')
        }
        playGame() {
            console.log('我可以打游戏')
        }
        
        // 可以对父类方法重写
        call(){
            console.log('我可以进行视频通话')
        }
    }
    
    const xioami = new SmartPhone('xiaomi',2499,'黑色','505')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    1.15.4 class中的getter和setter
    class Phone{
        get price() {
            console.log('我被读取了')
            return 'i love you '
        }
        
        set price(val){
            console.log('价格修改了')
            this.val = val
        }
    }
    
    let s = new Phone()
    console.log(s.price) 
    // '我被读取了'
    // 'i love you ' -------------------> 这才是s.price的返回值
    
    s.price = 'free' // '价格修改了'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.16 数值扩展

    // Number.EPSILON  -------------------------- 是Javascript表示的最下精度
    // Number.isFinite -------------------------- 检测一个数是否为有限数
    // Number.isNaN -----------------------------检测一个数值是否为 NaN
    // Number.parseInt  Number.parseFloat-------- 字符串转整数
    // Number.isInteger ---------------------------判断一个数是否为整数
    // Math.trunc ----------------------------------将数字的小数部分抹掉
    // Math.sign -------------------------------------判断一个数到底为正数,负数还是0 -----------> 1  -1  0
    
    
    // 进制数的表示方法
    let b = 0b1010
    let o = 0o777
    let d = 100
    let x = 0xfff
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.17 对象方法扩展

    // Object.is --------------------------------> 判断两个值是否完全相等
    	console.log(Object.is(NaN,NaN)) // true
    	console.log(NaN === NaN)  // false
    // Object.assign ----------------------------> 对象的合并
    // Object.setPropertyOf ----------------------> 设置Object原型对象
    // Object.getPropertyOf-----------------------> 获取对象的属性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1.18 模块化

    // 模块化是指将一个大的文件,拆分成许多小的文件,然后将小文件组合起来,一个个小文件就是一个模块。
    
        // 防止命名冲突
        // 代码复用
        // 高维护性
    
    • 1
    • 2
    • 3
    • 4
    • 5
    1.18.1 ES Module
    //第一种暴露方法:分别暴露
    export let a='zzl'; //向外暴露
    export function fun(){
        console.log('我是谁');//向外暴露
    }
    
    //第二种暴露方法:统一暴露[ 注意{}导出的并不是对象 ]
    let a='zzl';
    export{a,fun};
    
    //第三种:默认暴露
    export default{
        a:'zzl',
        fun:function(){
            console.log('我是谁');
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    1.18.2 html代码引入js模块
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <script type="module">
            //第一种引入方式:引入mi.js暴露的模块
            import * as m from './模块化/m1.js';
            console.log(m.a); //zzl
    
            //第二种引入方式解构赋值形式:引入mi.js暴露的模块
            import {a as a1,fun} from './模块化/m1.js';
            console.log(a1);//可以给a一个别名a1 输出zzl
            //默认暴露的引入比较特殊,引入语法是
    
            import * as m from './模块化/m1.js';
            m.default.fun();
            //默认暴露的解构赋值
    
            import{default as mm} from './模块化/m1.js';
            console.log(mm);
            //简便形式 针对默认暴露
    
            import m from './模块化/m1.js';
            //动态调用模块,即使用时再导入
    
            import('./模块化/m1.js').then(module =>{
                 module.fun();
        })
        </script>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    1.18.3 module.exports 与 exports的使用与区别
    // 二者都是专门负责导出的东西,都属于commonJS规范,是同步加载的.
    
    // exports
        a.js
            const a=10
    
            //导出 (实际上exports就是一个对象)
            exports._a = a
    
        b.js
    
            // 引入a.js导出的对象,实际就是exports对象
            const ba =require('./a.js') // === exports对象
            console.log('输出',ba._a) //输出 10
    
    // exports
    	a.js
    		const a=10
            //导出 (实际上exports就是一个对象)
            // exports._a=a
            /**
             * 实际上module也是一个对象
             * 下边三行代码具体逻辑如下:
             * 1、module.exports = exports 即4行的exports,
             *      此时是引用赋值,并且可以继续使用原来b.js的导入方式
             * 2、重新给module.exports一个新对象地址{_a:a}
             * 3、b.js导入方式不变,因为只是对象地址,该对象module.exports依然是导出对象
             */
            module.exports = { 
                _a:a
            }
    	b.js
    		// 引入a.js导出的对象,实际就是module.exports对象
            const ba=require('./a.js') // === module.exports对象
    
            console.log('输出',ba._a) //输出 10
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    1.18.4 require()与import()
    if (true){
       import * from './a.js'
    }
    
    /*
    以上代码是错误的,因为imprt关键字不支持在这类代码里,但是require支持,因为require本质是函数,但是,require不支持在浏览器里运行,并且它是同步执行的,所以ESModule里可以用import函数来引入外部模块,并且它是异步执行的.
    */
    
    if(true){
        import('./a.js').then(res=>{
            console.log(res._a)
        }).catch(err=>{
            console.log(err)
        })
    }
    //