微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

JavaScript进阶--ES6新特性

目录

let声明变量:

const声明变量:

解构赋值:

模板字符串:

对象简化写法:

箭头函数:

参数默认值:

rest参数:

扩展运算符:

Symbol数据类型:

 迭代器(iterator):

生成器:

Promise:

Set:

Map:

第一次写那么多,脑壳疼


let声明变量:

  1. 变量不能重复声明,有效防止变量污染
  2. 作用域为块级作用域,只在代码块中有效,如
    if (true) {
        var a = 10;
        let b = 20;
    }
    console.log(a);
    console.log(b);

                             

  3. 不支持变量提升,即不允许在变量声明前使用变量(用var变量提升的值为undefined)

  4. 不影响作用域链,通俗说就是块级作用域1中的块级作用域2可以访问块级作用域中的let变量。即函数内仍可以使用全局的let变量。

const声明变量:

  1. 一定要赋初始值
  2. 一般来说命名使用大写字母
  3. const常量的值不可修改
  4. 作用于块级作用域,与let一样
  5. 允许对const数组、对象里面的元素进行修改(常量不可修改的本质为指向的地址不可改变)

解构赋值:

  • 数组的解构:将数组元素拆分赋值给不同的变量
    const T = [1, 2, 5, 4];
    let [a, b, c, d] = T;

    此时a,b,c,d变量分别为1,2,3,4。数量不匹配时超出的部分为undefined。

  • 对象的解构:将对象元素拆分赋值给不同的变量

    const data = {
        name: "baciii",
        age: 20,
        say: function() {
            console.log('say');
        }
    };
    let {
        name,
        age,
        say
    } = data;

    与数组解构的区别,此时被赋值的变量名必须与对象的元素名一致,顺序可以颠倒。

  • @H_502_101@

    模板字符串:

            声明方式:`str`(双反引号)

            特性:1.双反括号内可以出现换行(回车换行)

    let str1 = `123
    123
    123`;

                      2.可以进行变量拼接

    let name='Baciii';
    let p=`Iam${name}`;

    对象简化写法:

    1. 允许直接在大括号内写入已声明的变量和函数作为对象的属性方法
    let name = "baciii";
    let age = 20;
    var data = {
        name,
        age,
    }

         2. 方法声明简化,不需要写function直接声明

    var data = {
        say() {
            console.log('say');
        }
    }

    箭头函数

            语法:

    let fn=(a,b,c)=>{xxx}

            特性:

    1. 箭头函数的this始终是静态的,this始终指向函数声明是所在的作用域,并且不能被call()、bind()等改变this指向。
    2. 箭头函数不能作为构造函数实例化对象,原因是this的指向不会改变。
    3. 不能使用arguments()属性获取函数传递的实参。
    4. 缩写形式:当形参有且只有一个时,可以省略括号;当函数体只有一句时,可以省略花括号,且函数的返回值为该语句的执行结果。
      let pow=n =>n*n;

    参数认值:

            允许在声明函数时给参数赋认值,若不传递参数时则使用该认值。

    function fn(a=10,b=20,c=30){
        console.log(a,b,c);
    }

    rest参数:

            获取函数的实参,代替arguments。返回值为一个数组。 

            语法:...args(三个点)

    function fn(a, b, ...args) {
        console.log(args);//[3,4,5,6]
        console.log(arguments);//{1,2,3,4,5,6}
    }
    fn(1, 2, 3, 4, 5, 6);

             args返回的是一个数组,arguments返回的是一个对象。rest参数必须放在形参的最后一个

    扩展运算符:

            语法:...(伪)数组名

            作用:将数组拆分为以逗号分割每个元素的序列,可以直接当作参数传递。

            应用场景:将伪数组转化为真正的数组,使其可以使用数组的各种方法、数组的克隆等。

    const d=document.querySelectorAll('div');
    const divs=[...d];
    const div_copy=[...divs];

    Symbol数据类型:

             Symbol表示一个独一无二的值,是一个类似字符串的数据类型。

            即使是通过同一个字符串声明的Symbol()也不相同,而通过Symbol.for()用同一个字符串声明的Symbol相同,且地址相同(即为同一个变量)。可以将Symbol理解为一个唯一的不会重复的字符串,用其声明变量不会出现命名冲突的问题。

    let s1 = Symbol();
    let s2 = Symbol('abc');
    let s3 = Symbol('abc');
    console.log(s2 === s3);//false
    let s4 = Symbol.for('qwe');
    let s5 = Symbol.for('qwe');
    console.log(s4 === s5);//true

    可用于给对象添加理论上一定不会命名重复的元素。

    let test1 = Symbol('t1');
    let o = {
        [Symbol('test')]:function(){}
    }
    o[test1] = function() {
        console.log(111);
    }
    o[test1]();

     对象中的Symbol元素不会被for...in、forEach循环遍历,但是可以通过Object.getownPropertySymbols()方法获取当前对象所有用作属性名的Symbol值,该方法返回一个数组,可以借助数组元素访问到对象的Symbol值元素。也可以通过Symbol.keyFor()方法返回某Symbol对象的参数值

    let name=Symbol('name');
    console.log(Symbol.keyFor(name));//name

    Symbol()的参数只是作为一个标识所用,并不会特定创建某一特殊对象,所以不写参数也是一样的(个人理解,仅供参考)。

    Symbol还有很多内置函数,此处不一一赘述(主要是我也还没搞明白,下次再说叭)

     迭代器(iterator):

            迭代器是一个接口,为不同的数据结构提供一种遍历操作的机制。

            原生支持iterator接口的数据类型有:Array、Arguments、Set、Map、String、TypedArray、NodeList。

            for of迭代与for in迭代的区别:for in迭代返回的是每个元素的键名key,for of迭代返回的是每个元素的键值value。

    const arr = ['a', 'b', 'c', 'd'];
    for (let i in arr) {
        console.log(i);
    }
    for (let i of arr) {
        console.log(i);
    }

                                                                 

    iterator的工作原理: 

    1. 创建一个指针对象,指向要迭代的数据结构的起始位置,该对象由调用tar[Symbol.iterator]方法获得。
    2. 调用该指针对象的next方法,使其指向数据结构的第一个成员,并返回一个对象。该对象有value属性、done属性,value属性的值为当前被指向元素的属性值,done属性表示迭代是否完成。
    3. 接下来不断调用指针对象的next方法,直到访问到最后一个对象。
    4. 当访问到最后一个对象后的下一次调用next,返回一个value值为undefined、done值为true的对象,表示当前迭代已完成。

    我们可以根据工作原理给原生不支持iterator迭代的数据类型添加方法

                [Symbol.iterator]: function() {
                    let index = 0;
                    return {
                        next: function() {
                            if (index < data.member.length) {
                                const d = {
                                    value: data.member[index],
                                    done: false
                                }
                                index++;
                                return d;
                            } else {
                                return {
                                    value: undefined,
                                    done: true
                                }
                            }
                        }
                    }
                }

    简要说明:

           给要添加iterator的数据类型添加[Symbol.iterator]方法,首先声明一个变量记录迭代的次数,用于后期判断是否迭代完成。 该方法返回一个对象,该对象有一个next方法

            next方法会在迭代未结束时返回当前迭代元素的值value和是否完成迭代判断属性done。迭代完成后会返回value:undefined,done:true的一个对象。

            个人觉得与链表的实现差不多,这个操作之后就可以对该对象使用for of方法

    生成器:

            生成器是一种特殊的函数,可以用于异步编程

            基本语法:function * fn(){}

            生成函数内的语句不会直接执行,通过调试可以发现,生成函数内部有一个next()方法,我们可以通过next方法执行函数内部的语句。我们可以通过若干个yield语句将函数内部分为若干个+1部分,每次调用next()方法就按顺序执行一部分。

    function* fn() {
        console.log(123);
        let a = yield '123';
        console.log(a);
        console.log(456);
        let b = yield '456';
        console.log(b);
        console.log(789);
    }
    let f = fn();
    f.next();
    f.next('aaa');
    f.next('bbb');

            每次调用next()方法,该方法的返回值为执行部分的下一个yield语句后面的内容,如这里第一个next()方法的返回值为123.

            我们还可以给next()方法传参数,该参数会成为当前执行部分的上一个yield语句的返回值。(这里很绕,不要混淆两者),所以此处代码一个yield,即a的值为aaa。

            所以我们可以利用其分步执行的性质进行异步编程,其核心是避免回调地狱的问题产生。

            function one() {
                setTimeout(() => {
                    console.log(1);
                    i.next();
                }, 1000)
            }
    
            function two() {
                setTimeout(() => {
                    console.log(2);
                    i.next();
                }, 2000)
            }
    
            function three() {
                setTimeout(() => {
                    console.log(3);
                    i.next();
                }, 3000)
            }
    
            function* fun() {
                yield one();
                yield two();
                yield three();
            }
            let i = fun();
            i.next();

    简要解释:

            此处的三个yield语句分别为三个函数,当第一次调用next()方法时,执行第一个定时器函数,当执行完毕后自动调用next()方法执行下一个yield语句的函数(因为next()方法的返回值就是那个函数),以此类推。 (虽然只有两个玩意,但是还是很绕qaq)

    Promise:

            异步编程的新解决方

            语法:const p=new Promise(function(resolve,reject){});

            Promise对象有三种状态:初始化、成功、失败。当调用一个参数时,即resolve(),表示状态为成功,反之reject(),表示状态为失败。

            Promise.then()方法:该方法的参数为两个函数,Promise对象为成功时执行第一个函数,失败时执行第二个函数

    Promise读取文件操作:当读取成功时调用then参数1,失败时调用then参数2

    const { log } = require('console');
    const fs = require('fs');
    // fs.readFile('./promise.md', (err, data) => {
    //     //err 错误对象 失败时为null  data 读取结果
    //     if (err) throw err;
    //     //data是一个buffer
    //     console.log(data.toString());
    // });
    //使用promise封装
    const p = new Promise(function(resolve, reject) {
        fs.readFile('./promise.md', (err, data) => {
            if (err) reject(err);
            resolve(data);
        })
    });
    p.then(function(value) {
        console.log(value.toString());
    }, function(reason) {
        console.log("读取失败");
    });

    Promise封装Ajax:当http状态码正常时调用then参数1,反之调用then参数2

    const p = new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://api.apiopen.top/getJoke');
        xhr.send();
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response)
                } else {
                    reject(xhr.status)
                }
            }
        }
    });
    p.then(function(value) {
        console.log(value);
    }, function(reason) {
        console.log(reason);
    })

     then()方法

            then()方法的返回值为一个Promise对象,then()方法的回调函数的返回结果决定。

            若then()方法的回调函数返回的是一个非Promise对象,then()方法返回的Promise对象的状态为成功,且promisevalue为该返回值 不return认return undefined 同样状态为成功

            若then()方法的回调函数返回的是一个Promise对象,则then()方法返回的Promise对象由其决定,且promisevalue为Promise函数调用resolve或reject时的参数。

            由于then()方法返回的是一个Promise对象,所以同样地,新产生的Promise对象也有then()方法,所以一致链式调用then()方法,所以可以根据该特点进行异步编程,与生成函数类似。

    如利用Promise读取多个文件的操作:

    const { log } = require('console');
    const fs = require('fs');
    // fs.readFile('./promise.md', (err, data1) => {
    //     fs.readFile('./promise1.md', (err, data2) => {
    //         fs.readFile('./promise2.md', (err, data3) => {
    //             let data = data1 + data2 + data3;
    //             console.log(data);
    //         })
    //     })
    // });
    
    const p = new Promise((resolve, reject) => {
        fs.readFile('./promise.md', (err, data) => {
            resolve(data);
        })
    });
    p.then(function(value) {
        console.log(value.toString());
        return new Promise((resolve, reject) => {
            fs.readFile('./promise1.md', (err, data) => {
                resolve([value, data]);
            })
        })
    }).then(function(value) {
        console.log(value);
        return new Promise((resolve, reject) => {
            fs.readFile('./promise2.md', (err, data) => {
                value.push(data);
                resolve(value);
            })
        })
    }).then(function(value) {
        console.log(value.toString());
    })

    简要说明:

            第二次之后的读取文件都在then()方法的回调函数中进行,这样可以利用promisevalue访问到上一次读取到的文件的信息,并进行操作。其中一个步骤出错后面不再执行。(个人感觉也跟链表有点像)

    Set:

            一种新的数据结构,类似于数组,但成员的值是唯一的,加入成员时会自动去重。

            基本操作:size 返回元素个数 add 添加元素 delete 删除元素 has 判断是否存在该元素 clear 清空操作 

            该数据结构可以使用for of遍历,基本运用场景:与扩展运算符交互紧密,可以将其与数组进行转换。

    let arr = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    //数组去重
    // let result = new Set(arr); //此时result不是一个数组 是一个集合
    // let r = [...result] //将result转化为一个数组
    // console.log(result);
    // console.log(r);
    
    //求交集
    let arr2 = [4, 5, 6, 5, 6];
    let result = [...new Set(arr)].filter(item => {
        return new Set(arr2).has(item);
    });
    console.log(result);
    
    //求并集
    let arr3 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
    let arr4 = [4, 5, 6, 5, 4];
    let r = [...new Set([...arr3, ...arr4])];
    console.log(r);
    
    //求差集
    let diff = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
    console.log(diff);

    Map:

            一种以键值对形式存储的数据结构,键可以是各种数据类型,可以使用for of遍历。该数据结构的返回值的每一项为一个数组,数组的一个成员为键名key

    let m = new Map();
    m.set('name', 'baciii');
    m.set('say', function() {
        console.log('say');
    })

    第二个成员为键值value。 

    class的get()、set()方法

            当我们读取、更改类内的属性时,相应的get()、set()方法就会被自动调用,我们可以通过重写该方法在读取或修改属性时进行操作。

    class Phone{
        get price(){
            let newVal='';
            return newVal;
        }
        set price(newVal){
            console.log('newVal is'+newVal);
        }
    }

    get()方法的返回值为当前属性的读取值,set()方法必须有参数,该参数为当前属性的新值。

    第一次写那么多,脑壳疼

    最后一句,新冠赶紧死,我想回学校!

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐