ECMAScript 6(三)

数值的扩展 & 函数的扩展

Posted by     "Jordon Li" on Wednesday, December 18, 2019

TOC

ECMAScript 6 简介

ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。

数值的扩展

二进制和八进制表示法

  • 基本用法: ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)0o(或0O)表示。 如果要将0b0o前缀的字符串数值转为十进制,要使用Number方法。
    0b111110111 === 503 // true
    0o767 === 503 // true
    
    Number('0b111')  // 7
    Number('0o10')  // 8
    

Number 对象的扩展

Number.isFinite(), Number.isNaN()

  • 基本用法:

    • Number.isFinite(): 用来检查一个数值是否为有限的(finite),即不是Infinity。如果参数类型不是数值,Number.isFinite一律返回false
    • Number.isNaN():用来检查一个值是否为NaN。如果参数类型不是NaNNumber.isNaN一律返回false
  • 和全局方法isFinite()isNaN()的区别:

    • isFinite()isNaN(): 先调用Number()将非数值的值转为数值,再进行判断。
    • Number.isFinite(): 只对数值有效, 对于非数值一律返回false
    • Number.isNaN():只对数值有效, 只有对于NaN才返回true,非NaN一律返回false
    isFinite(25) // true
    isFinite("25") // true
    Number.isFinite(25) // true
    Number.isFinite("25") // false
    
    isNaN(NaN) // true
    isNaN("NaN") // true
    Number.isNaN(NaN) // true
    Number.isNaN("NaN") // false
    Number.isNaN(1) // false
    

Number.parseInt(), Number.parseFloat()

  • 基本用法: ES6 将全局方法parseInt()parseFloat(),移植到Number对象上面,行为完全保持不变。 这样做的目的,是逐步减少全局性方法,使得语言逐步模块化。
    // ES5的写法
    parseInt('12.34') // 12
    parseFloat('123.45#') // 123.45
    
    // ES6的写法
    Number.parseInt('12.34') // 12
    Number.parseFloat('123.45#') // 123.45
    

Number.isInteger()

  • 基本用法: Number.isInteger()用来判断一个数值是否为整数。

Number.EPSILON

  • 基本用法: ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。 Number.EPSILON实际上是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了。 引入一个这么小的量的目的在于为浮点数计算设置一个误差范围。我们知道浮点数计算是不精确的。

安全整数 和 Number.isSafeInteger()

  • 基本用法: JavaScript 能够准确表示的整数范围在-2^532^53之间(不含两个端点),超过这个范围,无法精确表示这个值。ES6 引入了Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。 Number.isSafeInteger()则是用来判断一个整数是否落在这个范围之内。

Math 对象的扩展

Math.trunc()

  • 基本用法: Math.trunc方法用于去除一个数的小数部分,返回整数部分。

Math.sign()

  • 基本用法: Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。它会返回五种值:
    • 参数为正数,返回+1
    • 参数为负数,返回-1
    • 参数为 0,返回0
    • 参数为-0,返回-0
    • 其他值,返回NaN

Math.cbrt(),Math.hypot()

  • 基本用法: Math.cbrt方法用于计算一个数的立方根。 Math.hypot方法返回所有参数的平方和的平方根。

Math.clz32()

  • 基本用法: Math.clz32()方法将参数转为 32 位无符号整数的形式,然后返回这个 32 位值里面有多少个前导 0。

Math.imul()

  • 基本用法: Math.imul方法返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。

Math.fround()

  • 基本用法: Math.fround方法返回一个数的32位单精度浮点数形式。

对数方法: Math.expm1(), Math.log1p(), Math.log10(), Math.log2()

  • 基本用法:
    • Math.expm1(x)返回 ex - 1,即Math.exp(x) - 1
    • Math.log1p(x)方法返回1 + x的自然对数,即Math.log(1 + x)。如果x小于-1,返回NaN
    • Math.log10(x)返回以 10 为底的x的对数。如果x小于 0,则返回 NaN
    • Math.log2(x)返回以 2 为底的x的对数。如果x小于 0,则返回 NaN`。

双曲函数方法: Math.sinh(), Math.cosh(), Math.tanh(), Math.asinh(), Math.acosh(), Math.atanh()

  • 基本用法:
    • Math.sinh(x) 返回x的双曲正弦(hyperbolic sine)
    • Math.cosh(x) 返回x的双曲余弦(hyperbolic cosine)
    • Math.tanh(x) 返回x的双曲正切(hyperbolic tangent)
    • Math.asinh(x) 返回x的反双曲正弦(inverse hyperbolic sine)
    • Math.acosh(x) 返回x的反双曲余弦(inverse hyperbolic cosine)
    • Math.atanh(x) 返回x的反双曲正切(inverse hyperbolic tangent)

指数运算符

  • 基本用法: ES2016 新增了一个指数运算符(**)。
      2 ** 2 // 4
      2 ** 3 // 8
    

函数的扩展

函数参数的默认值

  • 基本用法: ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。参数变量是默认声明的,所以不能用letconst再次声明。 参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。
      function log(x, y = 'World') {
        console.log(x, y);
      }
    
      log('Hello') // Hello World
      log('Hello', 'China') // Hello China
      log('Hello', '') // Hello
    
      //与解构赋值默认值结合使用
      function foo({x, y = 5} = {}) {
        console.log(x, y);
      }
    
      foo() // undefined 5
    
  • 作用域: 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。

函数的 length 属性

  • 基本用法: 指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。 这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。
      (function (a) {}).length // 1
      (function (a = 5) {}).length // 0
      (function (a, b, c = 5) {}).length // 2
    
      //函数的length属性,不包括 rest 参数。
      (function(...args) {}).length // 0
    
      //如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
      (function (a = 0, b, c) {}).length // 0
      (function (a, b = 1, c) {}).length // 1
    

rest 参数

  • 基本用法: ES6 引入 rest 参数(形式为...变量名:rest参数)(...:扩展运算符),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。 注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
      function add(...values) {
        let sum = 0;
    
        for (var val of values) {
          sum += val;
        }
    
        return sum;
      }
    
      add(2, 5, 3) // 10
    

name 属性

  • 基本用法: 函数的name属性,返回该函数的函数名。这个属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准。
      function foo() {}
      foo.name // "foo"
    
      //将一个匿名函数赋值给一个变量
      var f = function () {};
      // ES5
      f.name // ""
      // ES6
      f.name // "f"
    
      //将一个具名函数赋值给一个变量
      const bar = function baz() {};
      // ES5
      bar.name // "baz"
      // ES6
      bar.name // "baz"
    
      //Function构造函数返回的函数实例,name属性的值为anonymous。
      (new Function).name // "anonymous"
    
      //bind返回的函数,name属性值会加上bound前缀。
      function foo() {};
      foo.bind({}).name // "bound foo"
      (function(){}).bind({}).name // "bound "
    

箭头函数

  • 基本用法: 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;
      };
    
      //如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
      var sum = (num1, num2) => { 
        //...
        return num1 + num2; 
      };
    
      //由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
      let getTempItem = id => { id: id, name: "Temp" }; // 报错
      let getTempItem = id => ({ id: id, name: "Temp" }); // 不报错
    
  • 使用注意点:
    • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。箭头函数让this指向固定化。
    • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
    • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
    • 不可以使用yield命令,因此箭头函数不能用作Generator函数。

严格模式

  • 基本用法: 从 ES5 开始,函数内部可以设定为严格模式('use strict')。 ES2016 做了一点修改,规定只要函数参数使用了默认值解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。 这样规定的原因是,函数内部的严格模式同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。

      function doSomething(a, b) {
        'use strict';
        // code
      }
    
      // 报错
      function doSomething(a, b = a) {
        'use strict';
        // code
      }
    
      // 报错
      const doSomething = function ({a, b}) {
        'use strict';
        // code
      };
    
      // 报错
      const doSomething = (...a) => {
        'use strict';
        // code
      };
    

    两种方法可以规避这种限制:

      //第一种是设定全局性的严格模式
      'use strict';
    
      function doSomething(a, b = a) {
        // code
      }
    
      //第二种是把函数包在一个无参数的立即执行函数里面。
      const doSomething = (function () {
        'use strict';
        return function(value = 42) {
          return value;
        };
      }());
    

尾调用优化

  • 基本用法: 尾调用(Tail Call)是函数式编程的一个重要概念,指某个函数的最后一步是调用另一个函数。函数调用会在内存形成一个调用记录,又称调用帧(call frame)尾调用优化(Tail call optimization),即只保留内层函数的调用帧。 如果所有函数都是尾调用,那么完全可以做到每次执行时,调用帧只有一项,这将大大节省内存。这就是尾调用优化的意义。 ES6 的尾调用优化只在严格模式下开启,正常模式是无效的。这是因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。
    • func.arguments:返回调用时函数的参数。
    • func.caller:返回调用当前函数的那个函数。 尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。 注意,目前只有 Safari 浏览器支持尾调用优化,Chrome 和 Firefox 都不支持。

尾递归

  • 基本用法: 函数调用自身,称为递归。如果尾调用自身,就称为尾递归。尾递归的实现,往往需要改写递归函数,确保最后一步只调用自身。做到这一点的方法,就是把所有用到的内部变量改写成函数的参数。

函数参数的尾逗号

  • 基本用法: ES2017 允许函数的最后一个参数有尾逗号(trailing comma)。
      function clownsEverywhere(
        param1,
        param2,
      ) { /* ... */ }
    

Function.prototype.toString()

  • 基本用法: ES2019 对函数实例的toString()方法做出了修改。toString()方法返回函数代码本身,以前会省略注释和空格。修改后的toString()方法,明确要求返回一模一样的原始代码。
      function /* foo comment */ foo () {}
    
      //ES5:
      foo.toString()
      // function foo() {}
    
      //ES6:
      foo.toString()
      // "function /* foo comment */ foo () {}"
    

catch 命令的参数省略

  • 基本用法: JavaScript 语言的try...catch结构,以前明确要求catch命令后面必须跟参数,接受try代码块抛出的错误对象。ES2019 做出了改变,允许catch语句省略参数。
      try {
        // ...
      } catch {
        // ...
      }
    

「下次一定」

下次一定

使用微信扫描二维码完成支付