精华内容
下载资源
问答
  • 主要介绍了ES6新特性之数组的扩充,结合实例形式分析了ES6数组操作的常见方法与相关使用技巧,需要的朋友可以参考下
  • 主要介绍了ES6新特性五之Set与Map的数据结构,结合实例形式分析了ES6中Set与Map的功能、定义、属性、结构与相关使用技巧,需要的朋友可以参考下
  • 主要介绍了ES6新特性中的let和const命令,结合实例形式分析了let和const命令的功能、使用方法与相关注意事项,需要的朋友可以参考下
  • ES6新特性

    2021-01-27 13:23:23
    Tags:javascript [TOC]使用var带来的麻烦:  运行getClothing(false)后输出的是undefined,这是因为执行function函数之前,所有变量都会被提升, 提升到函数作用域顶部.let与const声明的变量解决了这种问题,因为他们是...
  • 本文实例讲述了ES6新特性之字符串的扩展。分享给大家供大家参考,具体如下: 一、ES5字符串函数 concat: 将两个或多个字符的文本组合起来,返回一个的字符串。 indexOf: 返回字符串中一个子串第一处出现的索引(从...
  • ES6中,像Array,Date和Dom元素这样的内建对象都可以被子类化。   class MyArray extends Array {  constructor(...args) {  super(...args);  } } var arr = new MyArray(); arr[1] = 12; console.log(arr....
  • 主要介绍了ES6新特性之类(Class)和继承(Extends)相关概念与用法,结合实例形式较为详细的分析了ES6中类(Class)和继承(Extends)的基本概念、语法、使用方法与注意事项,需要的朋友可以参考下
  • es6新特性

    万次阅读 2019-03-17 17:15:56
    ES6语法 const 与 let 变量 使用var带来的麻烦: function getClothing(isCold) { if (isCold) { var freezing = 'Grab a jacket!'; } else { var hot = 'It's a shorts kind of day.'; ...

    ES6语法

    const 与 let 变量

    使用var带来的麻烦:

    function getClothing(isCold) {
      if (isCold) {
        var freezing = 'Grab a jacket!';
      } else {
        var hot = 'It's a shorts kind of day.';
        console.log(freezing);
      }
    }
    

    运行getClothing(false)后输出的是undefined,这是因为执行function函数之前,所有变量都会被提升, 提升到函数作用域顶部.

    letconst声明的变量解决了这种问题,因为他们是块级作用域, 在代码块(用{}表示)中使用letconst声明变量, 该变量会陷入暂时性死区直到该变量的声明被处理.

    function getClothing(isCold) {
      if (isCold) {
        const freezing = 'Grab a jacket!';
      } else {
        const hot = 'It's a shorts kind of day.';
        console.log(freezing);
      }
    }
    

    运行getClothing(false)后输出的是ReferenceError: freezing is not defined,因为 freezing 没有在 else 语句、函数作用域或全局作用域内声明,所以抛出 ReferenceError

    关于使用letconst规则:

    • 使用let声明的变量可以重新赋值,但是不能在同一作用域内重新声明
    • 使用const声明的变量必须赋值初始化,但是不能在同一作用域类重新声明也无法重新赋值.

    在这里插入图片描述
    在这里插入图片描述

    模板字面量

    在ES6之前,将字符串连接到一起的方法是+或者concat()方法,如

    const student = {
      name: 'Richard Kalehoff',
      guardian: 'Mr. Kalehoff'
    };
    const teacher = {
      name: 'Mrs. Wilson',
      room: 'N231'
    }
    let message = student.name + ' please see ' + teacher.name + ' in ' + teacher.room + ' to pick up your report card.';
    

    模板字面量本质上是包含嵌入式表达式的字符串字面量.
    模板字面量用倒引号 ( `` )(而不是单引号 ( '' ) 或双引号( "" ))表示,可以包含用 ${expression} 表示的占位符

    let message = `${student.name} please see ${teacher.name} in ${teacher.room} to pick up your report card.`;
    

    解构

    在ES6中,可以使用解构从数组和对象提取值并赋值给独特的变量

    解构数组的值:

    const point = [10, 25, -34];
    const [x, y, z] = point;
    console.log(x, y, z);
    

    Prints: 10 25 -34

    []表示被解构的数组, x,y,z表示要将数组中的值存储在其中的变量, 在解构数组是, 还可以忽略值, 例如const[x,,z]=point,忽略y坐标.

    解构对象中的值:

    const gemstone = {
      type: 'quartz',
      color: 'rose',
      karat: 21.29
    };
    const {type, color, karat} = gemstone;
    console.log(type, color, karat);
    

    花括号 { } 表示被解构的对象,typecolorkarat 表示要将对象中的属性存储到其中的变量

    对象字面量简写法

    let type = 'quartz';
    let color = 'rose';
    let carat = 21.29;
    const gemstone = {
      type: type,
      color: color,
      carat: carat
    };
    console.log(gemstone);
    

    使用和所分配的变量名称相同的名称初始化对象时如果属性名称和所分配的变量名称一样,那么就可以从对象属性中删掉这些重复的变量名称。

    let type = 'quartz';
    let color = 'rose';
    let carat = 21.29;
    const gemstone = {type,color,carat};
    console.log(gemstone);
    

    简写方法的名称:

    const gemstone = {
      type,
      color,
      carat,
      calculateWorth: function() {
        // 将根据类型(type),颜色(color)和克拉(carat)计算宝石(gemstone)的价值
      }
    };
    

    匿名函数被分配给属性 calculateWorth,但是真的需要 function 关键字吗?在 ES6 中不需要!

    let gemstone = {
      type,
      color,
      carat,
      calculateWorth() { ... }
    };
    

    for...of循环

    for...of循环是最新添加到 JavaScript 循环系列中的循环。
    它结合了其兄弟循环形式 for 循环和 for...in 循环的优势,可以循环任何可迭代(也就是遵守可迭代协议)类型的数据。默认情况下,包含以下数据类型:StringArrayMapSet,注意不包含 Object 数据类型(即 {})。默认情况下,对象不可迭代

    for循环

    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (let i = 0; i < digits.length; i++) {
      console.log(digits[i]);
    }
    

    for 循环的最大缺点是需要跟踪计数器和退出条件。
    虽然 for 循环在循环数组时的确具有优势,但是某些数据结构不是数组,因此并非始终适合使用 loop 循环。

    for...in循环

    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (const index in digits) {
      console.log(digits[index]);
    }
    

    依然需要使用 index 来访问数组的值
    当你需要向数组中添加额外的方法(或另一个对象)时,for...in 循环会带来很大的麻烦。因为 for...in 循环循环访问所有可枚举的属性,意味着如果向数组的原型中添加任何其他属性,这些属性也会出现在循环中。

    Array.prototype.decimalfy = function() {
      for (let i = 0; i < this.length; i++) {
        this[i] = this[i].toFixed(2);
      }
    };
    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (const index in digits) {
      console.log(digits[index]);
    }
    

    forEach 循环 是另一种形式的 JavaScript 循环。但是,forEach() 实际上是数组方法,因此只能用在数组中。也无法停止或退出 forEach 循环。如果希望你的循环中出现这种行为,则需要使用基本的 for 循环。

    for...of循环
    for...of 循环用于循环访问任何可迭代的数据类型。
    for...of 循环的编写方式和 for...in 循环的基本一样,只是将 in 替换为 of,可以忽略索引。

    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (const digit of digits) {
      console.log(digit);
    }
    

    建议使用复数对象名称来表示多个值的集合。这样,循环该集合时,可以使用名称的单数版本来表示集合中的单个值。例如,for (const button of buttons) {…}

    for...of 循环还具有其他优势,解决了 for 和 for...in 循环的不足之处。你可以随时停止或退出 for...of 循环。

    for (const digit of digits) {
      if (digit % 2 === 0) {
        continue;
      }
      console.log(digit);
    }
    

    不用担心向对象中添加新的属性。for...of 循环将只循环访问对象中的值。

    Array.prototype.decimalfy = function() {
      for (i = 0; i < this.length; i++) {
        this[i] = this[i].toFixed(2);
      }
    };
    const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    for (const digit of digits) {
      console.log(digit);
    }
    

    展开运算符

    展开运算符(用三个连续的点 (...) 表示)是 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

    展开运算符的一个用途是结合数组。

    如果你需要结合多个数组,在有展开运算符之前,必须使用 Arrayconcat() 方法。

    const fruits = ["apples", "bananas", "pears"];
    const vegetables = ["corn", "potatoes", "carrots"];
    const produce = fruits.concat(vegetables);
    console.log(produce);
    

    Prints: ["apples", "bananas", "pears", "corn", "potatoes", "carrots"]

    使用展开符来结合数组

    const fruits = ["apples", "bananas", "pears"];
    const vegetables = ["corn", "potatoes", "carrots"];
    const produce = [...fruits,...vegetables];
    console.log(produce);
    

    剩余参数(可变参数)

    使用展开运算符将数组展开为多个元素, 使用剩余参数可以将多个元素绑定到一个数组中.
    剩余参数也用三个连续的点 ( ... ) 表示,使你能够将不定数量的元素表示为数组.

    用途1: 将变量赋数组值时:

    const order = [20.17, 18.67, 1.50, "cheese", "eggs", "milk", "bread"];
    const [total, subtotal, tax, ...items] = order;
    console.log(total, subtotal, tax, items);
    

    用途2: 可变参数函数
    对于参数不固定的函数,ES6之前是使用参数对象(arguments)处理:

    function sum() {
      let total = 0;  
      for(const argument of arguments) {
        total += argument;
      }
      return total;
    }
    

    在ES6中使用剩余参数运算符则更为简洁,可读性提高:

    function sum(...nums) {
      let total = 0;  
      for(const num of nums) {
        total += num;
      }
      return total;
    }
    

    ES6箭头函数

    ES6之前,使用普通函数把其中每个名字转换为大写形式:

    const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(function(name) { 
      return name.toUpperCase();
    });
    

    箭头函数表示:

    const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
      name => name.toUpperCase()
    );
    

    普通函数可以是函数声明或者函数表达式, 但是箭头函数始终都是表达式, 全程是箭头函数表达式, 因此因此仅在表达式有效时才能使用,包括:

    • 存储在变量中,
    • 当做参数传递给函数,
    • 存储在对象的属性中。
    const greet = name => `Hello ${name}!`;
    

    可以如下调用:

    greet('Asser');
    

    如果函数的参数只有一个,不需要使用()包起来,但是只有一个或者多个, 则必须需要将参数列表放在圆括号内:

    // 空参数列表需要括号
    const sayHi = () => console.log('Hello Udacity Student!');
    // 多个参数需要括号
    const orderIceCream = (flavor, cone) => console.log(`Here's your ${flavor} ice cream in a ${cone} cone.`);
    orderIceCream('chocolate', 'waffle');
    

    一般箭头函数都只有一个表达式作为函数主题:

    const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map(
      name => name.toUpperCase()
    );
    

    这种函数表达式形式称为简写主体语法:

    • 在函数主体周围没有花括号,
    • 自动返回表达式

    但是如果箭头函数的主体内需要多行代码, 则需要使用常规主体语法:

    • 它将函数主体放在花括号内
    • 需要使用 return 语句来返回内容。
    const upperizedNames = ['Farrin', 'Kagure', 'Asser'].map( name => {
      name = name.toUpperCase();
      return `${name} has ${name.length} characters in their name`;
    });
    

    javascript标准函数this

    1. new 对象
    const mySundae = new Sundae('Chocolate', ['Sprinkles', 'Hot Fudge']);
    

    sundae这个构造函数内的this的值是实例对象, 因为他使用new被调用.

    1. 指定的对象
    const result = obj1.printName.call(obj2);
    

    函数使用call/apply被调用,this的值指向指定的obj2,因为call()第一个参数明确设置this的指向

    1. 上下`文对象
    data.teleport();
    

    函数是对象的方法, this指向就是那个对象,此处this就是指向data.

    1. 全局对象或 undefined
    teleport();
    

    此处是this指向全局对象,在严格模式下,指向undefined.

    javascript中this是很复杂的概念, 要详细判断this,请参考this豁然开朗

    箭头函数和this

    对于普通函数, this的值基于函数如何被调用, 对于箭头函数,this的值基于函数周围的上下文, 换句话说,this的值和函数外面的this的值是一样的.

    function IceCream() {
        this.scoops = 0;
    }
    // 为 IceCream 添加 addScoop 方法
    IceCream.prototype.addScoop = function() {
        setTimeout(function() {
            this.scoops++;
            console.log('scoop added!');
            console.log(this.scoops); // undefined+1=NaN
            console.log(dessert.scoops); //0
        }, 500);
    };
    

    标题

    const dessert = new IceCream();
    dessert.addScoop();

    传递给 setTimeout() 的函数被调用时没用到 newcall()apply(),也没用到上下文对象。意味着函数内的 this 的值是全局对象,不是 dessert 对象。实际上发生的情况是,创建了新的 scoops 变量(默认值为 undefined),然后递增(undefined + 1 结果为 NaN);

    解决此问题的方式之一是使用闭包(closure):

    // 构造函数
    function IceCream() {
      this.scoops = 0;
    }
    // 为 IceCream 添加 addScoop 方法
    IceCream.prototype.addScoop = function() {
      const cone = this; // 设置 `this` 给 `cone`变量
      setTimeout(function() {
        cone.scoops++; // 引用`cone`变量
        console.log('scoop added!'); 
        console.log(dessert.scoops);//1
      }, 0.5);
    };
    const dessert = new IceCream();
    dessert.addScoop();
    

    箭头函数的作用正是如此, 将setTimeOut()的函数改为剪头函数:

    // 构造函数
    function IceCream() {
      this.scoops = 0;
    }
    // 为 IceCream 添加 addScoop 方法
    IceCream.prototype.addScoop = function() {
      setTimeout(() => { // 一个箭头函数被传递给setTimeout
        this.scoops++;
        console.log('scoop added!');
        console.log(dessert.scoops);//1
      }, 0.5);
    };
    const dessert = new IceCream();
    dessert.addScoop();
    

    默认参数函数

    function greet(name, greeting) {
      name = (typeof name !== 'undefined') ?  name : 'Student';
      greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';
      return `${greeting} ${name}!`;
    }
    greet(); // Welcome Student!
    greet('James'); // Welcome James!
    greet('Richard', 'Howdy'); // Howdy Richard!
    

    greet() 函数中混乱的前两行的作用是什么?它们的作用是当所需的参数未提供时,为函数提供默认的值。但是看起来很麻烦, ES6引入一种新的方式创建默认值, 他叫默认函数参数:

    function greet(name = 'Student', greeting = 'Welcome') {
      return `${greeting} ${name}!`;
    }
    greet(); // Welcome Student!
    greet('James'); // Welcome James!
    greet('Richard', 'Howdy'); // Howdy Richard!
    

    默认值与解构

    1. 默认值与解构数组
    function createGrid([width = 5, height = 5]) {
      return `Generates a ${width} x ${height} grid`;
    }
    

    createGrid([]); // Generates a 5 x 5 grid
    createGrid([2]); // Generates a 2 x 5 grid
    createGrid([2, 3]); // Generates a 2 x 3 grid
    createGrid([undefined, 3]); // Generates a 5 x 3 grid

    createGrid() 函数预期传入的是数组。它通过解构将数组中的第一项设为 width,第二项设为 height。如果数组为空,或者只有一项,那么就会使用默认参数,并将缺失的参数设为默认值 5。

    但是存在一个问题:

    createGrid(); // throws an error
    

    Uncaught TypeError: Cannot read property 'Symbol(Symbol.iterator)' of undefined

    出现错误,因为 createGrid() 预期传入的是数组,然后对其进行解构。因为函数被调用时没有传入数组,所以出现问题。但是,我们可以使用默认的函数参数!

    function createGrid([width = 5, height = 5] = []) {
      return `Generating a grid of ${width} by ${height}`;
    }
    createGrid(); // Generates a 5 x 5 grid
    

    Returns: Generates a 5 x 5 grid

    1. 默认值与解构函数

    就像使用数组默认值解构数组一样,函数可以让对象成为一个默认参数,并使用对象解构:

    function createSundae({scoops = 1, toppings = ['Hot Fudge']}={}) {
      const scoopText = scoops === 1 ? 'scoop' : 'scoops';
      return `Your sundae has ${scoops} ${scoopText} with ${toppings.join(' and ')} toppings.`;
    }
    createSundae({}); // Your sundae has 1 scoop with Hot Fudge toppings.
    createSundae({scoops: 2}); // Your sundae has 2 scoops with Hot Fudge toppings.
    createSundae({scoops: 2, toppings: ['Sprinkles']}); // Your sundae has 2 scoops with Sprinkles toppings.
    createSundae({toppings: ['Cookie Dough']}); // Your sundae has 1 scoop with Cookie Dough toppings.
    createSundae(); // Your sundae has 1 scoop with Hot Fudge toppings.
    
    1. 数组默认值与对象默认值

    默认函数参数只是个简单的添加内容,但是却带来很多便利!与数组默认值相比,对象默认值具备的一个优势是能够处理跳过的选项。看看下面的代码:

    function createSundae({scoops = 1, toppings = ['Hot Fudge']} = {}) { … }
    

    createSundae() 函数使用对象默认值进行解构时,如果你想使用 scoops 的默认值,但是更改 toppings,那么只需使用 toppings 传入一个对象:

    createSundae({toppings: ['Hot Fudge', 'Sprinkles', 'Caramel']});
    

    将上述示例与使用数组默认值进行解构的同一函数相对比。

    function createSundae([scoops = 1, toppings = ['Hot Fudge']] = []) { … }
    

    对于这个函数,如果想使用 scoops 的默认数量,但是更改 toppings,则必须以这种奇怪的方式调用你的函数:

    createSundae([undefined, ['Hot Fudge', 'Sprinkles', 'Caramel']]);
    

    因为数组是基于位置的,我们需要传入 undefined 以跳过第一个参数(并使用默认值)来到达第二个参数。

    Javascript类

    ES5创建类:

    function Plane(numEngines) {
      this.numEngines = numEngines;
      this.enginesActive = false;
    }
    // 由所有实例 "继承" 的方法
    Plane.prototype.startEngines = function () {
      console.log('starting engines...');
      this.enginesActive = true;
    };
    

    ES6类只是一个语法糖,原型继续实际上在底层隐藏起来, 与传统类机制语言有些区别.

    class Plane {
      //constructor方法虽然在类中,但不是原型上的方法,只是用来生成实例的.
      constructor(numEngines) {
        this.numEngines = numEngines;
        this.enginesActive = false;
      }
      //原型上的方法, 由所有实例对象共享.
      startEngines() {
        console.log('starting engines…');
        this.enginesActive = true;
      }
    }
    console.log(typeof Plane); //function
    

    javascript中类其实只是function, 方法之间不能使用,,不用逗号区分属性和方法.

    静态方法
    要添加静态方法,请在方法名称前面加上关键字 static

    class Plane {
      constructor(numEngines) {
        this.numEngines = numEngines;
        this.enginesActive = false;
      }
      static badWeather(planes) {
        for (plane of planes) {
          plane.enginesActive = false;
        }
      }
      startEngines() {
        console.log('starting engines…');
        this.enginesActive = true;
      }
    }
    
    • 关键字class带来其他基于类的语言的很多思想,但是没有向javascript中添加此功能
    • javascript类实际上还是原型继承
    • 创建javascript类的新实例时必须使用new关键字

    super 和 extends

    使用新的super和extends关键字扩展类:

    class Tree {
      constructor(size = '10', leaves = {spring: 'green', summer: 'green', fall: 'orange', winter: null}) {
        this.size = size;
        this.leaves = leaves;
        this.leafColor = null;
      }
      changeSeason(season) {
        this.leafColor = this.leaves[season];
        if (season === 'spring') {
          this.size += 1;
        }
      }
    }
    class Maple extends Tree {
      constructor(syrupQty = 15, size, leaves) {
        super(size, leaves); //super用作函数
        this.syrupQty = syrupQty;
      }
      changeSeason(season) {
        super.changeSeason(season);//super用作对象
        if (season === 'spring') {
          this.syrupQty += 1;
        }
      }
      gatherSyrup() {
        this.syrupQty -= 3;
      }
    }
    

    使用ES5编写同样功能的类:

    function Tree(size, leaves) {
      this.size = size || 10;
      this.leaves = leaves || {spring: 'green', summer: 'green', fall: 'orange', winter: null};
      this.leafColor;
    }
    Tree.prototype.changeSeason = function(season) {
      this.leafColor = this.leaves[season];
      if (season === 'spring') {
        this.size += 1;
      }
    }
    function Maple (syrupQty, size, leaves) {
      Tree.call(this, size, leaves);
      this.syrupQty = syrupQty || 15;
    }
    Maple.prototype = Object.create(Tree.prototype);
    Maple.prototype.constructor = Maple;
    Maple.prototype.changeSeason = function(season) {
      Tree.prototype.changeSeason.call(this, season);
      if (season === 'spring') {
        this.syrupQty += 1;
      }
    }
    Maple.prototype.gatherSyrup = function() {
      this.syrupQty -= 3;
    }
    

    super 必须在 this 之前被调用

    在子类构造函数中,在使用 this 之前,必须先调用超级类。

    class Apple {}
    class GrannySmith extends Apple {
      constructor(tartnessLevel, energy) {
        this.tartnessLevel = tartnessLevel; // 在 'super' 之前会抛出一个错误!
        super(energy); 
      }
    }
    
          </div>
        </div>
    </div>
    
    展开全文
  • JavaScript ES6新特性

    千次阅读 2020-07-24 20:39:39
    JavaScript ES6新特性 这篇笔记讲了 ES6 新增的声明变量的方法,箭头函数,剩余参数 扩展运算符(…args),和ES6中新增的数组字符串方法,和 Set 数据结构 声明变量方法 let 关键字 let 声明的变量只在块级作用域...

    JavaScript ES6新特性

    这篇笔记讲了 ES6 新增的声明变量的方法,箭头函数,剩余参数 扩展运算符(…args),和ES6中新增的数组字符串方法,和 Set 数据结构

    声明变量方法

    let 关键字

    • let 声明的变量只在块级作用域有效

      • 块级作用域:两个大括号之间
    • 原来的作用域是一个函数,用 let 的话作用域变成了 {} 之间

    • let 可以防止循环变量变成全局变量

    for(let i = 0;i < 2;i++) {}
    console.log(i);
    // 报错,i 变量未定义
    
    • let 没有变量提升 (也就是不能先使用后定义)
    • 暂时性死区:外部同名变量无法穿透大括号作用域
    // 暂时性死区
    var num = 10;
    if(true) {
        let num = 20;
        console.log(num);
    }
    // 输出结果 20
    

    const 关键字

    • const:声明常量,也就是内存地址不能改变的量
    • const 声明的常量有块级作用域 (只能在两个大括号之间使用)
    • const 定义的常量时必须赋初始值

    • 下面一段代码:
    const PI = 3.14;
    PI = 100;
    // 报错:TypeError: Assignment to constant variable.
    
    const arr = [100,200];
    arr[0] = 'a';
    arr[1] = 'b';
    console.log(arr);
    // 输出:['a','b']
    arr = ['a','b'];
    // 报错
    

    const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。
    但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

    三种声明方法的区别

    varletconst
    函数级作用域块级作用域块级作用域
    存在变量提升不存在变量提升不存在变量提升
    值可更改值可更改值不可更改
    • const 关键字不需要实时监听变量的变化,所以效率要比 var,let 高

    解构赋值

    • 解构赋值可以把对象或者数组里面的 属性/值 从里面取出,赋给其他的变量
    • 例如:
    let arr = [1,2,3];
    let [a,b,c] = arr;
    console.log(a);
    // 输出 1
    
    • 里面不止可以使用 let 来定义,还可以使用 var

    • 假如变量名比数组里面的内容多,则未分配到内容的变量值为 undefined

    • 对象结构同理:

    let person = { name: '菜鸟小铭', age: 10 }
    let { name, age } = person;
    console.log(name);
    console.log(age);
    // 输出:菜鸟小铭 10
    
    // 可以使用键值对的形式来获取变量
    let {name: myname,age: myage} = person;
    // 冒号左侧仅用于匹配,冒号右侧的变量用来赋值
    console.log(myname);
    console.log(myage);
    // 输出:菜鸟小铭 10
    
    • 变量名必须和属性名相同才能取到这个变量的值
    • 更多解构赋值的应用可以看MDN的解构

    箭头函数

    • 箭头函数:() => {} 小括号放形参,大括号放函数体
    • 通常把箭头函数赋值给一个变量来调用
    const fn = () => {
      console.log('菜鸟小铭');
    }
    
    • 如果函数中只有一句代码,且执行结果就是返回值,可以省略大括号
    • 如果形参只有一个,可以省略小括号
    function sum(num1,num2) {
      return num1 + num2;
    }
    // 上下两个函数等价
    const sum = (num1,num2) => num1 + num2;
    
    • 注意:箭头函数里的 this 指向定义位置的 this

    剩余参数

    • 当形参大于实参个数时,可以将剩下的参数表示为一个数组
    • 和 arguments 很像,但是像箭头函数中没有 arguments,所以用箭头函数举例
    • 使用时参数前面加三个点 ...args 代表接收所有参数
    const sum = (...args) => {
      let total = 0;
      args.forEach(item => total += item);
    }
    sum(10, 20, 30);
    
    • 剩余参数还可以用在数组中接受多余的参数 (例如返回的是一个数组的函数可以使用这个特性)
    • 例如:
    let arr = [1, 2, 3];
    let [num, ...num2] = arr;
    console.log(num); // 1
    console.log(num2); // [2, 3]
    

    扩展运算符

    • 扩展运算符 ...arr 把数组或者对象转为参数序列
    let arr = [1, 2, 3];
    console.log(...ary);
    // 等价于 console.log(1,2,3);
    // 输出 1 2 3
    
    • 扩展运算符合并数组:
    let arr1 = [1, 2];
    let arr2 = [3, 4];
    let arr3 = [...arr1, ...arr2];
    // 也可以使用 push 方法合并数组
    arr1.push(...arr2);
    
    • 这个方法和 apply(this, [arr]) 方法有点像,apply也可以把数组作为参数去调用,只不过他多了一个改变 this 指向的方法

    伪数组转换为真正的数组

    var divs = document.getElementsByTagName('div');
    const ary = [...divs];
    
    • 变成真正的数组以后可以使用数组的方法 (例如 push)

    • 方法2:使用 Array.from 方法

    // divs 是一个伪数组
    var arr = Array.from(divs);
    
    • from 方法还有第二个参数,是一个函数,数组中有多少个元素这个函数就被调用多少次
    • 例如给数组中每个元素乘以 2
    var arr = Array.from(divs, item => item * 2);
    

    数组,字符串的扩展方法

    Array 扩展方法

    • find 方法,查找数组中第一个满足条件的值,没有找到返回 undefined
    • 之前的 forEach 方法
    let arr = [{
      id: 1,
      name: '菜鸟小铭'
    }];
    let target = arr.find((item, index) => item.id == 1);
    // 输出 arr里的对象
    

    • findIndex 方法 找出第一个复合条件的数组索引,没有找到返回 -1
    let arr = [1, 5, 10, 15];
    let index = arr.findIndex((value, index) => value > 9);
    console.log(index); // 2
    

    • includes 方法,数组是否包含给定的值,返回布尔值
    let arr = [1, 2, 3];
    arr.includes(2);
    // true
    

    String 扩展方法

    模板字符串

    • 模板字符串用反引号定义:
    let name = `菜鸟小铭`;
    
    • 模板字符串可以解析变量 (就像 innerHTML 可以解析标签一样)
    let name = '菜鸟小铭';
    let sayHello = `hello,${name}`;
    // 输出 hello,菜鸟小铭
    
    • 模板字符串内部可以换行
    let name = `菜
                鸟
                小
                铭`;
    console.log(name);
    // 菜
    // 鸟
    // 小
    // 铭
    
    • 在模板字符串里可以调用函数,显示函数的返回值
    const name = () => {
      return '菜鸟小铭';
    };
    let sayHello = `${name()} hello`;
    // 菜鸟小铭 hello
    

    ES6 新增方法

    • 判断字符串是否以某字符串开头或结尾,返回布尔值
    let str = 'noobming';
    str.startsWith('noob');
    // true
    str.endsWith('ming');
    // true
    

    • 将原字符串重复 n 次,返回重复后的字符串
    'noobming'.repeat(2);
    // "noobmingnoobming"
    

    set 数据结构

    • set 结构类似于数组,但是成员的值都是唯一的,没有重复的值

    • set 是使用构造函数生成 set 数据结构的

    • 创建的时候可以传递数组进去,会自动转换为 set 数据结构(不能像数组一样直接在构造函数中写值,需要把他包裹成一个数组传进去)

    • set 数据结构里面有 size 属性,表示里面有多少种类的值

    const s = new Set(['1', '2', '3']);
    console.log(s.size);
    // 数组作为参数
    const s1 = new Set([1, 2, 2]);
    console.log(s1.size);
    // 输出 2
    
    • set 和 array 的互化 (可以利用 set 为数组去重)
    const s = new Set([1, 2, 2]);
    // 转化为数组
    const arr = [...s];
    
    • set 常用方法:

      • add(value):添加个值,返回 Set 结构本身
      • delete(value):删除某个值,返回一个布尔值,表示删除是否成功
      • has(value):返回一个布尔值,表示该值是否为 Set 的成员
      • clear():清除所有成员,没有返回值
    • set 遍历:同样也用 forEach() 方法

    s.forEach(value => console.log(value));
    
    展开全文
  • 新特性 let、const let 定义的变量不会被变量提升,const 定义的常量不能被修改,let 和 const 都是块级作用域 ES6前,js 是没有块级作用域 {} 的概念的。(有函数作用域、全局作用域、eval作用域) ES6后,...
  • 本篇文章主要介绍了ES6新特性:使用export和import实现模块化详解,具有一定的参考价值,有兴趣的可以了解一下
  • ES6新特性有哪些?

    千次阅读 2020-12-17 17:41:23
    ES6新特性有哪些?https://www.cnblogs.com/ruhaoren/p/11575179.html 一、的原始类型和变量声明 1,symbol  在ES6之前,我们知道JavaScript支持8种数据类型:Object,String,Boolean,Number,Null,...

    ES6新特性有哪些?

    一、新的原始类型和变量声明

    1,symbol

      在ES6之前,我们知道JavaScript支持8种数据类型:Object,String,Boolean,Number,Null,Undefined、Array、Function。现在,ES6新增了一种原始数据类型:symbol,表示独一无二的值,即每个symbol类型的值都不相同。这让我想起了另一个特殊的值:NaN,想一想,他们是不是有一点类似呢!

    var sy = Symbol('test');
    var sy1 = Symbol('test');
    console.log(tepeof sy);   //'symbol'
    sy == sy1;   //false
    var sy2 = new Symbol('test');   //error : Symbol is not a constructor

      创建symbol数据类型的值时,需要给Symbol函数传递一个字符串,并且有一点特殊的是:不能使用new关键字调用它。另外,每个symbol类型值都是独一无二的,即使传递的是相同的字符串。

    2,let和const

      ES6新增了两个声明变量的关键字:let和const。

      他们声明的变量仅在let和const关键字所在的代码块内起作用,即在使用let和const的那一对大括号{}内起作用,也称块级作用域(ES6之前只有函数作用域和全局作用域)。

      let和const声明变量不会在预编译过程中有提升行为(在全局声明也不会变成window的属性),且同一变量不能重复声明。所以要使用这类变量,只能在let和const关键字之后使用它们。

      let和const关键字还有一个特性:“暂时性死区”,即在使用了该关键字的块级作用域中,其内部使用let和const关键字声明的变量与外部作用域中的变量相互隔绝,互不影响。即使是同名变量。

    var a = 1;
    {
       console.log(a);   //error Cannot access 'a' before initialization
       let a = 0;
       console.log(a);   //0
    }
    console.log(a);   //1

      const用来声明一个常量,声明时必须赋值,且一旦声明就不能改变。

      其实说const变量不能更改是不准确的,请看下面的例子:

    const obj = {
        name:'ren',
        age:12
    };
    obj = {};   //error
    obj.sex = male;
    consol.log(obj);   //{name:'ren',age:12;sex:'male'}

      const声明的如果是一个原始值,那么上面的说法是准确的,如果const声明的是一个引用值,那么更准确的说法应该是一个不能被重新赋值的变量。

    3,解构赋值 

      解构赋值是对赋值运算符的扩展。它是一种针对数组或者对象进行模式匹配,然后对其中的变量进行赋值。

    let [a,b,c] = [1,2,3];
    console.log(a,b,c);    //1,2,3
    
    let [a,b,c] = [1,,3];
    console.log(a,b,c);    //1,undefined,3
    
    let [a,,b] = [1,2,3];
    console.log(a,b);//1,3
    
    let [a,..b] = [1,2,3];    //...是剩余运算符,表示赋值运算符右边除第一个值外剩余的都赋值给b
    console.log(a,b);//1,[2,3]

       事实上所有可枚举(iterable)的对象都可以使用解构赋值,例如数组,字符串对象,以及ES6新增的Map和Set类型。

    let arr = 'hello';
    let [a,b,c,d,e] = arr;
    console.log(a,b,c,d,e);  //'h','e','l','l','o'

      对象的解构赋值和数组类似,不过左边的变量名需要使用对象的属性名,并且用大括号{}而非中括号[]:

    let obj = {name:'ren',age:12,sex:'male'};
    let {name,age,sex} = obj;
    console.log(name,age,sex);  //'ren' 12 'male'
    let {name:myName,age:myAge,sex:mySex} = obj;  //自定义变量名
    console.log(myName,myAge,mySex);  //'ren' 12 'male'

    二  新的对象和方法

      1,Map和Set

      Map对象用于保存键值对,任何值JavaScript支持的值都可以作为一个键或者一个值。这听起来和对象差不多啊?其实它们还是有区别的:

        a) object的键只能是字符串或ES6的symbol值,而Map可以是任何值。

        b) Map对象有一个size属性,存储了键值对的个数,而object对象没有类似属性。

    let myMap = new Map([['name','ren'],['age',12]]);
    console.log(myMap);  //{'name'=>'ren','age'=>12}
    myMap.set('sex','male');
    console.log(myMap);  //{'name'=>'ren','age'=>12,'sex'=>'male'}
    myMap.get('name');  //'ren'
    myMap.has('age');  //true
    myMap.delete('age');  //true
    myMap.has('age');  //false
    myMap.get('age');  //undefined

      Map构造函数接收一个二维数组来创建一个Map对象。数组元素的第0位表示Map对象的key,第1位表示Map对象的value。

      Map对象使用set方法来新增数据,set方法接收两个参数,第一个表示key,第二个表示value。使用get方法获取数据,参数是对象的key。

      Map对象使用delete方法来删除数据,接收一个参数,表示需要被删除的key。

      Map对象使用has方法检测是否已经具有某个属性,返回boolean值。

      Set对象和Map对象类似,但它是用来存储一组唯一值的,而不是键值对。类似数组,但它的每个元素都是唯一的。

    let mySet = new Set([1,2,3]);
    console.log(mySet);  //{1,2,3}
    mySet.add(4);
    console.log(mySet);  //{1,2,3,4}
    mySet.delete(1);  //true
    mySet.has(1);  //false

         利用Set对象唯一性的特点,可以轻松实现数组的去重:

    let arr = [1,1,2,3,4,4];
    let mySet = new Set(arr);
    let newArr = Array.from(mySet);
    console.log(newArr);  //[1,2,3,4]

      2,对象新特性

      创建对象的字面量方式可以更加简洁。直接使用变量名作为属性,函数体作为方法,最终变量值变成属性值,函数名变成方法名。

     let name = 'ren';
     let age = 12;
     let myself = {
         name,
         age,
         say(){
             console.log(this.name);
         }
     };
    console.log(myself);  //{name:'ren',age:12,say:fn}
    myself.say();  //'ren'

      对象的拓展运算符(...)三点。用于拷贝目标对象所有可遍历的属性到当前对象。

    let obj = {name:'ren',age:12};
    let person = {...obj};
    console.log(person);//{name:'ren',age:12}
    obj == person;//false
    let another = {sex:'male'};
    let someone = {...person,...another};//合并对象
    console.log(someone);//{name:'ren',age:12,sex:'male'}

      ES6对象新增了两个方法,assign和is。

      assign用于浅拷贝源对象可枚举属性到目标对象。

    let source = {a:{ b: 1},b: 2};
    let target = {c: 3};
    Object.assign(target, source);
    console.log(target);  //{c: 3, a: {b:1}, b: 2}
    source.a.b = 2;
    console.log(target.a.b);  //2

      如果有同名属性,那么目标对象的属性值会被源对象的属性值覆盖。所以数组的表现就有一点特别了:

    Object.assign([1,2,3],[11,22,33,44]);//[11,22,33,44]

      数组的index就是属性名,当使用assign方法时,从第0位开始,目标数组的值便开始被源数组的值覆盖了。

      is方法和(===)功能基本类似,用于判断两个值是否绝对相等。

    Object.is(1,1);//true
    Object.is(1,true);//false
    Object.is([],[]);//false
    Object.is(+0,-0);//false
    Object.is(NaN,NaN);//true

      他们仅有的两点区别是,is方法可以区分+0还是-0,还有就是它认为NaN是相等的。

      3,字符串新方法

      includes()判断字符串是否包含参数字符串,返回boolean值。如果想要知道参数字符串出现的位置,还是需要indexOf或lastIndexOf方法。

      startsWith()/endsWith(),判断字符串是否以参数字符串开头或结尾。返回boolean值。这两个方法可以有第二个参数,一个数字,表示开始查找的位置。

    let str = 'blue,red,orange,white';
    str.includes('blue');//true
    str.startsWith('blue');//true
    str.endsWith('blue');//false

      repeat()方法按指定次数返回一个新的字符串。如果次数是大于0的小数则向下取整,0到-1之间的小数则向上取整,其他负数将抛出错误。

    console.log('hello'.repeat(2));//'hellohello'
    console.log('hello'.repeat(1.9));//'hello'
    console.log('hello'.repeat(-0.9));//''
    console.log('hello'.repeat(-1.9));//error

      padStart()/padEnd(),用参数字符串按给定长度从前面或后面补全字符串,返回新字符串。

    let arr = 'hell';
    console.log(arr.padEnd(5,'o'));  //'hello'
    console.log(arr.padEnd(6,'o'));  //'helloo'
    console.log(arr.padEnd(6));  //'hell  ',如果没有指定将用空格代替
    console.log(arr.padStart(5,'o'));  //'ohell'

      另外,如果字符串加上补全的字符串超出了给定的长度,那么,超出的部分将被截去。

      4,数组的新方法

      of()是ES6新增的用于创建数组的方法。of把传入的参数当做数组元素,形成新的数组。

    let arr = Array.of(1,'2',[3],{});
    console.log(arr);   //[1,'2',[3],{}]

      from()方法可以将可迭代对象转换为新的数组。函数可接受3个参数:第一个表示将被转换的可迭代对象,第二个是回调函数,将对每个数组元素应用该回调函数,然后返回新的值到新数组,第三个是回到函数内this的指向。后两个参数是可选的。

    let obj = {
        double(n) {
            return n * 2;
        }
    }
    let arr = [1, 2, 3];
    console.log(Array.from(arr, function (n){
        return this.double(n);
    }, obj)); // [2, 4, 6]

      find()和findIndex(),查找数组中符合条件的元素值或索引,方法不会修改原数组。

      接受一个回调函数作为参数,函数可以接受四个参数,分别是当前遍历到的元素,当前遍历到的索引,数组本身以及函数内this的指向。方法会把回调函数作用于每一个遍历到的元素,如果遍历到某一个元素可以使回调函数返回true,那么find方法会立即返回该元素,findIndex方法会返回该元素的索引。并终止继续遍历。

      如果有多个符合条件的,也将只返回第一个。如果遍历完整个数组也无法是回调函数返回true,那么find方法将返回undefined,findIndex方法将返回-1。

    let arr = [1,2,3,4,5];
    console.log(arr.find((ele) => {
        return ele === 1;
    }));//1
    console.log(arr.findIndex((ele) => {
        return ele > 4;
    }));  //4

      fill()/copyWithin(),替换数组中部分元素,会修改原数组。

    let arr = [1,2,3,4,5];
    console.log(arr.fill(0,0,3));//[0,0,0,4,5]
    //参数1表示目标值,参数2,3表示替换的始末位置,左闭右开区间。
    console.log(arr.copyWithin(0,2,4));//[0,4,0,4,5]
    //参数1表示修改的起始位置,参数2,3表示用来替换的数据的始末位置,左闭右开区间。

      fill()用指定的值替换,copyWithin()使用数组中原有的某一部分值替换。

      includes()用于检测数组是否包含某个值,可以指定开始位置。

    let arr = [1,2,3,4,5];
    console.log(arr.includes(2));//true
    console.log(arr.includes(1,1));//false

    三、函数

      1,参数默认值

      ES6首次添加了参数默认值。我们再也不用在函数内部编写容错代码了。

    function add(a=1,b=2){
        return a + b;
    }
    add();//3
    add(2);//4
    add(3,4);//7

      和参数默认值一起,ES6还带来了不定参。它的功能和使用arguments差不多。

    function add(...num){
        return num.reduce(function(result,value){
            return result + value;
        });
    }
    add(1,2,3,4);//10

      下面介绍的箭头函数没有arguments属性,如果箭头函数内要实现不定参,上述方式就是一个不错的选择了。

      2,箭头函数

      箭头函数实现了一种更加简洁的书写方式,并且也解决了关键字声明方式的一些麻烦事儿。箭头函数内部没有arguments,也没有prototype属性,所以不能用new关键字调用箭头函数。

      箭头函数的书写方式:参数 => 函数体。

    let add = (a,b) => {
        return a+b;
    }
    let print = () => {
        console.log('hi');
    }
    let fn = a => a * a;
    //当只有一个参数时,括号可以省略,函数体只有单行return语句时,大括号也可以省略,强烈建议不要省略它们,是真的难以阅读

      当函数需要直接返回对象时,你必须使用小括号把对象包裹起来。否则将抛出错误。

    const fn = () =>{name:'ren',age:12};
    // SyntaxError
    *******************************************
    const fn = () =>({name:'ren',age:12});

      箭头函数和普通函数最大的区别在于其内部this永远指向其父级AO对象的this。

      普通函数在预编译环节会在AO对象上添加this属性,保存一个对象(请参照《JavaScript之深入对象(二)》)。每个普通函数在执行时都有一个特定的this对象,而箭头函数执行时并不直接拥有this属性,如果你在箭头函数中使用this,将根据函数作用域链,直接引用父级AO对象上this绑定的对象。普通函数的AO对象只有在函数执行时才产生,换言之,普通函数的this是由函数执行时的环境决定。而箭头函数的特别之处在于,当函数被定义时,就引用了其父级AO对象的this,即箭头函数的this由定义时的环境决定。

      根据箭头函数的特点,不难推测:如果定义对象的方法直接使用箭头函数,那么函数内的this将直接指向window。

     var age = 123;
     let obj = {
         age:456,
         say:() => {
             console.log(this.age);
         }
     };
    obj.say();   //123
    //对象是没有执行期上下文的(AO对象),定义对象的方法实际上是在全局作用域下,即window

       如果你一定要在箭头函数中让this指向当前对象,其实也还是有办法的(但是没必要这么麻烦啊,直接使用普通函数不是更好吗?):

     var age = 123;
     let obj = {
         age:456,
         say:function(){
             var fn = () => {
             console.log(this.age);
            }
             return fn();
          }
     };
    obj.say();  //456

      我们来分析一下这是怎么做到的:首先,我们使用obj调用say方法时,say内创建了AO对象,并且该AO对象的this属性指向了obj(这里不明白的请回去复习一下我的《JavaScript之深入函数/对象》),然后,say内部又声明了一个箭头函数。我们说箭头函数在声明时就要强行引用父级AO的this属性,那么现在该箭头函数的父级AO是谁呢?当然就是say的AO啦,所以这里箭头函数的this直接就绑定了obj,最后箭头函数在执行时拿到的this,实际上就是say方法的AO.this,即obj本身。

      上面是在对象中使用箭头函数,如果那让你难于理解,那么请看下面这种方式:在普通函数中使用箭头函数。

    var obj = {name:'ren'};
    function test(){
        var fn = () => {
            console.log(this);
        };
        fn();
    }
    test();  //window
    test.call(obj);  //{name:'ren'}

      test函数在全局执行时,其this指向window,这时也产生了箭头函数的定义,于是箭头函数内的this也被指向了window,所以最终打印出window对象。

      当我们手动改变test函数执行时this的指向时,箭头函数定义所绑定的this实际上也被我们修改了。所以最终打印出obj。

     

    四、class(类)  

      class 作为对象的模板被引入ES6,你可以通过 class 关键字定义类。class 的本质依然是一个函数。

      1,创建类

    class Ex {   //关键字声明方式
        constructor(name){
            this.name = name;
            this.say = () => {
                console.log(this.name);
            }
        }
        methods(){
            console.log('hello ' + this.name);
        }
        static a = 123;
        static m = () => {
            console.log(this.a);
        };
    }
    //let ex = class{}  字面量方式
    var example = new Ex('ren');
    example.say();    //'ren'
    Ex.m();   //123
    example.methods();  //'hello ren'
      constructor是创建类必须的方法,当使用new调用类创建实例时,将自动执行该方法,该方法和构造函数类似,默认返回this对象。实例的方法和属性都定义在constructor内部。相当于构造函数的this方式。
    
      类保留了prototype属性,类中的方法不需要使用function关键字,并且方法之间不需要逗号隔开。类中定义的方法实际上还是保存在类的prototype属性上。
      使用static关键字定义类的静态属性和方法。类中不能定义共有属性,要想定义实例的共有属性还是需要使用prototype属性:Ex.prototype.属性名 = 属性值。
    
      创建实例依然使用new关键字。
    
      2、类的继承
    
      类的继承通过extends关键字实现。
    class Person {
        constructor (name,age){
            this.name = name;
            this.age = age;
        }
        say(){
            console.log(this.name + ':' + this.age);
        }
    }
    class Student extends Person{
        constructor (name,age,sex){
            super(name,age);
            this.sex = sex;
        }
    }
    var student = new Student('ren',12,'male');
    student.name;  //'ren'
    student.sex;  //'male'
    student.say();  //'ren:12'

      子类继承自父类,不会隐式的创建自己的this对象,而是通过super()引用父类的this。这个过程和在子构造函数内使用父构造函数call(this)很像,但他们有本质的区别。另外,ES6规定,super()必须在子类的this之前执行。所以一般我们把super()放在子类constructor方法的第一行,这样准没错!

    五、模块导入和导出

      1,导入

      ES6使用关键字 import 导入模块(文件),有两种常用的方式:

    import ‘模块名称’ from ‘路径’;
    import  ‘路径’;

      通过 import...from 的方式引入模块,模块名称实际上相当于定义一个变量,用来接收即将导入的模块。

      路径可以有很多方式,既可以是绝对路径,也可以是相对路径,甚至只是一个简单的模块名称,更甚至连文件后缀都不需要。当你使用该命令时,系统会自动从配置文件中指定的路径中去寻找并加载正确的文件。

    import Vue from "vue";
    //完整路劲其实是 "../node_modules/vue/dist/vue.js";

      通过 import... 的方式一般用来引入样式文件或预处理文件,因为他们不需要用变量来接收。

      2,导出

      ES6 通过 export 和export default 导出模块。导出的含义是向外暴露、输出,在一个文件中通过 import 导入另一个文件,通过变量即可以接收到导出的数据了。一般情况下,JS文件可以向外输出变量、函数和对象。

    let name = 'ren',age = 12;
    export {name,age};
    //注意:变量需要用大括号包裹,然后才能向外输出
    
    

      如果仅需向外暴露一个变量:

    export var name = 'ren';

      使用 export 向外输出函数的用法和变量相同,这里不再举例。

      总结:使用 export 向外输出成员时,可以同时输出多个,并且必须用‘{}’大括号包裹,在其他地方使用 import 导入时,接收成员的变量名必须和这里输出的名称一致,同时,可以根据实际情况,仅接收实际需要的的成员(接收的时候也要用大括号包裹)。

      如果希望通过 export 向外暴露成员,并且在导入的时候自定义接收名称,那么你可以使用 as 关键字重命名。

    let name = 'ren', age = 12;
    export {name, age};
    
    import {name as myName, age as myAge} from 'url';

      与 export 相比,export default 有以下几点不同:首先,在同一个模块中,export default 只允许向外暴露一次成员;然后,这种方式可以使用任意的名称接收,不像 export 那样有严格的要求;最后,export 和 export default 可以在同一模块中同时存在。

    let person = {name:'ren'};
    let age = 12;
    let address = 'cd';
    export default person;
    export {age};
    export {address};
    
    import man,{age,address} from 'url'

       小技巧:通常 import 无法直接被浏览器识别,即如果在HTML文档中引入的 JS 文件直接使用了 import 关键字,浏览器会报错。要想直接在被HTML文档引用的 JS 文件中使用 import,需要给该 <script> 标签添加type属性,且其值应该是 module。

     

    六  异步机制

      ES6新增了两种实现异步的新机制,Promise和Generator。文笔有限,怕讲的不清楚,误人子弟,请有兴趣的同学去下面的链接继续学习,廖老师的教程也是受很多人推崇的,当然MDN更官方。

      1,Promise

      https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

      https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

      2,Generator

      https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Generator

      https://www.liaoxuefeng.com/wiki/1022910821149312/1023024381818112

    展开全文
  • ES6新特性总结

    2020-08-04 15:21:04
    ES6新特性总结 日常开发中写的 JavaScript 代码,会用到ES6的部分新特性,这篇博客总结了ES入门的知识点,供日常查阅使用。 1. let和const命令 var ES6之前, 我们定义变量使用关键词var. 但是var有个问题就是定义...

    ES6新特性总结

    日常开发中写的 JavaScript 代码,会用到ES6的部分新特性,这篇博客总结了ES入门的知识点,供日常查阅使用。

    1. let和const命令

    var

    ES6之前, 我们定义变量使用关键词var. 但是var有个问题就是定义的变量很容易变成全局变量, 这并不是我们想看到的.比如:

    for (var i = 0; i < 5; i++){
      console.log(i);
    }
    
    console.log(i) // 5
    

    循环中定义的i变量在循环外也可以使用.

    let

    使用let声明变量, 只在let命令所在的代码块中有效.

    for (let i = 0; i < 5; i++){
      console.log(i);
    }
    
    console.log(i) // undefined
    

    const

    const 声明的变量是常量,不能被修改,类似于java中final关键字

    const a = 1
    const a = 2 // 报错: Assignment to constant variable.
    

    2.字符串扩展

    在ES6中,为字符串扩展了几个新的API.

    • includes() : 返回布尔值,表示是否找到了参数字符串;
    • startsWith() : 返回布尔值,表示参数字符串是否在原字符串的头部;
    • endsWith() : 返回布尔值,表示参数字符串是否在原字符串的尾部.

    字符串模板

    ES6中提供了`来作为字符串模板标记。我们可以这么玩:

    字符串模板

    在两个 `之间的部分都会被作为字符串的值,可以任意换行。

    3. 解构表达式

    什么是解构? -- ES6中允许按照一定模式从数组和对象中提取值,然后对变量进行赋值,这被称为解构 (
    Destructuring)。

    3.1 数组解构

    比如有一个数组:

    let arr = [1, 2, 3]
    

    之前我想获取其中的值,只能通过角标。ES6可以这样:

    let arr = [1,2,3]
    const [x,y,z] = arr;// x,y,z将与arr中的每个位置对应来取值
    // 然后打印
    console.log(x,y,z); // 1 2 3
    const [a] = arr; //只匹配1个参数
    console.log(a); // 1
    

    3.2 对象解构

    例如有一个person对象:

    const person = {
      name:"jack",
      age:21,
      language: ['java','js','css']
    }
    

    我们可以这样解构:

    //  解构表达式获取值
    const {name,age,language} = person;
    // 打印
    console.log(name);
    console.log(age);
    console.log(language);
    

    如果需要使用其他变量,需要额外指定别名:

    {name : n} :name 是 person 中的属性名,冒号后面的 n 是解构后要赋值的变量。

    4. 函数优化

    在ES6中,对函数的操作做了优化,使得我们在操作函数时更加的便捷。

    4.1 函数参数的默认值

    在ES6之前,我们无法给一个参数设置默认值,我们只能采取变通的写法:

     function add(a , b) {
        // 判断b是否为空,为空就给默认值1
        b = b || 1;
        return a + b;
     }
      // 传一个参数
      console.log(add(10));
    

    现在可以这么写:

    function add(a , b = 1) {
      return a + b;
    }
    // 传一个参数
    console.log(add(10));
    

    4.2 箭头函数

    ES6中定义函数的简写方式:
    一个参数时:

    var print = function (obj) {
      console.log(obj);
    }
    // 简写为:
    var print2 = obj => console.log(obj);
    

    多个参数:

    //  两个参数的情况:
    var sum = function (a , b) {
      return a + b;
    }
    // 简写为:
    var sum2 = (a,b) => a+b;
    

    没有参数:

    //  没有参数时,需要通过()进行占位,代表参数部分
    let sayHello = () => console.log("hello!");
    sayHello();
    

    代码不止一行,可以用 {} 括起来:

    var sum3 = (a,b) => {
      return a + b;
    }
    // 多行,没有返回值
    let sayHello = () => {
      console.log("hello!");
      console.log("world!");
    }
    sayHello();
    

    4.3 对象的函数属性的简写

    比如一个Person对象,里面有eat方法:

    let person = {
      name: "jack",
      // 以前:
      eat: function (food) {
        console.log(this.name + "在吃" + food);
     },
      // 箭头函数版:
      eat2: food => console.log(person.name + "在吃" + food),// 这里拿不到this
      // 简写版:
      eat3(food){
        console.log(this.name + "在吃" + food);
     }
    }
    

    4.4 箭头函数结合解构表达式

    比如有一个函数:

    const person = {
      name:"jack",
      age:21,
      language: ['java','js','css']
    }
    function hello(person) {
      console.log("hello," + person.name)
    }
    

    如果用箭头函数和解构表达式:

    var hi = ({name}) =>  console.log("hello," + name);
    hi(person)
    

    5. map和reduce

    ES6中,数组新增了map和reduce方法。

    5.1 map

    map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。

    举例:有一个字符串数组,我们希望转为int数组。

    let arr = ['1','20','-5','3'];
    console.log(arr)
    let newArr = arr.map(s => parseInt(s));
    console.log(newArr)
    

    5.2 reduce

    reduce{}:接收一个函数(必须)和一个初始值(可选),该函数接收两个参数:

    • 第一个参数是上一次 reduce处理的结果
    • 第二个参数是数组中要处理的下一个元素

    reduce()会从左到右依次把数组中的元素用reduce处理,并把处理的结果作为下次reduce的第一个参数。如果是
    第一次,会把前两个元素作为计算参数,或者把用户指定的初始值作为起始参数。

    举例:

    const arr = [1, 20, -5, 3]
    
    // 没有初始值
    arr.reduce((a, b) => a + b) // 19
    
    // 指定初始值
    arr.reduce((a, b) => a * b, -1) // 300
    

    6. 扩展运算符

    扩展运算符(spread)是三个点(...), 将一个数组转为用逗号分隔的参数序列 。

    用法:

     console.log (...[1, 2, 3]); //1 2 3
      console.log(1, ...[2, 3, 4], 5); // 1 2 3 4 5
      function add(x, y) {
        return x + y;
     }
      var numbers = [1, 2];
      console.log(add(...numbers)); // 3
      // 数组合并
      let arr = [...[1,2,3],...[4,5,6]];
      console.log(arr); //[1, 2, 3, 4, 5, 6]
      // 与解构表达式结合
      const [first, ...rest] = [1, 2, 3, 4, 5];
      console.log(first, rest) //1  [2, 3, 4, 5]
      //将字符串转成数组
      console.log([...'hello']) //["h", "e", "l", "l", "o"]
    

    7. Promise

    所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法
    上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样
    的方法进行处理。

    我们可以通过Promise的构造函数来创建Promise对象,并在内部封装一个异步执行的结果。

    语法:

    const promise = new Promise(function(resolve, reject) {
     // ... 执行异步操作
     if (/* 异步操作成功 */){
      resolve(value);// 调用resolve,代表Promise将返回成功的结果
    } else {
      reject(error);// 调用reject,代表Promise会返回失败结果
    }
    });
    

    这样,在promise中就封装了一段异步执行的结果。

    如果我们想要等待异步执行完成,做一些事情,我们可以通过 promise的then方法来实现,语法:

    promise .then(function(value){
      // 异步执行成功后的回调
    });
    

    如果想要处理promise异步执行失败的事件,还可以跟上catch:

    promise .then(function(value){
      // 异步执行成功后的回调
    }).catch(function(error){
      // 异步执行失败后的回调
    })
    

    示例:

    const p = new Promise(function (resolve, reject) {
      // 这里我们用定时任务模拟异步
      setTimeout(() => {
        const num = Math.random();
        // 随机返回成功或失败
        if (num < 0.5) {
          resolve("成功!num:" + num)
       } else {
          reject("出错了!num:" + num)
       }
     }, 300)
    })
    // 调用promise
    p.then(function (msg) {
      console.log(msg);
    }).catch(function (msg) {
      console.log(msg);
    })
    
    // 结果:
    出错了!0.834567898765434567890
    

    8. set和map

    ES6提供了Set和Map的数据结构。

    Set,本质与数组类似。不同在于Set中只能保存不同元素,如果元素相同会被忽略。和java中的Set集合非常相似。

    构造函数:

    // Set 构造函数可以接收一个数组或空
    let set = new Set();
    set.add(1);// [1]
    // 接收数组
    let set2 = new Set([2,3,4,5,5]);// 得到[2,3,4,5]
    

    方法:

    set.add(1);//  添加
    set.clear();// 清空
    set.delete(2);// 删除指定元素
    set.has(2); // 判断是否存在
    set.forEach(function(){})//遍历元素
    set.size; // 元素个数。是属性,不是方法。
    

    map,本质是与Object类似的结构。不同在于,Object强制规定key只能是字符串。而Map结构的key可以是任意对象即:

    • object 是 <string,object>集合
    • map 是<object,object>集合

    构造函数:

    // map 接收一个数组,数组中的元素是键值对数组
    const map = new Map([
     ['key1','value1'],
     ['key2','value2'],
    ])
    // 或者接收一个set
    const set = new Set([
     ['key1','value1'],
     ['key2','value2'],
    ])
    const map2 = new Map(set)
    // 或者其它map
    const map3 = new Map(map)
    

    方法:

    map .set(key, value);// 添加
    map.clear();// 清空
    map.delete(key);// 删除指定元素
    map.has(key); // 判断是否存在
    map.forEach(function(key,value){})//遍历元素
    map.size; // 元素个数。是属性,不是方法
    map.values() //获取value的迭代器
    map.keys() //获取key的迭代器
    map.entries() //获取entry的迭代器
    用法:
    for (let key of map.keys()) {
    console.log(key);
    }
    或:
    console.log(...map.values()); //通过扩展运算符进行展开
    

    9. class(类)的基本语法

    JavaScript 语言的传统方法是通过构造函数定义并生成新对象,ES6中引入 class 的概念,通过 class 关键词自定义类。

    基本语法:

      class User{
        constructor(name, age = 20){ // 构造方法
          this.name = name; // 添加属性并且赋值
          this.age = age;
       }
        sayHello(){ // 定义方法
          return "hello";
       }
        static isAdult(age){ //静态方法
          if(age >= 18){
            return "成年人";
         }
          return "未成年人";
       }
     }
      let user = new User("张三");
      // 测试
      console.log(user); // User {name: "张三", age: 20}
      console.log(user.sayHello()); // hello
      console.log(User.isAdult(20)); // 成年人
    

    类的继承:

    class User{
        constructor(name, age = 20){ // 构造方法
          this.name = name; // 添加属性并且赋值
          this.age = age;
       }
        sayHello(){
          return "hello"; // 定义方法
       }
        static isAdult(age){ //静态方法
          if(age >= 18){
            return "成年人";
         }
          return "未成年人";
       }
     }
      class ZhangSan extends User{
        constructor(){
          super("张三", 30); //如果父类中的构造方法有参数,那么子类必须通过super调用父类的构造
    方法
          this.address = "上海";//设置子类中的属性,位置必须处于super下面
       }
     }
      // 测试
      let zs = new ZhangSan();
      console.log(zs.name, zs.address);
      console.log(zs.sayHello());
      console.log(ZhangSan.isAdult(20));
    

    10. Generator函数

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

    Generator函数有两个特征: 一是 function命令与函数名 之间有一个星号: 二是 函数体内部使用 yield吾句定义不同的
    内部状态。

    用法:

    function* hello () {
        yield "hello";
        yield "world";
        return "done";
    }
    let h = hello();
    
    console.log(h.next()); //{value: "hello", done: false}
    console.log(h.next()); //{value: "world", done: false}
    console.log(h.next()); //{value: "done", done: true}
    console.log(h.next()); //{value: undefined, done: true}
    

    可以看到,通过 hello() 返回的h对象,每调用一次next()方法返回一个对象,该对象包含了 value 值和 done 状态。直到
    遇到 return 关键字或者函数执行完毕,这个时候返回的状态为 true,表示已经执行结束了。

    for...of 循环

    通过for...of可以循环遍历Generator函数返回的迭代器。

    function* hello () {
        yield "hello";
        yield "world";
        return "done";
    }
    let h = hello();
    for (let obj of h) {
        console.log(obj);
    }
    
    // 输出:
    hello
    world
    

    11. 修饰器(Decorator)

    修饰器(Decorator)是一个函数, 用来修改类的行为。 ES2017 引入了这项功能, 目前 Babel 转码器己经支持。
    使用:

    
    @T //通过@符号进行引用该方法,类似java中的注解
    class User {
        constructor(name, age = 20){
            this.name = name;
            this.age = age;
        }
    }
    
    function T(target) { //定义一个普通的方法
        console.log(target); //target对象为修饰的目标对象,这里是User对象
        target.country = "中国"; //为User类添加一个静态属性country
    }
    console.log(User.country); //打印出country属性值
    

    运行报错!

    原因是,在 ES6中,并没有支持该用法,在ES2017中才有,所以我们不能直接运行了,需要进行编码后再运行。
    转码的意思是:将ES6或ES2017转为ES5执行。类似这样:

    // 转码前
    input .map(item =>item + 1);
    //转码后
    input.map(function (item) {
      return item + 1;
    })
    

    12. 转码器

    • Babel (babeljs.io) 是一个广为使用的 ES6 转码器,可以将 ES6 代码转为 ES5 代码,从而 在浏览器或其他环境执
      行 。
    • Google 公司的 Traceur 转码器 Cgithub.com/google/traceur-compiler), 也可 以将 ES6 代码转为ES5的代
      码。

    这两款都是非常优秀的转码工具。这里介绍一个阿里蚂蚁金服的一个底层前端框架---umi。umi框架对转码器进行了封装。

    12.1 了解UmiJS

    官网:

    特点:

    • 插件化
      umi 的整个生命周期都是插件化的,甚至其内部实现就是由大量插件组成,比如 pwa、按需加载、一键切
      换 preact、一键兼容 ie9 等等,都是由插件实现。
    • 开箱即用
      你只需一个 umi 依赖就可启动开发,无需安装 react、preact、webpack、react-router、babel、jest 等等。
    • 约定式路由
      类 next.js 的约定式路由,无需再维护一份冗余的路由配置,支持权限、动态路由、嵌套路由等等。

    12.2 部署安装

    首先需要安装 Node.js,检查 Node.js 是否安装好可以使用命令:

    node -v
    

    已经安装 Node.js 的可以忽略。

    接下来,开始安装yarn,其中tyarn使用的是npm.taobao.org的源,速度要快一些。可以把yarn看做了优化了的npm。

    npm i yarn tyarn -g  #-g 是指全局安装
    tyarn -v #进行测试,如果能够正常输出版本信息则说明安装成功了
    

    接下来安装 umi

    tyarn global add umi
    umi #进行测试
    

    12.3 快速入门

    在项目根目录下执行:

    # 通过初始化命令将生成package.json文件,它是 NodeJS 约定的用来存放项目的信息和配置等信息的文件。
    tyarn init -y
    
    #通过umi命令创建index.js文件
    umi g page index  #可以看到在pages下创建好了index.js和index.css文件
    
    #将下面内存拷贝到index.js文件中进行测试
     @T //通过@符号进行引用该方法,类似java中的注解
     class User {
       constructor(name, age = 20){
         this.name = name;
         this.age = age;
       }
     }
     
      function T(target) { //定义一个普通的方法
       console.log(target); //target对象为修饰的目标对象,这里是User对象
       target.country = "中国"; //为User类添加一个静态属性country
     }
     console.log(User.country); //打印出country属性值
    #通过命令行启动umi的后台服务,用于本地开发
    umi dev
    #通过浏览器进行访问:http://localhost:8000/,查看效果
    #值得注意的是,这里访问的是umi的后台服务,不是idea提供的服务
    

    13. 模块化

    13.1 什么是模块化

    模块化就是把代码进行拆分,方便重复利用。类似 Java 中的导包:要使用一个包,必须先导入一个包。而 JS 中没有包的概念,换来的是模块。

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

    • export:用于规定模块的对外接口;
    • import:用于导入其他模块提供的功能。
    export

    比如我定义一个js文件:Util.js,里面有一个Util类:

    class Util {
      static sum = (a, b) => a + b;
    }
    //导出该类
    export default Util;
    

    import

    使用 export 命令定义了模块的对外接口以后,其他 JS 文件就可以通过 import 命令加载这个模块。
    例如我要使用上面导出的Util:

    //Index.js
    //导入Util类
    import Util from './Util'
    //使用Util中的sum方法
    console.log(Util.sum(1, 2));
    
    展开全文
  • es6新特性有哪些

    万次阅读 2020-05-09 21:44:24
    ES6特性你了解多少? 如果遇到一个东西不知道是ES6还是ES5,你改如何区分? 1、常用的es6特性: let && const;let 命令也用于声明对象,但是作用域为局部;iterable 类型。为了统一集合类型,ES6 标准...
  • 这是啥东西啊,不着急,我们需要先把es6新特性给学习了。下面我总结了一些经常会用到的es6新特性: 一、let和const 二、模板字符串 三、es6在es5原有函数上的扩展 四、es6在对象上的扩展 ...
  • ES6 新特性

    千次阅读 多人点赞 2019-08-11 20:31:12
    现在使用主流的前端框架中,如ReactJS、Vue.js、angularjs等,都会使用到ES6新特性,作为一名高级工程师而言,ES6也就成为了必修课,所以本套课程先以ES6新特性开始。 1.1、了解ES6 ES6,是ECMAScript 6的简称,...
  • ES5&ES6新特性

    千次阅读 2018-12-06 20:05:55
    ES5和6的一些新特性 1、let和const var有一个问题,就是定义的变量有时会莫名奇妙的成为全局变量。 for(var i = 0; i &lt; 5; i++){ console.log(i); } console.log("循环外:" + i)   1、...
  • ES6新特性思维导图

    2020-11-07 17:25:34
    查看我整理的ES新特性思维导图,参照思维导图可以宏观角度来学习ES6新特性。配合Day05-Day07进行学习效果更佳
  • 三分钟带你了解ES6新特性 变量和常量 解构赋值 箭头函数 新增方法 前言 ECMAScript 6(简称ES6)是于2015年6月正式发布的JavaScript语言的标准,正式名为ECMAScript 2015(ES2015)。它的目标是使得JavaScript语言...
  • 使用ES6新特性开发微信小程序(6)——元编程 元编程是指的是开发人员对 “语言本身进行编程”。一般是编程语言暴露了一些API,供开发人员来操作语言本身的某些特性。 从ES6开始,新增了Proxy和 Reflect特性,扩展了...
  • ES6 新特性 总结

    万次阅读 多人点赞 2018-05-24 14:03:52
    ES6新特性的学习笔记整理
  • 说说ES6新特性

    2020-10-16 22:45:49
    详见:ES6中常用的10个新特性讲解
  • 前端面试-说说你常用的ES6新特性

    千次阅读 2019-11-01 19:35:15
    ES6新特性 1.变量声明const 和 let 2.模板对象与字符串模板 3.箭头函数 4.类的引入 5.参数默认值,不定参数,拓展参数 6.import和 export 7.promise、async/await介绍 8.set和map ...
  • html5新特性 语义化标签 如:header,footer,nav,dialog 增强型表单 如:date,week,url,time,email,month 视频和音频 audio和video Canvas绘图 标签只是图形容器,真正绘图的是javascript svg绘图 它是一种可伸缩的矢量...
  • H5,C3和ES6新特性总结

    2020-12-24 15:49:52
    H5,C3和ES6新特性总结 一、H5 新增语义化标签header、sction、main、sider、footer和nav等。 表单新特性:email、url、number、range、Date Pickers、search、color等。 拖拽属性:draggable 多媒体视频(vedio)...
  • JavaScript-ES6新特性

    2019-03-23 17:28:41
    1.ES6中的常量写法 // 常量命名 const PI = 3.1415926 console.log(PI); // 作用域 const callbacks = []; for(var i = 0; i<= 3;i++){ callbacks[i] = function(){ return i*2 } } console....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 54,647
精华内容 21,858
关键字:

es6新特性