V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GrapeCityChina
V2EX  ›  推广

现代 JavaScript: ES6+ 中的 Imports, Exports, Let, Const 和 Promise

  •  8
     
  •   GrapeCityChina · 2020-12-24 11:41:46 +08:00 · 5248 次点击
    这是一个创建于 1190 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在过去几年里,JavaScript 有很多的更新。如果你想提升写代码的能力,这些更新将会对你有非常大的帮助。

    对于程序员来说,了解这门语言的最新发展是非常重要的。它能使你跟上最新趋势,提高代码质量,在工作中出类拔萃,从而进一步提升你的薪资待遇。

    特别地,如果你想学习像 React 、Angular 或 Vue 这样的框架,你必须掌握这些最新的特性。

    最近,JavaScript 增加了许多有用的功能,比如Nullish coalescing operator, optional chaining, Promises, async/await, ES6 destructuring,等等。

    那么现在,我们将探讨每个 JavaScript 开发者都应该知道的概念。

    JavaScript 中的 Let 和 const

    在 ES6 之前,JavaScript 使用 var 关键字来声明变量,var 只有全局作用域和函数作用域,所谓全局作用域就是在代码的任何位置都能访问 var 声明的变量,而函数作用域在变量声明的当前函数内部访问变量。此时是没有块级作用域的。

    随着 let 和 const 这两个关键字的添加,JS 增加了块级作用域的概念。

    如何在 JavaScript 中使用 let

    当我们在用 let 声明变量时,用于声明一次之后就不能再以相同的名称重新声明它。

    // ES5 Code
    
    var value =  10;
    
    console.log(value);  // 10
    
    var value =  "hello";
    
    console.log(value);  // hello
    
    var value =  30;
    
    console.log(value);  // 30
    

    如上所示,我们多次使用 var 关键字重新声明了变量值。

    在 ES6 之前,我们可以使用 var 重新声明之前已经声明过的变量,这就会导致了一个问题:如果我们在不知情的情况下,在其他地方重新声明了该变量,很有可能会覆盖原先变量的值,造成一些难以调试的问题。

    所以,Let 解决很好地解决此问题。当你使用 let 重新声明变量值时,将会报错。

    // ES6 Code
    let value = 10;
    console.log(value); // 10
    
    let value = "hello"; // Uncaught SyntaxError: Identifier 'value' has already been declared
    
    

    但是,以下代码是合法的:

    // ES6 Code
    let value = 10;
    console.log(value); // 10
    
    value = "hello";
    console.log(value); // hello
    
    

    我们发现上面的代码看起来没什么问题,是因为我们重新给 value 变量赋了一个新值,但是并没有重新声明。

    我们来看下下面的代码:

    // ES5 Code
    var isValid = true;
    if(isValid) {
      var number = 10;
      console.log('inside:', number); // inside: 10
    }
    console.log('outside:', number); // outside: 10
    
    

    如上所示,在使用 var 声明变量时,可以在 if 块之外访问该变量。

    而使用 let 声明的 number 变量只能在 if 块内访问,如果在 if 块外访问将会报错。

    我们来看下接下来的代码

    
    // ES6 Code
    let isValid = true;
    if(isValid) {
      let number = 10;
      console.log('inside:', number); // inside: 10
    }
    console.log('outside:', number); // Uncaught ReferenceError: number is not defined
    
    

    如上述代码所示,使用 let 分别在 if 块内、if 块外声明了 number 变量。在 if 块外,number 无法被访问,因此会出现引用错误。

    但是,如果变量 number 在 if 块外已经声明,将会出现下面的结果。

    
    // ES6 Code
    let isValid = true;
    let number = 20;
    
    if(isValid) {
      let number = 10;
      console.log('inside:', number); // inside: 10
    }
    
    console.log('outside:', number); // outside: 20
    
    

    现在在单独的范围内有两个 number 变量。在 if 块外,number 的值为 20 。

     // ES5 Code
    for(var i = 0; i < 10; i++){
     console.log(i);
    }
    console.log('outside:', i); // 10
    
    
    
    

    当使用 var 关键字时,i 在 for 循环之外也可以访问到。

    
    // ES6 Code
    for(let i = 0; i < 10; i++){
     console.log(i);
    }
    
    console.log('outside:', i); // Uncaught ReferenceError: i is not defined
    
    

    而使用 let 关键字时,在 for 循环外部是不可访问的。

    因此,正如上述示例代码所示,let 声明的变量只能在块内部可用,而在块外部不可访问。

    我们可以使用一对大括号创建一个块,如下:

    let i = 10;
    {
     let i = 20;
     console.log('inside:', i); // inside: 20
     i = 30;
     console.log('i again:', i); // i again: 30
    }
    
    console.log('outside:', i); // outside: 10
    
    
    

    前面有提到,let 在同一个块中不能重新声明变量,不过可以在另一个块中重新声明。如上代码所示,我们在块内重新声明了 i,并赋值 20,该变量仅可在该块中使用。

    在块外,当我们打印变量时,我们得到的是 10 而不是之前分配的值,这是因为块外,内部变变量 i 是不存在的。

    如果在块外未声明变量,那么将会报错:

    
    {
     let i = 20;
     console.log('inside:', i); // inside: 20
     i = 30;
     console.log('i again:', i); // i again: 30
    }
    
    console.log('outside:', i); // Uncaught ReferenceError: i is not defined
    

    如何在 JavaScript 使用 const

    const 关键字在块级作用域中的工作方式与 let 关键字完全相同。因此,我们来看下他们的区别。

    const 声明的变量为常量,其值是不能改变的。而 let 声明的变量,可以为其赋一个新值,如下所示:

    let number = 10;
    number = 20;
    console.log(number); // 20
    

    但是以下情况,我们不能这样使用 const 。

    
    const number = 10;
    number = 20; // Uncaught TypeError: Assignment to constant variable.
    
    
    

    我们甚至不能使用 const 像下面一样重新声明。

    const number = 20;
    console.log(number); // 20
    
    const number = 10; // Uncaught SyntaxError: Identifier 'number' has already been declared
    
    

    现在,看下面的代码:

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

    我们说过 const 声明的常量,它的值永远不会改变——但是我们改变了上面的常量数组并没有报错。这是为什么呢?

    注意:数组是引用类型,而不是 JavaScript 的基本类型

    实际存储在 arr 中的不是数组,而是数组存储的内存位置的引用(地址)。执行 arr.push(5),并没有改变 arr 指向的引用,而是改变了存储在那个引用上的值。

    对象也是如此:

    const obj = {
     name: 'David',
     age: 30
    };
    
    obj.age = 40;
    
    console.log(obj); // { name: 'David', age: 40 }
    
    

    这里,我们也没有改变 obj 指向的引用,而是改变了存储在引用的值。

    因此,上述的代码将会起作用,但下面的代码是无效的。

    const obj = { name: 'David', age: 30 };
    const obj1 = { name: 'Mike', age: 40 };
    obj = obj1; // Uncaught TypeError: Assignment to constant variable.
    
    

    这样写会抛出异常,因为我们试图更改 const 变量指向的引用。

    因此,在使用 const 时要记住一点:使用 const 声明常量时,不能重新声明,也不能重新赋值。如果声明的常量是引用类型,我们可以更改存储在引用的值。

    同理,下面的代码也是无效的。

    const arr = [1, 2, 3, 4];
    arr = [10, 20, 30]; // Uncaught TypeError: Assignment to constant variable.
    
    

    总结:

    • 关键字 let 和 const 在 JavaScript 中添加块级作用域。

    • 当我们将一个变量声明为 let 时,我们不能在同一作用域(函数或块级作用域)中重新定义或重新声明另一个具有相同名称的 let 变量,但是我们可以重新赋值。

    • 当我们将一个变量声明为 const 时,我们不能在同一作用域(函数或块级作用域)中重新定义或重新声明具有相同名称的另一个 const 变量。但是,如果变量是引用类型(如数组或对象),我们可以更改存储在该变量中的值。

    好了,我们继续下一个话题: promises 。

    JavaScript 中的 promises

    对于很多新开发者来说,promises 是 JavaScript 中较难理解的部分。ES6 中原生提供了 Promise 对象,那么 Promise 究竟是什么呢?

    Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息。

    如何创造一个 promise

    使用 promise 构造函数创建一个 promise,如下所示:

    const promise = new Promise(function(resolve, reject) {
     
    });
    
    

    Promise 的构造函数接收一个函数作为参数,并且在内部接收两个参数:resolve,reject 。resolve 和 reject 参数实际上是我们可以调用的函数,具体取决于异步操作的结果。

    Promise 有三种状态:

    • pending: 初始状态,不是成功或失败状态。

    • fulfilled:表示操作成功完成。

    • rejected: 表示操作失败。

    当我们创建 Promise 时,它处于等待的状态。当我们调用 resolve 函数时,它将进入已完成状态。如果调用 reject,他将进入被拒绝状态。

    在下面的代码中,我们执行了一个异步操作,也就是 setTimeout,2 秒后,调用 resolve 方法。

    const promise = new Promise(function(resolve, reject) {
     setTimeout(function() {
      const sum = 4 + 5;
      resolve(sum);
     }, 2000);
    });
    
    
    

    我们需要使用以下方法注册一个回调.then 获得 1promise 执行成功的结果,如下所示:

    const promise = new Promise(function(resolve, reject) {
     setTimeout(function() {
      const sum = 4 + 5;
      resolve(sum);
     }, 2000);
    });
    
    promise.then(function(result) {
     console.log(result); // 9
    });
    
    
    

    then 接收一个参数,是函数,并且会拿到我们在 promise 中调用 resolve 时传的的参数。

    如果操作不成功,则调用 reject 函数:

    const promise = new Promise(function(resolve, reject) {
     setTimeout(function() {
      const sum = 4 + 5 + 'a';
      if(isNaN(sum)) {
        reject('Error while calculating sum.');
      } else {
        resolve(sum);
      }
     }, 2000);
    });
    
    promise.then(function(result) {
     console.log(result);
    });
    
    
    

    如果 sum 不是一个数字,那么我们调用带有错误信息的 reject 函数,否则我们调用 resolve 函数。

    执行上述代码,输出如下:

    image.png

    调用 reject 函数会抛出一个错误,但是我们没有添加用于捕获错误的代码。

    需要调用 catch 方法指定的回调函数来捕获并处理这个错误。

    promise.then(function(result) {
     console.log(result);
    }).catch(function(error) {
     console.log(error);
    });
    
    

    输出如下:

    image.png

    所以建议大家在使用 promise 时加上 catch 方法,以此来避免程序因错误而停止运行。

    链式操作

    我们可以向单个 promise 添加多个 then 方法,如下所示:

    promise.then(function(result) {
     console.log('first .then handler');
     return result;
    }).then(function(result) {
     console.log('second .then handler');
     console.log(result);
    }).catch(function(error) {
     console.log(error);
    });
    
    

    当添加多个 then 方法时,前一个 then 方法的返回值将自动传递给下一个 then 方法。

    image.png

    如上图所示,我们在第一个 then 方法中输出字符串,并将接收的参数 result ( sum )返回给下一个 result 。

    在下一个 then 方法中,输出字符串,并输出上一个 then 方法传递给它的 result 。

    如何在 JavaScript 中延迟 promise 的执行

    很多时候,我们不希望立即创建 promise,而是希望在某个操作完成后再创建。

    我们可以将 promise 封装在一个函数中,然后从函数中返回 promise,如下所示:

    function createPromise() {
     return new Promise(function(resolve, reject) {
      setTimeout(function() {
       const sum = 4 + 5;
       if(isNaN(sum)) {
         reject('Error while calculating sum.');
       } else {
        resolve(sum);
       }
      }, 2000);
     });
    }
    
    
    

    这样,我们就可以通过函数将参数传递给 promise,达到动态的目的。

    function createPromise(a, b) {
     return new Promise(function(resolve, reject) {
      setTimeout(function() {
       const sum = a + b;
       if(isNaN(sum)) {
         reject('Error while calculating sum.');
       } else {
        resolve(sum);
       }
      }, 2000);
     });
    }
    
    createPromise(1,8)
     .then(function(output) {
      console.log(output); // 9
    });
    
    // OR
    
    createPromise(10,24)
     .then(function(output) {
      console.log(output); // 34
    });
    
    

    image.png

    此外,我们只能向 resolve 或 reject 函数传递一个值。如果你想传递多个值到 resolve 函数,可以将它作为一个对象传递,如下:

    const promise = new Promise(function(resolve, reject) {
     setTimeout(function() {
      const sum = 4 + 5;
      resolve({
       a: 4,
       b: 5,
       sum
      });
     }, 2000);
    });
    
    promise.then(function(result) {
     console.log(result);
    }).catch(function(error) {
     console.log(error);
    });
    
    

    image.png

    如何在 JavaScript 中使用箭头函数

    上述示例代码中,我们使用常规的 ES5 语法创建了 promise 。但是,通常使用箭头函数代替 ES5 语法,如下:

    const promise = new Promise((resolve, reject) => {
     setTimeout(() => {
      const sum = 4 + 5 + 'a';
      if(isNaN(sum)) {
        reject('Error while calculating sum.');
      } else {
        resolve(sum);
      }
     }, 2000);
    });
    
    promise.then((result) => {
     console.log(result);
    });
    
    

    你可以根据自己需要使用 ES5 或 ES6 语法。

    ES6 Import 和 Export 语法

    在 ES6 之前,我们在一个 HTML 文件中可以使用多个 script 标签来引用不同的 JavaScript 文件,如下所示:

    <script type="text/javascript" src="home.js"></script>
    <script type="text/javascript" src="profile.js"></script>
    <script type="text/javascript" src="user.js"></script>
    
    

    但是如果我们在不同的 JavaScript 文件中有一个同名的变量,将会出现命名冲突,你实际得到的可能并不是你期望的值。

    ES6 增加了模块的概念来解决这个问题。

    在 ES6 中,我们编写的每一个 JavaScript 文件都被称为模块。我们在每个文件中声明的变量和函数不能用于其他文件,除非我们将它们从该文件中导出并、在另一个文件中得到引用。

    因此,在文件中定义的函数和变量是每个文件私有的,在导出它们之前,不能在文件外部访问它们。

    export 有两种类型:

    • 命名导出:在一个文件中可以有多个命名导出

    • 默认导出:单个文件中只能有一个默认导出

    JavaScript 中的命名导出

    如下所示,将单个变量命名导出:

    export const temp = "This is some dummy text";
    

    如果想导出多个变量,可以使用大括号指定要输出的一组变量。

    const temp1 = "This is some dummy text1";
    const temp2 = "This is some dummy text2";
    export { temp1, temp2 };
    
    

    需要注意的是,导出语法不是对象语法。因此,在 ES6 中,不能使用键值对的形式导出。

              // This is invalid syntax of export in ES6
               export { key1: value1, key2: value2 }
    
    

    import 命令接受一对大括号,里面指定要从其他模块导入的变量名。

               import { temp1, temp2 } from './filename';
    

    注意,不需要在文件名中添加.js 扩展名,因为默认情况下会考虑该拓展名。

    
     // import from functions.js file from current directory
    
    import  { temp1, temp2 }  from  './functions';
    
     // import from functions.js file from parent of current directory
    
    import  { temp1 }  from  '../functions';
    

    提示一点,导入的变量名必须与被导入模块对外接口的名称相同。

    因此,导出应使用:

    // constants.js
    
    export  const  PI  =  3.14159;
    

    那么在导入的时候,必须使用与导出时相同的名称:

    import  {  PI  }  from  './constants';
    
    // This will throw an error
    
    import  { PiValue }  from  './constants';
    

    如果想为输入的变量重新命名,可以使用 as 关键字,语法如下:

    import  {  PI  as PIValue }  from  './constants';
    

    我们以为 PI 重命名为 PIValue,因此不能再使用 PI 变量名。

    导出时也可使用下面的重命名语法:

    // constants.js
    
    const  PI  =  3.14159;
    
    export  {  PI  as PIValue };
    

    然后在导入是,必须使用 PIValue 。

    import  { PIValue }  from  './constants';
    

    命名导出某些内容之前必须先声明它。

    export  'hello';  // this will result in error
    
    export  const greeting =  'hello';  // this will work
    
    export  { name:  'David'  };  // This will result in error
    
    export  const object =  { name:  'David'  };  // This will work
    

    我们来看下面的 validations.js 文件:

    // utils/validations.js
    
    const  isValidEmail  =  function(email)  {
    
      if  (/^[^@ ]+@[^@ ]+\.[^@ \.]{2,}$/.test(email))  {
    
      return  "email is valid";
    
      }  else  {
    
      return  "email is invalid";
    
      }
    
    };
    
    const  isValidPhone  =  function(phone)  {
    
      if  (/^[\\(]\d{3}[\\)]\s\d{3}-\d{4}$/.test(phone))  {
    
      return  "phone number is valid";
    
      }  else  {
    
      return  "phone number is invalid";
    
      }
    
    };
    
    function  isEmpty(value)  {
    
      if  (/^\s*$/.test(value))  {
    
      return  "string is empty or contains only spaces";
    
      }  else  {
    
      return  "string is not empty and does not contain spaces";
    
      }
    
    }
    
    export  { isValidEmail, isValidPhone, isEmpty };
    

    在 index.js 中,我们可以使用如下函数:

    // index.js
    
    import  { isEmpty, isValidEmail }  from  "./utils/validations";
    
    console.log("isEmpty:",  isEmpty("abcd"));  // isEmpty: string is not empty and does not contain spaces
    
    console.log("isValidEmail:",  isValidEmail("[email protected]"));  // isValidEmail: email is valid
    
    console.log("isValidEmail:",  isValidEmail("ab@[email protected]"));  // isValidEmail: email is invalid
    

    JavaScript 的默认导出

    如上所述,单个文件中最多只能有一个默认导出。但是,你可以在一个文件中使用多个命名导出和一个默认导出。

    要声明一个默认导出,我们需要使用以下语法:

    //constants.js
    
    const name =  'David';
    
    export  default name;
    

    在导入时就不需要再使用花括号了。

    import name from  './constants';
    

    如下,我们有多个命名导出和一个默认导出:

    // constants.js
    
    export  const  PI  =  3.14159;
    
    export  const  AGE  =  30;
    
    const  NAME  =  "David";
    
    export  default  NAME;
    

    此时我们使用 import 导入时,只需要在大括号之前指定默认导出的变量名。

    // NAME is default export and PI and AGE are named exports here
    
    import  NAME,  {  PI,  AGE  }  from  './constants';
    

    使用 export default 导出的内容,在导入的时候,import 后面的名称可以是任意的。

    // constants.js
    
    const  AGE  =  30;
    
    export  default  AGE;
    
    import myAge from ‘./constants’;
    
    console.log(myAge);  // 30
    

    另外,export default 的变量名称从 Age 到 myAge 之所以可行,是因为只能存在一个 export default 。因此你可以随意命名。还需注意的是,关键字不能在声明变量之前。

    // constants.js
    
    export  default  const  AGE  =  30;  // This is an error and will not work
    

    因此,我们需要在单独的一行使用关键字。

    // constants.js
    
    const  AGE  =  30;
    
    export  default  AGE;
    

    不过以下形式是允许的:

    //constants.js
    
    export  default  {
    
     name:  "Billy",
    
     age:  40
    
    };
    

    并且需要在另一个文件中使用它

    import user from  './constants';
    
    console.log(user.name);  // Billy
    
    console.log(user.age);  // 40
    

    还有,可以使用以下语法来导入 constants.js 文件中导出的所有变量:

    // test.js
    
    import  *  as constants from  './constants';
    

    下面,我们将导入所有我们 constants.js 存储在 constants 变量中的命名和 export default 。因此,constants 现在将成为对象。

    // constants.js
    
    export  const  USERNAME  =  "David";
    
    export  default  {
    
     name:  "Billy",
    
     age:  40
    
    };
    

    在另一个文件中,我们按一下方式使用。

    // test.js
    
    import  *  as constants from  './constants';
    
    console.log(constants.USERNAME);  // David
    
    console.log(constants.default);  // { name: "Billy", age: 40 }
    
    console.log(constants.default.age);  // 40
    

    也可以使用以下方式组合使用命名导出和默认导出:

    // constants.js
    
    const  PI  =  3.14159;  const  AGE  =  30;
    
    const  USERNAME  =  "David";
    
    const  USER  =  {
    
     name:  "Billy",
    
     age:  40
    
    };
    
    export  {  PI,  AGE,  USERNAME,  USER  as  default  };
    
    import  USER,  {  PI,  AGE,  USERNAME  }  from  "./constants";
    

    总而言之:

    ES6 中,一个模块就是一个独立的文件,该文件内部的所有变量,外部都无法获取。如果想从外部读取模块内的某个变量,必须使用 export 关键字导出该变量,使用 import 关键字导入该变量。

    JavaScript 中的默认参数

    ES6 增加了一个非常有用的特性,即在定义函数时提供默认参数。

    假设我们有一个应用程序,一旦用户登录系统,我们将向他们显示一条欢迎消息,如下所示:

    function  showMessage(firstName)  {
    
      return  "Welcome back, "  + firstName;
    
    }
    
    console.log(showMessage('John'));  // Welcome back, John
    

    但是,如果数据库中没有用户名,那该怎么办呢?所以,我们首先需要检查是否提供了 firstName,然后再显示相应的信息。

    在 ES6 之前,我们必须写这样的代码:

    function  showMessage(firstName)  {
    
      if(firstName)  {
    
      return  "Welcome back, "  + firstName;
    
      }  else  {
    
      return  "Welcome back, Guest";
    
      }
    
    }
    
    console.log(showMessage('John'));  // Welcome back, John
    
    console.log(showMessage());  // Welcome back, Guest
    

    但现在使用 ES6 提供的默认参数,我们可以这样写:

    function  showMessage(firstName =  'Guest')  {
    
      return  "Welcome back, "  + firstName;
    
    }
    
    console.log(showMessage('John'));  // Welcome back, John
    
    console.log(showMessage());  // Welcome back, Guest
    

    函数的默认参数可以为任意值。

    function  display(a =  10, b =  20, c = b)  {
    
     console.log(a, b, c);
    
    }
    
    display();  // 10 20 20
    
    display(40);  // 40 20 20
    
    display(1,  70);  // 1 70 70
    
    display(1,  30,  70);  // 1 30 70
    

    在上面的代码中,我们没有提供函数的所有参数,实际代码等同于:

    display();  // 等同于 display(undefined, undefined, undefined)
    
    display(40);  等同于 display(40, undefined, undefined)
    
    display(1,  70);  等同于 display(1, 70, undefined)
    

    因此,如果传递的参数是 undefined,则对应的参数将使用默认值。

    我们还可以将对象或计算值指定为默认值,如下:

    const defaultUser =  {
    
     name:  'Jane',
    
     location:  'NY',
    
     job:  'Software Developer'
    
    };
    
    const  display  =  (user = defaultUser, age =  60  /  2  )  =>  {
    
     console.log(user, age);
    
    };
    
    display();
    
    /* output
    
    {
    
     name: 'Jane',
    
     location: 'NY',
    
     job: 'Software Developer'
    
    } 30
    
    */
    

    ES5 代码如下:

    // ES5 Code
    
    function  getUsers(page, results, gender, nationality)  {
    
      var params =  "";
    
      if(page ===  0  || page)  {
    
     params +=  `page=${page}&`;
    
      }
    
      if(results)  {
    
     params +=  `results=${results}&`;
    
      }
    
      if(gender)  {
    
     params +=  `gender=${gender}&`;
    
      }
    
      if(nationality)  {
    
     params +=  `nationality=${nationality}`;
    
      }
    
      fetch('https://randomuser.me/api/?'  + params)
    
      .then(function(response)  {
    
      return response.json();
    
      })
    
      .then(function(result)  {
    
     console.log(result);
    
      })
    
      .catch(function(error)  {
    
     console.log('error', error);
    
      });
    
    }
    
    getUsers(0,  10,  'male',  'us');
    

    在这段代码中,我们通过在 getUsers 函数中传递各种可选参数来进行 API 调用。在进行 API 调用之前,我们添加了各种 if 条件来检查是否添加了参数,并基于此构造查询字符串,如下所示:

    https://randomuser.me/api/? page=0&results=10&gender=male&nationality=us
    

    使用 ES6 的默认参数则不必添这么多 if 条件,如下所示:

    function  getUsers(page =  0, results =  10, gender =  'male',nationality =  'us')  {
    
     fetch(`https://randomuser.me/api/?page=${page}&results=${results}&gender=${gender}&nationality=${nationality}`)
    
     .then(function(response)  {
    
      return response.json();
    
     })
    
     .then(function(result)  {
    
     console.log(result);
    
     })
    
     .catch(function(error)  {
    
     console.log('error', error);
    
      });
    
    }
    
    getUsers();
    

    这样一来,代码得到了大量的简化,即便我们不为 getUsers 函数提供任何参数时,它也能采用默认值。当然,我们也可以传递自己的参数:

    getUsers(1,  20,  'female',  'gb');
    

    它将覆盖函数的默认参数。

    null 不等于未定义

    注意: 定义默认参数时,null 和 undefined 是不同的。

    我们来看下面的代码:

    function  display(name =  'David', age =  35, location =  'NY'){
    
     console.log(name, age, location);
    
    }
    
    display('David',  35);  // David 35 NY
    
    display('David',  35,  undefined);  // David 35 NY
    
    // OR
    
    display('David',  35,  undefined);  // David 35 NY
    
    display('David',  35,  null);  // David 35 null
    
    

    当我们传递 null 作为参数时,它实际是给 location 参数赋一个空值,与 undefined 不一样。所以它不会取默认值“NY”。

    Array.prototype.includes

    ES7 增加了数组的 includes 方法,用来判断一个数组是否包含一个指定的值,如果是返回 true,否则 false 。

    // ES5 Code
    const numbers = ["one", "two", "three", "four"];
    console.log(numbers.indexOf("one") > -1); // true 
    console.log(numbers.indexOf("five") > -1); // false
    
    

    数组可以使用 includes 方法:

    // ES7 Code
    
    const numbers =  ["one",  "two",  "three",  "four"];
    
    console.log(numbers.includes("one"));  // true
    
    console.log(numbers.includes("five"));  // false
    

    includes 方法可以使代码简短且易于理解,它也可用于比较不同的值。

    <pre style="line-height:18.0pt;
    vertical-align:baseline">const day =  "monday";</pre>
    
    if(day ===  "monday"  || day ===  "tuesday"  || day ===  "wednesday")  {
    
      // do something
    
    }
    
    // 以上代码使用 include 方法可以简化如下:
    
    const day =  "monday";
    
    if(["monday",  "tuesday",  "wednesday"].includes(day))  {
    
      // do something
    
    }
    

    因此,在检查数组中的值时,使用 includes 方法将会非常的方便。

    结语

    从 ES6 开始,JavaScript 中发生许多变更。对于 JavaScript,Angular,React 或 Vue 开发人员都应该知道它们。

    了解这些变更可以使你成为更棒的开发者,甚至可以帮助您获得更高的薪水。而且,如果你只是在学习 React 之类的库以及 Angular 和 Vue 之类的框架,那么您一定要掌握这些新特性。

    29 条回复    2020-12-29 13:24:56 +08:00
    GrapeCityChina
        1
    GrapeCityChina  
    OP
       2020-12-24 11:49:17 +08:00
    自顶,顺便打个广告:

    关于 ES 6,除了语法更新需要了解,开发者还需掌握一些第三方组件,以便更好的完成项目交付。
    例如,使用 SpreadJS 表格组件,可以向 JavaScript 应用程序添加高级电子表格功能,包括支持 450 多种计算公式、在线导入导出 Excel 文档、数据透视表和可视化分析,以创建财务、分析、预算 /预测、数据收集、科学和许多其他类似的应用程序。

    SpreadJS 表格组件地址: https://www.grapecity.com.cn/developer/spreadjs
    HFX3389
        2
    HFX3389  
       2020-12-25 15:03:33 +08:00
    好长
    gqbre
        3
    gqbre  
       2020-12-25 16:36:08 +08:00
    导入导出那块不错
    mascteen
        4
    mascteen  
       2020-12-25 18:05:45 +08:00
    再加一个 Proxy
    hantsy
        5
    hantsy  
       2020-12-25 21:10:34 +08:00
    generaters, class 也是最新 ES 特性,我实在看到 Generaters 晕。
    guansixu
        6
    guansixu  
       2020-12-25 21:43:21 +08:00
    赞👍,写的不错
    agee
        7
    agee  
       2020-12-26 10:49:30 +08:00
    简单明了,赞
    zorui
        8
    zorui  
       2020-12-28 09:53:55 +08:00
    赞👍,现在都 E11 了,es6 都是 5 年前的了。 拥抱 TS 🤭🤭
    yuehui123
        9
    yuehui123  
       2020-12-28 10:28:41 +08:00   ❤️ 5
    好家伙,这是当博客发呢
    corgiyun
        10
    corgiyun  
       2020-12-28 10:34:14 +08:00
    大哥这是做笔记吗???
    baleeny
        11
    baleeny  
       2020-12-28 10:36:36 +08:00
    @zorui 哈哈哈哈
    liamzz
        12
    liamzz  
       2020-12-28 10:52:42 +08:00
    满满的 cv 感
    yamedie
        13
    yamedie  
       2020-12-28 11:05:12 +08:00
    重点在 1 楼打个广告部分, 正文太长可以忽略
    kinghly
        14
    kinghly  
       2020-12-28 12:47:08 +08:00 via Android   ❤️ 2
    还以为这个帖子是几年前的
    XIVN1987
        15
    XIVN1987  
       2020-12-28 13:02:08 +08:00   ❤️ 1
    js 这个 import .. from ... 很魔性啊,自动补全怎么工作?

    是不是先打 form ...,然后在回到行首打 import 啊?
    Lemeng
        16
    Lemeng  
       2020-12-28 14:40:31 +08:00
    好长好长
    AilF
        17
    AilF  
       2020-12-28 15:17:30 +08:00
    JerryCha
        18
    JerryCha  
       2020-12-28 15:39:07 +08:00
    借楼问一个问题,var 和 function 在提升的时候有优先级次序吗
    KamiBako
        19
    KamiBako  
       2020-12-28 16:33:44 +08:00
    这个说得都还挺不错,刚刚看了一圈像是复习了一圈一样。
    ddzy
        20
    ddzy  
       2020-12-28 16:39:04 +08:00
    @JerryCha 先到先得吧
    wednesdayco
        21
    wednesdayco  
       2020-12-28 17:28:15 +08:00
    @XIVN1987 敲出需要 Import 的方法 /类 /变了等,自动提示 import,选择正确的 import,vscode 自动把 import from 加到文件首
    ruanimal
        22
    ruanimal  
       2020-12-28 17:41:43 +08:00
    文末没有二维码,差评
    EPr2hh6LADQWqRVH
        23
    EPr2hh6LADQWqRVH  
       2020-12-28 17:45:31 +08:00 via Android
    这有什么好置顶的。。。
    dingdangnao
        24
    dingdangnao  
       2020-12-28 17:49:52 +08:00
    大小写看着难受。
    soulmt
        25
    soulmt  
       2020-12-28 18:07:47 +08:00
    @JerryCha function 的优先级要高于 var
    rioshikelong121
        26
    rioshikelong121  
       2020-12-28 18:26:47 +08:00
    @avastms 花钱置顶打广告啊。
    hubqin
        27
    hubqin  
       2020-12-28 18:43:30 +08:00 via Android
    @XIVN1987 webstorm 下,使用到时自动 import
    Akat3uki
        28
    Akat3uki  
       2020-12-28 20:51:12 +08:00
    挺好挺细的
    i4oolish
        29
    i4oolish  
       2020-12-29 13:24:56 +08:00
    笔记不错,产品也不错
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5486 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 08:14 · PVG 16:14 · LAX 01:14 · JFK 04:14
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.