zoukankan      html  css  js  c++  java
  • ES6新特性

    let 声明变量以及特点

    1.变量不能重复声明

    let a = 1;
    let a = 2;
    
    // Uncaught SyntaxError: Identifier 'a' has already been declared
    

    2.let 作用域为块级作用域

    {
        let b = 1;
    }
    console.log(b);
    
    // Uncaught ReferenceError: b is not defined
    

    3.不存在变量提升

    console.log(c);
    let c = 1;
    
    // Uncaught ReferenceError: Cannot access 'c' before initialization
    // 代码执行之前不会收集变量,而如果使用var会赋一个初始值undefined
    

    4.不影响作用域链

    {
        let d = 1;
        function fn() {
            console.log(d);
        }
        fn();
    }
    
    // 函数作用域里没有变量d,会向上一级作用域找
    

    const 声明常量以及特点

    1.必须赋初始值

    const A;
    
    // Uncaught SyntaxError: Missing initializer in const declaration
    

    2.一般常量使用大写字母

    3.常量的值不能修改

    const B = 1;
    B = 2;
    
    // Uncaught TypeError: Assignment to constant variable.
    

    4.const 作用域为块级作用域

    {
        const C = 1;
    }
    console.log(C);
    
    // Uncaught ReferenceError: C is not defined
    

    5.对于数组和对象的元素修改,不会报错

    const NUMS = [1,2,3];
    NUMS.push(4);
    
    // 因为NUMS指向的地址没有改变
    // 声明数组和对象可以使用const
    

    变量的解构赋值

    1.数组的解构赋值

    const NUMS = [1,2,3];
    let [a,b,c] = NUMS;
    

    2.对象的解构赋值

    const STUDENT  = {
        name: '小明',
        age: 20,
        learn: function(){
            console.log('学习');
        }
    }
    let {name, age, learn} = STUDENT;
    

    模板字符串

    1.声明

    let str = `字符串`;
    console.log(str, typeof str);
    
    // 字符串 string
    

    2.内容中可以直接出现换行符

    let str = `<div>
    			   <span></span>
    		   </div>`;
    

    3.变量拼接

    let a = 1;
    let b = `${a}>0`;
    

    对象和函数的简化写法

    ES6 允许在大括号里面,直接写入变量和函数,作为对象的属性和方法

    let name = 'zhangsan';
    let change = function(){
        console.log('我是zhangsan');
    }
    
    const ZHANGSAN = {
        name,
        change
    }
    

    函数简化

    test(){
        console.log('test');
    }
    

    箭头函数以及声明特点

    1.声明

    () => {}
    

    2.this 是静态的,始终指向函数声明时所在作用域的 this 的值

    function getName() {
        console.log(this.name);
    }
    let getName2 = () => {
        console.log(this.name);
    };
    window.name = 'zhangsan';
    const STUDENT = {
        name: 'lisi'
    };
    

    1.直接调用

    getName();  // zhangsan 
    getName2(); // zhangsan
    

    2.call方法调用

    getName.call(STUDENT.name)  // lisi
    getName2.call(STUDENT.name) // zhangsan
    

    2.不能作为构造函数实例化对象

    let Person = (name, age) => {
        this.name = name;
        this.age = age;
    };
    let p1 = new Person('zhangsan', 20);
    console.log(p1);
    
    // Uncaught TypeError: Person is not a constructor
    

    3.不能使用 arguments 变量

    arguments可以获取函数调用时所有的实参

    let test = () => {
        console.log(arguments);
    };
    test(1,2,3);
    
    // Uncaught ReferenceError: arguments is not defined
    

    4.箭头函数的简写

    1.当形参有且只有一个时,可以省略小括号

    let add = n => {
        return n + n;
    }
    

    2.当代码体只有一条语句时,可以省略花括号,此时 return 也必须省略,语句的执行结果就是函数的返回值

    let add = (a, b) => a + b;
    

    箭头函数适合与 this 无关的回调,如定时器和数组的方法回调

    箭头函数不适合与 this 有关的回调,如事件回调和对象的方法

    函数参数的默认值设置

    1.形参初始值具有默认值的设置,一般放在最后

    function add(a, b, c=10){
        return a + b + c;
    }
    
    console.log(add(1, 2));  // 13
    console.log(add(1, 2, 3));  // 6
    

    2.与解构赋值结合

    function connect({host='127.0.0.1', username, password, port}){
        console.log(host);
        console.log(username);
        console.log(password);
        console.log(port);
    }
    connect({
        // host: 'localhost',
        username: 'root',
        password: '123456',
        port: 3306
    })
    
    // 127.0.0.1
    // root
    // 123456
    // 3306
    

    rest 参数

    ES6 引入 rest 参数,用于获取函数的实参,代替 arguments

    1.rest 参数放在函数形参位置,是一个数组

    function test(...args) {
        console.log(args);
    }
    test(1, 2, 3);
    
    // [1, 2, 3]
    

    2.rest 参数必须要放到最后

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

    扩展运算符

    扩展运算符可以把数组转化为参数的序列

    1.数组的合并

    const arr1 = [1, 2, 3];
    const arr2 = [4, 5, 6];
    const arr = [...arr1, ...arr2];
    console.log(arr);
    
    // [1, 2, 3, 4, 5, 6]
    

    2.数组的拷贝(浅拷贝)

    const arr1 = [1, 2, 3];
    const arr2 = [...arr1];
    console.log(arr2);
    
    // [1, 2, 3]
    

    3.将伪数组转换为真数组

    const divs = document.querySelectorAll('div');
    console.log(divs);
    const divArr = [...divs];
    console.log(typeof divArr);
    

    Symbol

    ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值,给对象添加属性或方法。它是 JavaScript 的第七种数据类型,是一种类似于字符串的数据类型

    JavaScript 数据类型:USONB

    U:undefined

    S:String Symbol

    O:Object

    N:Null Number

    B:Boolean

    1.Symbol 的值是唯一的,用来解决命名冲突的问题

    2.Symbol 的不能与其他数据进行运算

    3. Symbol 定义的对象属性不能使用 for...in 循环遍历,但是可以使用 Reflect.ownKeys 来获取对象的所有键名

    用 Symbol 给对象添加方法

    let game = {
        name: 'LOL',
        up(){
            console.log('up');
        },
        down(){
            console.log('down');
        }
    };
    let methods = {
        up1: Symbol(),
        down: Symbol()
    };
    game[methods.up1] = function () {
        console.log('up up');
    };
    game[methods.down] = function () {
        console.log('down down');
    };
    console.log(game);
    
    // {name: "LOL", up: ƒ, down: ƒ, Symbol(): ƒ, Symbol(): ƒ}
    
    let game2 = {
        name: 'LOL',
        [Symbol('say')]: function () {
            console.log('发言');
        }
    };
    console.log(game2);
    
    // {name: "LOL", Symbol(say): ƒ}
    

    迭代器

    迭代器(Iterator)是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要不输 Iterator 接口,就可以完成遍历操作

    1.ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费

    2.原生具备 Iterator 接口的数据(可用 for...of 遍历)

    1. Array
    2. Arguments
    3. Set
    4. Map
    5. String
    6. TypedArray
    7. NodeList

    3.工作原理

    1. 创建一个指针对象,指向当前数据结构的起始位置
    2. 第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
    3. 接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
    4. 每调用 next 方法返回一个包含 value 和 done 属性的对象

    数组使用 for...of

    const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
    for(let v of xiyou){
        console.log(v);
    }
    
    // 唐僧
    // 孙悟空
    // 猪八戒
    // 沙僧
    

    数组使用 for...in

    const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
    for(let k in xiyou){
        console.log(k);
    }
    
    // 0
    // 1
    // 2
    // 3
    

    可以看出 for...in 返回的是键名,而 for...of 返回的是键值

    为什么数组可以使用 for...of 遍历?

    const xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
    console.log(xiyou);
    

    发现其中包含一个 Symbol(Symbol.iterator): *ƒ values()* 属性

    console.log(xiyou[Symbol.iterator]());
    

    其中就包含一个 next 方法,用来遍历

    生成器函数

    生成器函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同

    1.声明

    function * gen(){}
    

    生成器函数的特殊:

    function * gen(){
        console.log('hello generator');
    }
    let iterator = gen();
    console.log(iterator);
    

    查看控制台并没有输出 hello generator,而返回的 iterator 是一个迭代器对象

    iterator.next();
    

    控制台输出 hello generator

    生成器函数直接调用并不会执行,必须调用 iterator 的 next 方法才会执行

    2.yield

    yield 是什么?

    • yield 是 ES6 的新关键字,使生成器函数执行暂停,yield 关键字后面的表达式的值返回给生成器的调用者。它可以被认为是一个基于生成器版本的 return 关键字。
    • yield 关键字实际返回一个 IteratorResult(迭代器)对象,它有两个属性,value 和 done,分别代表返回值和是否完成。
    • yield 无法单独工作,需要配合 generator (生成器)的其他函数,如 next,懒汉式操作,展现强大的主动控制特性。

    使用 yield

    function * gen(){
        yield 'AAA';
        yield 'BBB';
        yield 'CCC';
    }
    let iterator = gen();
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    console.log(iterator.next());
    
    /*
    {value: "AAA", done: false}
    {value: "BBB", done: false}
    {value: "CCC", done: false}
    {value: undefined, done: true}
    */
    

    三个 yield 把 gen 函数分成四块,通过 next 方法控制代码的执行

    因为 gen 返回的是一个迭代器对象,所以还可以使用 for...of 进行遍历

    function * gen(){
        yield 'AAA';
        yield 'BBB';
        yield 'CCC';
    }
    for(let v of gen()){
        console.log(v);
    }
    
    /*
    AAA
    BBB
    CCC
    */
    

    每一次返回的结果就是 yield 后面表达式的值

    3.生成器函数参数

    function * gen(arg){
        console.log(arg);
        yield 'AAA';
        yield 'BBB';
        yield 'CCC';
    }
    let iterator = gen(111);
    console.log(iterator.next());
    
    /*
    111
    {value: "AAA", done: false}
    */
    

    而 next 方法也可以传递参数

    function * gen(){
        let one = yield 'AAA';
        console.log('第一个yield的返回结果:'+one);
        yield 'BBB';
        yield 'CCC';
    }
    let iterator = gen();
    console.log(iterator.next());
    console.log(iterator.next(222));
    
    /*
    {value: "AAA", done: false}
    第一个yield的返回结果:222
    {value: "BBB", done: false}*/
    

    其中第二次调用 next 方法传入的实参将作为第一个 yield 语句的返回结果

    4.生成器函数实例

    需求:在控制台经过1s输出111,2s输出222,3s输出333

    传统做法:

    setTimeout(() => {
        console.log(111);
        setTimeout(() => {
            console.log(222);
            setTimeout(() => {
                console.log(333);
            },3000)
        },2000)
    },1000)
    

    但是这样就使得代码一层套一层,从而造成回调地狱,不利于维护

    使用生成器函数:

    function one() {
        setTimeout(() => {
            console.log(111);
            iterator.next();
        },1000)
    }
    function two() {
        setTimeout(() => {
            console.log(222);
            iterator.next();
        },2000)
    }
    function three() {
        setTimeout(() => {
            console.log(333);
            iterator.next();
        },3000)
    }
    
    function * gen() {
        yield one();
        yield two();
        yield three();
    }
    
    let iterator = gen();
    iterator.next();
    

    这样观感就很好,也利于维护,成功解决了回调地狱的问题

    Promise

    Promise 是 ES6 引入的异步编程的新解决方案,语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果

    1. Promise 对象的特点

    1. 对象的状态不受外界影响,Promise 对象代表一个异步操作,有三种状态:pending (进行中)、fulfilled (已成功)和 rejected (已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
    2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise 对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected,这两种情况只要发生,状态就凝固了,不会再变了。

    2.Promise 的 then 方法

    new Promise((resolve, reject) => {
        setTimeout(() => {
            let data = '用户数据';
            resolve(data);
        },2000)
    }).then(value => {
        console.log(value);
    }, reason => {
        console.error(reason);
    })
    

    resolve 表示将 Promise 对象的状态改为成功,此时就会执行 then 中的第一个回调函数

    new Promise((resolve, reject) => {
        setTimeout(() => {
            let err = '读取数据失败';
            reject(err);
        },2000)
    }).then(value => {
        console.log(value);
    }, reason => {
        console.error(reason);
    })
    

    reject 表示将 Promise 对象的状态改为失败,此时就会执行 then 中的第二个回调函数

    3.Promise 的 catch 方法

    new Promise((resolve, reject) => {
        setTimeout(() => {
            let err = '读取数据失败';
            reject(err);
        },2000)
    }).then(value => {
        console.log(value);
    }).catch(reason => {
        console.error(reason);
    })
    

    catch 用来捕获异常,同 then 方法中的第二个回调函数

    Set 集合

    ES6 提供了新的数据结构 Set。它类似于数组,但成员的值都是单一的,集合实现了 Iterator 接口,所以可以使用扩展运算符和 for...of 进行遍历

    1.Set 的属性和方法

    1. size:返回 Set 的元素个数
    2. add:增加一个新元素,返回当前集合
    3. delete:删除元素,返回 boolean 值
    4. has:检测集合中是否包含某个元素,返回 boolean 值
    5. clear:清空集合,返回 undefined

    2.声明 Set

    let s = new Set()
    

    3.集合实践

    1.数组去重

    const arr = [1,2,2,3,4,4,5];
    let result = [...new Set(arr)];
    console.log(result);
    

    2.求交集

    const arr = [1,2,2,3,4,4,5];
    const arr2 = [1,2,3];
    let result = [...new Set(arr)].filter(item => new Set(arr2).has(item));
    console.log(result);
    

    3.求并集

    const arr = [1,2,2,3,4,4,5];
    const arr2 = [1,2,3];
    let result = [...new Set([...arr, ...arr2])];
    console.log(result);
    

    4.求差集

    const arr = [1,2,2,3,4,4,5];
    const arr2 = [1,2,3];
    let result = [...new Set(arr)].filter(item => !(new Set(arr2).has(item)));
    console.log(result);
    

    Map 集合

    ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了 Iterator 接口,所以可以使用扩展运算符和 for...of 进行遍历

    1.Map 的属性和方法

    1. size:返回 Map 的元素个数
    2. set:增加一个新元素,返回当前 Map
    3. delete:删除元素,返回 boolean 值
    4. has:检测 Map 中是否包含某个元素,返回 boolean 值
    5. clear:清空集合,返回 undefined

    2.声明 Map

    let m = new Map()
    

    class 类

    ES6 提供了更接近传统语言的写法,引入了 class 这个概念,作为对象的模板。通过 class 关键字,可以定义类。ES6 的 class 可以看做只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的 class 写法只是让对象原型的写法更加清晰,更像面向对象编程的语法。

    1.ES5 与 ES6 实例化对象

    ES5 通过构造函数实例化对象

    function Phone(brand, price) {
        this.brand = brand;
        this.price = price;
    }
    Phone.prototype.slogan = () => {
        console.log('永远相信美好的事情即将发生');
    };
    let xiaomi = new Phone('小米', 4999);
    console.log(xiaomi);
    xiaomi.slogan();
    

    ES6 通过类实例化对象

    class Phone{
        constructor(brand, price) {
            this.brand = brand;
            this.price = price;
        }
        slogan(){
            console.log('Never Settle');
        }
    }
    let yijia = new Phone('一加', 4999);
    console.log(yijia);
    yijia.slogan();
    

    2.class 静态成员

    ES5 通过构造函数实例化对象时,构造函数也是一个对象

    function Phone() {}
    Phone.name = '小米';
    Phone.slogan = () => {
        console.log('永远相信美好的事情即将发生');
    };
    Phone.prototype.brand = 'XIAOMI';
    let xiaomi = new Phone();
    console.log(xiaomi.name);   // undefined
    console.log(xiaomi.brand);  // XIAOMI
    xiaomi.slogan();            // xiaomi.slogan is not a function
    

    函数对象的属性和方法不属于实例化对象,但是函数对象的原型对象上的属性和方法属于实例化对象

    ES6 通过class 实例化对象,添加静态成员

    class Phone{
        static name = '一加';
        static slogan(){
            console.log('Never Settle');
        }
    }
    let yijia = new Phone();
    console.log(yijia.name);   // undefined
    yijia.slogan();            // yijia.slogan is not a function
    

    static 标注的属性和方法,它们属于类而不属于实例化对象

    3.对象继承

    ES5 构造函数继承

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    Person.prototype.say = () => {
        console.log('我可以说话');
    };
    
    function Student(name, age, id, classname) {
        Person.call(this, name, age);
        this.id = id;
        this.classname = classname;
    }
    
    // 设置子级构造函数的原型
    Student.prototype =  new Person;
    
    Student.prototype.study = () => {
        console.log('我会学习');
    };
    
    const xiaoming = new Student('小明', 10, '001', '1班');
    console.log(xiaoming);    // {name: "小明", age: 10, id: "001", classname: "1班"}
    xiaoming.study();		  // 我会学习	
    xiaoming.say();           // 我会说话
    

    ES6 类继承

    class Person{
        constructor(name, age) {
            this.name = name;
            this.age = age;
        }
    
        say(){
            console.log('我会说话');
        }
    }
    
    class Student extends Person{
        constructor(name, age, id, classname) {
            super(name, age);
            this.id = id;
            this.classname = classname;
        }
    
        study(){
            console.log('我会学习');
        }
    }
    
    const xiaoming = new Student('小明', 10, '001', '1班');
    console.log(xiaoming);
    xiaoming.study();
    xiaoming.say();
    

    ES6 语法更加简洁,更加符合传统语言面向对象编程的语法

    4.子类对父类方法的重写

    say(){
        console.log('我会说英语');
    }
    xiaoming.say();   //我会说英语
    

    但是在子类重写的方法中不能直接调用对应父类的方法

    5.class 中的 getter 和 setter

    class Phone{
        get price(){
            console.log('读取价格');
            return '1999';
        }
    
        set price(newVal){
            console.log('修改价格'+newVal);
        }
    }
    
    const p = new Phone();
    p.price;
    p.price = '2999';
    

    数值扩展

    1.Number.EPSILON

    JavaScript 表示的最小精度,如果两数之差小于这个数,就可以认为两数相等

    function equal(a, b) {
        return Math.abs(a - b) < Number.EPSILON;
    }
    
    console.log(0.1+0.2 === 0.3);	// false
    console.log(equal(0.1+0.2, 0.3));	// true
    

    2.进制

    二进制

    console.log(0b1010);	// 10
    

    八进制

    console.log(0o777);		// 511
    

    十六进制

    console.log(0x123);		// 291		
    

    十进制

    console.log(100);		// 100
    

    3.Number.isFinite

    判断一个数是否有限

    console.log(Number.isFinite(100));		// true
    console.log(Number.isFinite(100/0));	//false	
    console.log(Number.isFinite(Infinity)); //false
    

    4.Number.isNaN

    判断一个数是否为 NaN

    console.log(Number.isNaN(100));		// false
    

    5.Number.parseInt

    字符串转整数

    console.log(Number.parseInt('123456七八九'));		// 123456
    

    6.Number.parseFloat

    字符串转浮点数

    console.log(Number.parseFloat('3.14156九'));		// 3.14156
    

    7.Number,isInteger

    判断一个数是否为整数

    console.log(Number.isInteger(123));		// true
    console.log(Number.isInteger('123'));	// false
    

    8.Math.trunc

    去除数字的小数部分

    console.log(Math.trunc(1.23));		// 1
    

    9.Math.sign

    判断一个数是正数、负数还是0

    console.log(Math.sign(100));	// 1
    console.log(Math.sign(-100));	// -1	
    console.log(Math.sign(0));		// 0
    

    对象方法扩展

    1.Object.is

    判断两个对象是否相等

    console.log(Object.is(100, 100));
    console.log(Object.is(NaN, NaN));		//注意这种方法判断两个NaN是相等的
    

    2.Object.assign

    合并两个对象

    const obj1 = {
        name: 'obj1',
        test1: 'test1'
    };
    const obj2 = {
        name: 'obj2',
        test2: 'test2'
    };
    
    const result = Object.assign(obj1, obj2);
    console.log(result);
    
    // {name: "obj2", test1: "test1", test2: "test2"}
    

    3.Object.setPrototypeOf 和 Object.getPrototypeOf

    设置原型对象和获取原型对象,不推荐使用

    模块化

    模块化是指将一个大的程序文件,拆分成许多小的文件,然后将小文件整合起来

    1.模块化的好处

    1. 防止命名冲突
    2. 代码复用
    3. 高维护性

    2.ES6 模块化语法

    模块功能主要由两个命令构成:export 和 import

    • export 命令用于规定模块的对外接口
    • import 命令用于输入其他模块提供的功能

    3.export 暴露语法

    1.分别暴露

    export const name = '小明';
    
    export function showName() {
        console.log('My Name is '+name);
    }
    
    // 导入
    <script type="module">
        import * as m1 from './m1.js'
    
        console.log(m1);
    </script>
    

    2.统一暴露

    const name = '小明';
    
    let showName = () => {
        console.log('My Name is '+name);
    };
    
    export {name, showName}
    

    3.默认暴露

    export default {
        name : '小明',
        showName : () => {
            console.log('My Name is '+name);
        }
    }
    
    // 导入
    <script type="module">
        import * as m3 from './m3.js'
    
        console.log(m3);
        m3.default.showName();	// 使用方法需要加上default
    </script>
    

    4.import 导入语法

    1.通用导入

    import * as m1 from './m1.js'
    

    2.解构赋值形式导入

    import {name, showName} from './m1.js';
    
    // 还可以设置别名
    import {name as xiaoming, showName} from './m1.js';
    
    import {default as m3} from './m3.js'
    

    3.简便形式,只适用于默认暴露

    import m3 from './m3.js'
    

    5.ES6 模块化方式2

    创建一个入口文件 app.js

    import * as m1 from './m1.js'
    import * as m2 from './m2.js'
    import * as m3 from './m3.js'
    

    在需要使用的页面引入 app.js

    <script src="app.js" type="module"></script>
    
  • 相关阅读:
    Go语言之进阶篇服务器如何知道用户需要什么资源
    Go语言之进阶篇请求报文格式分析
    Go语言之进阶篇实现并发聊天功能
    Go语言之进阶篇文件传输
    Go语言之进阶篇获取文件属性
    Go语言之进阶篇简单版并发服务器
    Go语言之进阶篇TCP相互通信
    Go语言之进阶篇 netcat工具的使用
    HAProxy的高级配置选项-ACL篇之匹配访问路径案例
    HAProxy的高级配置选项-ACL篇之基于文件后缀实现动静分离
  • 原文地址:https://www.cnblogs.com/codeDD/p/13288896.html
Copyright © 2011-2022 走看看