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

    一、let&&const  块级作用域    const也是块级作用域

    let、const不存在变量提升

    // var 的情况
    console.log(foo); // 输出undefined
    var foo = 2;
    
    // let 的情况
    console.log(bar); // 报错ReferenceError
    let bar = 2;

     var与let的区别:

    (1)var定义的变量,作用域是整个封闭函数,是全域的。通过let定义的变量,作用域是在块内的;

    (2)关于变量的提升。 var可以变量提升,但是let不存在变量提升。

    (3)let不允许在相同的作用域内,重复声明同一个变量。

    // 报错
    function func() {
        var a = 1;
        let a = 10;
    } 
    //如果在当前作用域中嵌套另一个作用域,便可在嵌套作用域中用let声明同名变量
    function func() {
        var a = 1;
        if(condition){
            let a = 10;
        }
    }     
    var a=10;
    function foo(){
          console.log(a);
          let a=20;
    }
    foo()//ReferenceError
    //let和const声明可以让变量在其作用域上受限于它所使用的块、语句或表达式,与var不同的是,这些变量没有被提升,并且有一个所谓的暂时死区(TDZ)试图访问TDZ中
    的这些变量将引发ReferenceError错误,因为只有执行到达声明时才能访问它们。

    为什么需要块级作用域:

    ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景

    • 第一种场景,内层变量可能会覆盖外层变量。
    var tmp = new Date();
    
    function f() {
      console.log(tmp);
      if (false) {
        var tmp = 'hello world';
      }
    }
    f(); // undefined

    上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。

    • 第二种场景,用来计数的循环变量泄露为全局变量。

    var s = 'hello';
    for (var i = 0; i < s.length; i++) {
      console.log(s[i]);
    }
    
    console.log(i); // 5

      上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。

    • 第三种场景,循环中的函数
    //(1)在循环中使用var声明
    //循环中每次迭代同时共享着变量i,循环内部创建的函数全都保留了对相同变量的引用,循环结束时变量i的值为10
    var a = [];
    for (var i = 0; i < 10; i++) {
      a.push(function () {
        console.log(i);
      });
    }
    a.forEach(function(item){
      item();//输出10次数字10
    })
    
    //(2)为解决以上问题,一般使用立即执行函数,以强制生成变量的副本,如
    for (let i = 0; i < 10; i++) {
    a.push((function (num) {
        return function(){
            console.log(num);
        }
      })(i));
    }
    
    
    //(3)在循环中使用let声明
    //每次循环时let声明都会创建一个新变量i,并将其初始化为当前值,所以内部函数每次都能得到属于他们自己的i的副本
    for (let i = 0; i < 10; i++) {
    a.push(function () {
        console.log(i);
      });
     }
    a.forEach(function(item){
      item();//输出0-9
    })  

    const用于声明一个常量,设定后值不会发生改变,强行对其进行重新赋值会报错。

    这个不可变对于基础类型(按值访问)而言是值不可变;而对于引用类型(按引用访问)是引用地址不变,比如用const声明对象后,可以修改该对象的属性值。

    const num=123;
    num=456;
    console.log(num);//Uncaught SyntaxError: Identifier 'num' has already been declared
    
    const obj={
        a:2
    }
    //可以修改对象属性的值
    obj.a=4;
    console.log(obj.a);//4
    
    //抛出语法错误
    obj={
      a:4      
    }

     1.1  新增数据类型:Symbol

    Symbol功能类似于一种标识唯一性的ID,通常情况下,我们可以通过调用Symbol()函数来创建一个Symbol实例。

    let s1=Symbol();

    或者可以传入一个可选的字符串参数

    let s2=Symbol('another symbol');

    由于Symbol是一种基础数据类型,所以当我们使用typeof去检查它的类型的时候,会返回一个属于自己的类型symbol。

    另外,每个Symbol实例都是唯一的,因此,当你比较两个Symbol实例的时候,将总会返回false。

    let s2=Symbol('another symbol');
    let s3=Symbol('another symbol');
    s2===s3  //false

    二、变量的解构赋值

      ES6允许按照一定的模式,从数组和对象中提取值,对变量进行赋值,称为解构。本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。

    let[a,b,c]=[1,2,3];//等同于let a = 1;let b = 2;let c = 3;

    如果解构不成功,变量的值就等于undefined

    let [bar, foo] = [1];
    console.log(bar);//1
    console.log(foo);//undefined

    解构不仅可以用于数组,还可以用于对象。

    let { foo, bar } = { foo: "aaa", bar: "bbb" };
    foo // "aaa"
    bar // "bbb"

    三、箭头函数

    ES6 允许使用“箭头”(=>)定义函数。

    var f = v => v;等同于
    var f = function(v) {
      return v;
    };

    如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。

    
    
    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
    var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };

    箭头函数与传统的js函数的区别:
    (1)箭头函数体内的this对象,就是函数定义时所在的对象,而普通函数的this是函数运行时所在的对象。且箭头函数内部的this值不可被改变
    (2)不可以当作构造函数,也就是说不可以使用new命令,否则会抛出一个错误。

        因为箭头函数在创建时this对象就绑定了,更不会指向对象实例。

    //普通函数
    function fun(){
        console.log('普通函数');
    }
    var p=new fun();//普通函数
    
    //箭头函数
    var fun=()=>{
        console.log('箭头函数');
    }
    var p=new fun();//Uncaught TypeError: fun is not a constructor

    (3)不可以使用arguments对象,该对象在函数体内不存在。

    //普通函数
    function fun(x,y){
        console.log(arguments[0]);
    }
    fun('a','b');//a
    
    //箭头函数
    var fun=(x,y)=>{
        console.log(arguments[0]);
    }
    fun('a','b');//ƒ (e,t){return new v.fn.init(e,t,n)}

    (4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

    (5)没有原型,因为不可以通过new关键字调用箭头函数,因而没有构建原型的需求,所以箭头函数不存在prototype这个属性。

     
    ES5与ES6中函数this的指向不同

    箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。下面是另一个例子。

    function Timer() {
      this.s1 = 0;
      this.s2 = 0;
      // 箭头函数
      setInterval(() => this.s1++, 1000);
      // 普通函数
      setInterval(function () {
        this.s2++;
      }, 1000);
    }
    
    var timer = new Timer();
    
    setTimeout(() => console.log('s1: ', timer.s1), 3100);
    setTimeout(() => console.log('s2: ', timer.s2), 3100);
    // s1: 3
    // s2: 0

    上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),
    后者的this指向运行时所在的作用域(即全局对象)。所以,3100毫秒之后,timer.s1被更新了3次,而timer.s2一次都没更新。

    this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。

    四、类
    ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类,与多数传统语言类似。
    为了简化原型链继承,es6的class大大减少了相关代码,不用再去构建有序的原型链,直接用extend就能实现继承。
    //原型
    function Student(name) {
        this.name = name;
    }
    
    Student.prototype.hello = function () {
        alert('Hello, ' + this.name + '!');
    }
    //
    class Student {
        constructor(name) {
            this.name = name;
        }
    
        hello() {
            alert('Hello, ' + this.name + '!');
        }
    }
    var xiaoming = new Student('小明');
    xiaoming.hello();
    
    

    class继承

    用class定义对象的另一个好处就是继承更方便了,直接用extends来实现

    class PrimaryStudent extends Student{
        constructor(name,grade){
            super(name);
            this.grade=grade;
        }
        myGrade(){
            console.log('my grade is'+this.grade);
        }
    }
    var stu=new PrimaryStudent('an','32');
    stu.hello();//hello,an
    stu.myGrade();//my grade is32

    五、字符串模板
    模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

    六、默认参数值

    ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。

     

    七、for of/in遍历

    区别

    (1)for in遍历的是数组的索引,而for of遍历的是数组的元素值;

    (2)for in更适合遍历对象,不要使用for in遍历数组;

    for...in

    Array.prototype.method=function(){
        console.log(this.length);
    }
    var myArr=[1,2,3,4,5];
    console.log('for...in遍历');
    for(var i in myArr){
        console.log(myArr[i])
    }

     遍历结果:

                              

    当你需要向数组中添加额外的方法(或另一个对象)时,for...in 会遍历数组所有可枚举的属性,意味着如果向数组的原型中添加任何其他属性,这些属性也会出现在循环中。

    for/in与Object.keys(obj)的区别:

    最主要的区别是for/in会走原型链,而Object.keys()不会走原型链

    for...of

    for...of遍历的只是数组内的元素,不包含数组原型上的属性和方法。
             

    (3)for of只能遍历拥有迭代器对象的对象

    var obj={
        a:1,
        b:2,
        c:3
    }
    for(let i in obj){
        console.log(i)//a,b,c
    }
    for(let item of obj){
        console.log(item)//Uncaught TypeError: obj is not iterable
    }

    一个数据结构只要部署了Symbol.iterator属性,就被视为具有iterator接口,就可以使用for of循环。

    而对象是没有Symbol.iterator这个属性,所以使用for of会报obj is not iterable。

    for of不同于forEach,他可以与break、continue和return配合使用,也就是说for of循环可以随时退出循环,而forach()不能跳出循环,break报错

    哪些数据结构部署了Symbol.iterator属性了呢??

    • 数组Array
    • Map
    • Set
    • String
    • arguments对象

    以上这些都可以直接使用for of循环,凡是部署了iterator接口的数据结构也都可以使用数组的扩展运算符和解构赋值操作。

    假如想要对象也可以使用for of循环怎么办?使用Objct.keys()获取对象的key值集合后,再使用for of。

    var obj={
        a:1,
        b:2,
        c:3
    }
    for(let item of Object.keys(obj)){
        console.log(item)//a,b,c
    }

    判断一个数据结构是否具有可迭代能力,只有当数据具有Symbol.iterator属性的时候才可以使用for...of进行迭代。

    console.log(Array.prototype.hasOwnProperty(Symbol.iterator));//true

    console.log(Object.prototype.hasOwnProperty(Symbol.iterator));//false

    八、扩展运算符

    扩展运算符(用三个连续的点 (...) 表示)是 ES6 中的新概念,使你能够将字面量对象展开为多个元素

    通过减少赋值语句的使用,或者减少通过下标访问数组或对象的方式,使代码更加简洁优雅,可读性更佳。

    const books = ["Don Quixote", "The Hobbit", "Alice in Wonderland", "Tale of Two Cities"];
    console.log(...books);
    
    Prints: Don Quixote The Hobbit Alice in Wonderland Tale of Two Cities

    应用:

    (1)复制数组, 使用扩展运算符拷贝对象或数组时,只对第一层深拷贝,二层及以后为浅拷贝

    var a1=[1,3,2,5,3];
    //ES5
    var a2=a1.concat();
    //ES6
    var a3=[...a1];

    (2)合并多个数组

    //ES5
    var a2=arr1.concat(arr2,arr3);
    //ES6
    var a3=[...arr1,...arr2,...arr3];

    (3)使用扩展运算符展开数组代替apply方法,将数组转为函数的参数。

    //ES5
    var a2=Math.max.apply(this,[1,5,3,8,6]);
    //ES6
    var a3=Math.max(...[1,5,3,8,6]);
    //相当于Math.max(1,5,3,8,6);

    (4)将字符串转为数组

    var str='abcde';
    //ES5
    var a2=str.split('');
    //ES6
    var a3=[...str];
    //["a", "b", "c", "d", "e"]

    (5)Map结构

    let map=new Map([
        [1,'one1'],
        [2,'one2'],
        [3,'one3']
    ]);
    let arr=[...map.keys()];
    console.log(arr);//[1,2,3]
    九、Set数据结构

    ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。   可用于数组去重

    
    

    Set本身是一个构造函数,用来生成 Set 数据结构。 Set函数接收一个数组作为参数用来初始化。

    
    
    // 例一
    const set = new Set([1, 2, 3, 4, 4]);
    [...set] 获Array.from(set);
    // [1, 2, 3, 4]
    
    // 例二
    const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
    items.size // 5
    
    

    (1)se结构与数组的区别

    • 添加元素   add()        如:const set = new Set([1, 2, 3, 4, 4]);  set.add('1');
    • 删除元素   set.delete(value);
    • 判断某值是否存在  set.has(value)
    • 清除所有值   set.clear();
    • 获取长度   set.size

    (2)将set结构转换为数组:

    • [...set]
    • Array.from(set)

     (3)Set和数组的相同点:

    • 数组的map()和filter()方法用于set数据结构

       注意写法:(不是在set实例后面写方法,是在参数数组后面)

               

    • Set支持for...of和forEach循环

      注意: 在forEach((item,index){})循环中发现:Set的value值与index值相同

      Set结构:

      

      数组:

      

    10、Map数据结构
    Map结构出现的目的:
    由于JS的对象(Object)本质上是键值对的集合(Hash结构),但是传统意义上只能用字符串当作键,这就给它的使用带来了很大的限制。
      ES6提供的Map数据结构,类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串——值”的对应,Map结构提供了“值——值”的对应,是一种更加完善的Hash结构,如果你需要“键值对”的数据结构
    ,Map比Object更合适。

    传统对象键名必须为字符串
    let obj={
        a:1,
        666:2
    }
    console.log(obj.666);//报错
    map结构是一种“值对值”的数据结构
    let map=new Map();
    map.set(666,2);
    console.log(map.get(666));//2

    Map结构的属性和方法

    (1)属性:size
    (2)set(key,val):向字典中添加新元素
    (3)get(key):通过键查找特定的数值并返回
    (4)has(key):如果键存在字典中返回true
    (5)delete(key)
    (6)clear():将字典中的所有元素都删除

    遍历方法
    (1)keys():将字典中包含的所有键名以数组形式返回
    (2)values():将字典中包含的所有数值以数组的形式返回
    (3)forEach()遍历字典中的成员

    Map结构初始化的参数,可以接受一个二维数组作为参数。
    let map=new Map([
        ['name','张三'],
        ['title','Author']
    ])
    console.log(map.size)//2
    console.log(map.has('name'))//true
    console.log(map.get('name'))//"张三"

    for(let key of map.keys()){ console.log(key);//name title } for(let val of map.values()){ console.log(val);//张三 Author }

    11、ES6新增的数组方法?
    (1)map()
    map():对数组的每个元素进行一定的操作(映射)后,会返回一个新的数组。

       map()传参与forEach()相同

    (2)forEach()
      forEach():该方法对数组中的每一项运行给定函数,该方法没有返回值。其实就是遍历循环
      forEach()包含两个参数,第一个参数是匿名函数,第二个参数是this。匿名函数中包含三个参数:item(每一项的值),index(每一项的索引),self(代表所遍历函数自己)

      map()和forEach()的区别:
        map()会返回一个新的数组,forEach()不会返回数据;
        forach()允许改变原数组的元素,map()返回的是新数组,不会修改原数组。
        
    (3)filter()
      filter():该方法对数组中的每一项运行给定函数,返回该函数会返回每一相对应的true或false,最后返回包含留下为true对应的元素的数组。

      filter()传参与forEach()相同。

      filter()用法:
    • 创建一个数组,判断数组中是否存在某个值或过滤某些值
    var arr=[2,4,3,2,5];
    console.log(arr.filter(item=>item==3));//[3]
    • 去掉数组中的空数组、空字符串、undefined、null
    var arr = ['1','2',undefined,'','3.jpg',undefined,null];
    var newArr = arr.filter(function(item){
        return item;
    })
    console.log(newArr);//["1", "2", "3.jpg"]
    • 数组去重
    var arr = [1,2,4,5,3,2,4,3,6,8,6,8,8,8];
    var newArr=arr.filter(function(item,index,self){
        return self.indexOf(item)==index;
    })
    console.log(newArr);//[1, 2, 4, 5, 3, 6, 8]

    (4)reduce()
      归并方法reduce():该方法会迭代数组中的每一项,然后生成一个最终返回值。接收两个参数(回调函数,初始值),将第二个参数作为初始值
      数组求和来启动累积。
      reduce()接收一个函数作为累加器,回调函数接收最多四个参数:初始值(或者上一次回调函数的返回值),当前元素值,当前索引,调用 reduce 的数组。
    
    
    //数组求和
    var arr = [1,2,4,5,3];
    var sum=arr.reduce(function(pre,item){
            return pre+item;
    },0)
    console.log(sum);//15

    (5)every()
      对数组的每一项都运行给定的函数,如果每一项都返回true,则返回true,否则返回false。

    (6)some()
      对数组的每一项都运行给定的函数,如果任一项返回true,则返回true。
      
    function add(){
        var arr=[1,2,3,4,5];
        return arr.every(function(item){
            return item>3;
        })
    }
    console.log(add());//false
    
    function add(){
        var arr=[1,2,3,4,5];
        return arr.some(function(item){
            return item>3;
        })
    }
    console.log(add());//true
    
    

    11、模块

    导入、导出

    12、Promise

     13、Object.assign()、Object.create()

  • 相关阅读:
    iframe+json
    qw
    MySql数据类型和Java数据类型对应一览
    MyEclipse生成get/set注释
    Redis集群_主从配置
    MyBatis输出sql需要log4j.properties配置
    默认没有创建两次定时实例的
    spring+freemarker+redis
    jquery easyui 扩展验证
    vs2010 安装 Ajax Control Toolkit
  • 原文地址:https://www.cnblogs.com/xiaoan0705/p/8671495.html
Copyright © 2011-2022 走看看