• ES6常用知识总结(20%的知识占80%的份额)


    一、变量和常量

    var的缺点:(1)var可以多次声明同一个变量;   (2)var会造成变量提升 

    (function rr() {  
      if(true) {  
        var a = 666;  
      }  
      console.log(a); //输出666  
    })()  
    

      

    let以及const都是块级作用域。我们常常使用let来声明一个值会被改变的变量,而使用const来声明一个值不会被改变的变量,也可以称之为常量。

    常见题:

    for(var a = 0; a < 3; a++) {  
      setTimeout(function() {  
        console.log(a);  
      }, 1000)  
    }  
    //输出结果都为3 

        如何将结果输出为0, 1, 2

        es5处理方法 -- 用函数制造块级作用域

    for(var a = 0; a < 3; a++) {  
      (function (a) {  
        setTimeout(function() {  
          console.log(a);  
        }, 1000)  
      })(a)  
    }  
    1. //输出结果0,1,2  

        es6处理方法 -- 更加简单明了

    for(let a = 0; a < 3; a++) {  
      setTimeout(function() {  
        console.log(a);  
      }, 1000)  
    }  
    1. //输出结果为:0,1,2  

    二、解构赋值(Destructuring)

    1、对象的解构赋值

    const props = {
        className: 'tiger-button',
        loading: false,
        clicked: true,
        disabled: 'disabled'
    }

    当我们想要取得其中的2个值:loading与clicked时:

     

    // es5
    var loading = props.loading;
    var clicked = props.clicked;
    
    // es6
    let { loading, clicked } = props;
    
    // 给一个默认值,当props对象中找不到loading时,loading就等于该默认值,只有严格等于undifined才会使用默认值
    let { loading = false, clicked } = props;
    变量名不一致时:
    let { loading: loadprop, clicked: propclick } = props;
    
    // loadprop = false, propclick = true
    2、数组的解构赋值
    // es6
    let arr = [1, 2, 3];
    let [a, b, c] = arr;
    
    // es5
    var arr = [1, 2, 3];
    var a = arr[0];
    var b = arr[1];
    var c = arr[2];

    数组以序列号一一对应,这是一个有序的对应关系。
    而对象根据属性名一一对应,这是一个无序的对应关系,属性名一致即可。根据这个特性,使用解析结构从对象中获取属性值更加具有可用性。
    ES6解构赋值
    数值与布尔值的解构赋值会先转化为对象

    三、函数

    1、箭头函数(array function)
    // es5
    var fn = function(a, b) {
        return a + b; 
    }
    // es6 箭头函数写法,当函数直接被return时,可以省略函数体的括号
    const fn = (a, b) => a + b;
    // es5 var foo = function() {
      var a = 20;
      var b = 30;
      return a + b; 
    }
    // es6 const foo = () => {
      const a = 20;
      const b = 30;
      return a + b; 
    }

    2、形参默认值(default)

    ES5的默认值写法
      
    function sum(x,y){
             x=x||10;
             y=y||20;
      return x+y;
     }

    ES6的默认值写法:

    function sum(x = 10, y = 20) {
        return x + y;
    }
    
    console.log(add());

    注意:1、箭头函数是匿名函数,不能作为构造函数,不能使用new

    let FunConstructor = () => {
        console.log('lll');
    }
    
    let fc = new FunConstructor();

    2、箭头函数中,没有自己的this。如果你在箭头函数中使用了this,那么该this一定就是外层的this,是定义时所在的对象,而不是使用时所在的对象。也正是因为箭头函数中没有this,因此我们也就无从谈起用call/apply/bind来改变this指向。这个特性解决了函数中this指向的问题。
    var obj = {
      a: 10,
      b: () => {
        console.log(this.a); // undefined
        console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
      },
      c: function() {
        console.log(this.a); // 10
        console.log(this); // {a: 10, b: ƒ, c: ƒ}
      }
    }
    obj.b(); 
    obj.c();
    复制代码
    复制代码
    var obj = {
      a: 10,
      b: function(){
        console.log(this.a); //10
      },
      c: function() {
         return ()=>{
               console.log(this.a); //10
         }
      }
    }
    obj.b(); 
    obj.c()();
    3、箭头函数不绑定arguments,取而代之用rest参数...解决
    function A(a){
      console.log(arguments);
    }
    A(1,2,3,4,5,8);  //  [1, 2, 3, 4, 5, 8, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    
    
    let B = (b)=>{
      console.log(arguments);
    }
    B(2,92,32,32);   // Uncaught ReferenceError: arguments is not defined
    
    
    let C = (...c) => {
      console.log(c);
    }
    C(3,82,32,11323);  // [3, 82, 32, 11323]

    四、新增的数据类型

    重新复习下旧知识:基本数据类型有6种:Undefined、Null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。

    1、Set  (类似数组)

    主要用来去除重复的数据,Set 本身是一个构造函数,用来生成 Set 数据结构。

    let set = new Set(["name1","zhang","wang","name1","zhang"]);
    console.log(set);  //"name1","zhang","wang"

    console.log(set);  //3

    四个方法:add(),delete(),has(),clear()

    2、Map(映射,类似对象)

    (1)也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
    const map1 = new Map()
    const objkey = {p1: 'v1'}
    
    map1.set(objkey, 'hello')
    console.log(map1.get(objkey))

    结果:

    hello

    (2)Map可以接受数组作为参数,数组成员还是一个数组,其中有两个元素,一个表示键一个表示值。

    const map2 = new Map([
      ['name', 'Aissen'],
      ['age', 12]
    ])
    console.log(map2.get('name'))
    console.log(map2.get('age'))

    结果:

    Aissen
    12

    如果 Map 的键是一个简单类型的值(数字、字符串、布尔值),则只要两个值严格相等,Map 将其视为一个键,包括0和-0,布尔值true和字符串true则是两个不同的键。另外,undefined和null也是两个不同的键。虽然NaN不严格相等于自身,但 Map 将其视为同一个键。

    3、symbol(唯一的属性名)

    常用于对象的属性名,不会出现属性名冲突的现象。

    Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象

    Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

    复制代码
    // 没有参数的情况
    var s1 = Symbol();
    var s2 = Symbol();
    
    s1 === s2 // false
    
    // 有参数的情况
    var s1 = Symbol("foo");
    var s2 = Symbol("foo");
    
    s1 === s2 // false
    复制代码

    Symbol值不能与其他类型的值进行运算

    五、新增的语法糖

    1、class, extends, super

          这三个特性涉及了ES5中最令人头疼的的几个部分:原型、构造函数,继承

    复制代码
    class Animal {
        constructor(){
            this.type = 'animal'
        }
        says(say){
            console.log(this.type + ' says ' + say)
        }
    }
    
    let animal = new Animal()
    animal.says('hello') //animal says hello
    
    class Cat extends Animal {
        constructor(){
            super()
            this.type = 'cat'
        }
    }
    
    let cat = new Cat()
    cat.says('hello') //cat says hello
    复制代码

      上面代码首先用class定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象

      简单地说,constructor内定义的方法和属性是实例对象自己的,而constructor外定义的方法和属性则是所有实例对象可以共享的

      Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。上面定义了一个Cat类,该类通过extends关键字,继承了Animal类的所有属性和方法。

      super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。

      ES6的继承机制,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this。

      P.S 如果你写react的话,就会发现以上三个东西在最新版React中出现得很多。创建的每个component都是一个继承React.Component的类。

    六、内置对象扩展

    1、模板字符串(template string)

    大家可以先看下面一段代码:

    $("#result").append(
      "There are <b>" + basket.count + "</b> " +
      "items in your basket, " +
      "<em>" + basket.onSale +
      "</em> are on sale!"
    );

      我们要用一堆的'+'号来连接文本与变量,而使用ES6的新特性模板字符串``后,我们可以直接这么来写:

    $("#result").append(`
      There are <b>${basket.count}</b> items
       in your basket, <em>${basket.onSale}</em>
      are on sale!
    `);

      用反引号(来标识起始,用 ${}  来引用变量,而且所有的空格和缩进都会被保留在输出之中

    2、数组扩展(Array.from和Array.of)

    (1)Array.from是将伪数组对象或可迭代对象转为数组实例

    let m = new Map([[1, 2], [2, 4], [4, 8]]);
    Array.from(m); 
    // [[1, 2], [2, 4], [4, 8]]
    function f() {
      return Array.from(arguments);
    }
    f(1, 2, 3);
    // [1, 2, 3]
    Array.from([1, 2, 3], x => x + x);      
    // [2, 4, 6]
    
    // Generate a sequence of numbers
    // Since the array is initialized with `undefined` on each position,
    // the value of `v` below will be `undefined`
    Array.from({length: 5}, (v, i) => i);
    // [0, 1, 2, 3, 4]
    //数组去重合并
    function combine(){ let arr
    = [].concat.apply([], arguments); //concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,仅仅返回被连接数组的一个副本。

    return Array.from(new Set(arr));
    } 
    
    var m = [1, 2, 2], n = [2,3,3]; 
    console.log(combine(m,n));                     // [1, 2, 3]

    (2)Array.of是将零散的东西集合成一个数组,

    Array.of(element0[, element1[, ...[, elementN]]])
    Array.of(7);       // [7] 
    Array.of(1, 2, 3); // [1, 2, 3]
    
    Array(7);          // [ , , , , , , ]
    Array(1, 2, 3);    // [1, 2, 3]

    兼容旧环境:如果原生不支持的话,在其他代码之前执行以下代码会创建 Array.of() 。

    if (!Array.of) {
      Array.of = function() {
        return Array.prototype.slice.call(arguments);
      };
    }

    3、对象的扩展

    (1)key和value相同时,写一个就够了。

    (2)Object.assign(),将多个对象合为一个对象

         let obj1={name:"July"};

      let obj2={age:18};

      console.log(Object.assign(obj1,obj2))   //{name:"July",age:18}

    4、延展操作符(三点式)

     常见用法:(1)、复制数组和复制对象;(2)、合并数组和合并对象
    const a = {a: 1, b: 2}
    const b = {b: 3, c: 4}
    
    console.log({...a, ...b, c: 5}) // {a: 1, b: 3, c: 5}
    
    // 相当于 Object.assign(a, b, {c: 5})
    

    5、Math对象扩展

    Math.trunc():去除小数部分

    Math.trunc(4.9) //  4
    Math.trunc(-4.9) //  -4
    Math.trunc('-4.9') //  -4
    

    Math.sign():判断是正数、负数还是0

    Math.sign(-5) // -1
    Math.sign(5) // +1
    Math.sign(0) // +0
    Math.sign(-0) // -0
    

    Math.cbrt():计算一个数的立方根

    Math.cbrt(-1) // -1
    Math.cbrt(8) // 2
    

    Math.imull():返回两个以32位带符号整数形式相乘的结果。Math.imull(2,4) // 8

    **指数运算符:2**3 // 8

    七、import export

      这两个家伙对应的就是es6自己的module功能。

      我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小工程,再用一种简单的方法把这些小工程连接在一起。

      这有可能导致两个问题:

      (1)一方面js代码变得很臃肿,难以维护

      (2)另一方面我们常常得很注意每个script标签在html中的位置,因为它们通常有依赖关系,顺序错了可能就会出bug

      在es6之前为解决上面提到的问题,我们得利用第三方提供的一些方案,主要有两种CommonJS(服务器端)和AMD(浏览器端,如require.js)。

      而现在我们有了es6的module功能,它实现非常简单,可以成为服务器和浏览器通用的模块解决方案。

      ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。

      上面的设计思想看不懂也没关系,咱先学会怎么用,等以后用多了、熟练了再去研究它背后的设计思想也不迟!

    传统的写法

      首先我们回顾下require.js的写法。假设我们有两个js文件: index.jscontent.js,现在我们想要在index.js中使用content.js返回的结果,我们要怎么做呢?

      首先定义:

    //content.js
    define('content.js', function(){
        return 'A cat';
    })

    然后require:

    //index.js
    require(['./content.js'], function(animal){
        console.log(animal);   //A cat
    })

    那CommonJS是怎么写的呢?

    //index.js
    var animal = require('./content.js')
    
    //content.js
    module.exports = 'A cat'

    ES6的写法

    //index.js
    import animal from './content'
    
    //content.js
    export default 'A cat'

      以上我把三者都列出来了,妈妈再也不用担心我写混淆了...

    ES6 module的其他高级用法

    //content.js
    
    export default 'A cat'    
    export function say(){
        return 'Hello!'
    }    
    export const type = 'dog' 

    上面可以看出,export命令除了输出变量,还可以输出函数,甚至是类(react的模块基本都是输出类)

    //index.js
    
    import { say, type } from './content'  
    let says = say()
    console.log(`The ${type} says ${says}`)  //The dog says Hello

    这里输入的时候要注意:大括号里面的变量名,必须与被导入模块(content.js)对外接口的名称相同

      如果还希望输入content.js中输出的默认值(default),可以写在大括号外面。

    //index.js
    
    import animal, { say, type } from './content'  
    let says = say()
    console.log(`The ${type} says ${says} to ${animal}`)  
    //The dog says Hello to A cat

    修改变量名

      此时我们不喜欢type这个变量名,因为它有可能重名,所以我们需要修改一下它的变量名。在es6中可以用 as 实现一键换名。(有点类似sql语句,哈哈)

    //index.js
    
    import animal, { say, type as animalType } from './content'  
    let says = say()
    console.log(`The ${animalType} says ${says} to ${animal}`)  
    //The dog says Hello to A cat

    模块的整体加载

      除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。通常 星号结合 as 一起使用比较合适。

    //index.js
    
    import animal, * as content from './content'  
    let says = content.say()
    console.log(`The ${content.type} says ${says} to ${animal}`)  
    //The dog says Hello to A cat

    想更全面了解ES6伙伴们可以去看阮一峰所著的电子书ECMAScript 6入门

  • 相关阅读:
    JZ2440开发板开发环境搭建
    20180730-宿主机开发环境搭建
    20180319-双网卡电脑同时上内外网
    嵌入式ARM板子起步
    20180127-服务器开发环境搭建
    Pool多进程示例
    Python基础-day01
    解释型语言与编译型语言
    C 编译过程浅析
    博客奇谭
  • 原文地址:https://www.cnblogs.com/phoebeyue/p/9206625.html
Copyright © 2020-2023  润新知