阅读 3106

ES6常用但被忽略的方法(第一弹解构赋值和数值)

写在开头

  • ES6常用但被忽略的方法 系列文章,整理作者认为一些日常开发可能会用到的一些方法、使用技巧和一些应用场景,细节深入请查看相关内容连接,欢迎补充交流。

相关文章

解构赋值

剔除对象不需要的属性的值

const obj = {
    name: 'detanx',
    age: 24,
    height: 180
}
// 剔除height
const { height, ...otherObj } = obj;
// otherObj => {name: 'detanx', age: 24}
复制代码

剔除数组不需要的项

const arr = ['detanx', 24, 180]
// 剔除 第一项
const [ name, ...otherArr ] = arr;
// otherArr => [24, 180]
复制代码

设置默认值

  • ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于undefined,默认值才会生效。(面试可能会遇到
const [x = 1] = [undefined];
// x 1
const [x = 1] = [null];
// x null
复制代码
  • 可以引用解构赋值的其他变量,但该变量必须已经声明。
let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError: y is not defined
复制代码

不需要额外变量就可交换两个变量的值

let x = 1, y = 2;
[x, y] = [y, x]
// x: 2,y: 1
复制代码

获取指定的值

// 返回一个数组
function example() {
  return [1, 2, 3];
}
let [a, b, c] = example();

// 返回一个对象
function example() {
  return {
    foo: 1,
    bar: 2
  };
}
let { foo, bar } = example();
// 导入模块某些方法
import { clone } from '_lodash';
复制代码

字符串

includes

  • 之前判断目标字符或字符串片段是否存在某个字符串中需要使用indexOf来判断,返回的结果是首次出现目标的位置,不存在返回-1。实际场景我们并不需要回去目标在字符串中的位置,只需要判断目标是否该字符串中即可,所以我们可以使用includes。同时可以接收第二个参数,表示从左到右第几个位置开始
'detanx'.includes('tan') // true
'detanx'.includes('tan',3) // false
复制代码

查询目标字符在字符串开始或结尾

  • str.startsWith(char[, pos])查询char是否是字符串开头,pos代表从左到右哪一个位置算起始位置。
'detanx'.startsWith('tan', 2) // true
复制代码
  • str.endsWith(char[, len])查询char是否是字符串,len代表从左到右包含多少个字符(即长度)。
'detanx'.endsWith('tan', 5) // true
复制代码

字符串重复多少次repeat

  • 重复字符串多少次,接收一个参数
    1. 当参数为大于-1并且小于1或者为NaN时作为0
    2. 大于1且为小数时向下取整
    3. infinity或者小于-1时会报错
    4. 其他类型会转为数字
'detanx'.repeat(0) // ""
'detanx'.repeat(-0.7) // ""
'detanx'.repeat(NaN) // ""
'detanx'.repeat(2) // "detanxdetanx"
'detanx'.repeat({}) // ""
'detanx'.repeat([]) // ""
'detanx'.repeat(()=>{}) // ""
复制代码

字符串补全

  • 从左边补全padStart,当字符串长度不够需要指定以什么开头,不传第二参数默认使用空格。
// 时间显示小于10补0
const x = 7
if(x < 10) String(x).padStart(2,'0')
// 替换结尾
'04'.padStart(10, 'YYYY-MM-DD'); // 'YYYY-MM-04'
复制代码
  • 从右边补全padEnd,当字符串长度不够需要指定以什么结尾,不传第二参数默认使用空格。
'de'.padEnd(6, 'tanx'); // detanx
复制代码

去掉头或尾空格

  • 除了空格键,这两个方法对字符串头部(或尾部)的 tab 键、换行符等不可见的空白符号也有效。
  • 浏览器还部署了额外的两个方法,trimLeft()trimStart()的别名,trimRight()trimEnd()的别名。
// 去掉头部空格
'  detanx  '.trimStart(); // 'detanx  '
'  detanx  '.trimLeft(); // 'detanx  '
// 去掉尾部空格
'  detanx  '.trimEnd(); // '  detanx'
'  detanx  '.trimRight(); // '  detanx'
复制代码

数值扩展

isFinite

  • 用来检查一个数值是否为有限的(finite),即不是Infinity或者-Infinity。其他类型直接返回false,包括NaN
Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false
复制代码

isInteger

  • 判断一个数值是否为整数。如果对数据精度的要求较高,不建议使用Number.isInteger()判断一个数值是否为整数。
  • JavaScript 采用 IEEE 754 标准,数值存储为64位双精度格式,数值精度最多可以达到 53 个二进制位(1 个隐藏位与 52 个有效位)。如果数值的精度超过这个限度,第54位及后面的位就会被丢弃,这种情况下,Number.isInteger可能会误判。
Number.isInteger(3.0000000000000002) // true
复制代码
  • 这个小数的精度达到了小数点后16个十进制位,转成二进制位超过了53个二进制位,导致最后的那个2被丢弃。
  • 如果一个数值的绝对值小于Number.MIN_VALUE(5E-324),即小于 JavaScript 能够分辨的最小值,会被自动转为 0Number.isInteger也会误判。
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true
复制代码

isSafeInteger

  • Number.isSafeInteger()是用来判断一个整数是否落在Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER这两个常量范围之内。
Number.isSafeInteger('a') // false
Number.isSafeInteger(null) // false
Number.isSafeInteger(NaN) // false
Number.isSafeInteger(Infinity) // false
Number.isSafeInteger(-Infinity) // false

Number.isSafeInteger(3) // true
Number.isSafeInteger(1.2) // false
Number.isSafeInteger(9007199254740990) // true
Number.isSafeInteger(9007199254740992) // false

Number.isSafeInteger(Number.MIN_SAFE_INTEGER - 1) // false
Number.isSafeInteger(Number.MIN_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER) // true
Number.isSafeInteger(Number.MAX_SAFE_INTEGER + 1) // false
复制代码
  • 实际使用这个函数时,需要注意。验证运算结果是否落在安全整数的范围内,不要只验证运算结果,而要同时验证参与运算的每个值。

Math.trunc

  • Math.trunc方法用于去除一个数的小数部分,返回整数部分。非数值,Math.trunc内部使用Number方法将其先转为数值。空值和无法截取整数的值,返回NaN
Math.trunc(4.9) // 4
Math.trunc(-4.1) // -4
Math.trunc(-0.1234) // -0

Math.trunc('123.456') // 123
Math.trunc(true) //1
Math.trunc(false) // 0
Math.trunc(null) // 0

Math.trunc(NaN);      // NaN
Math.trunc('foo');    // NaN
Math.trunc();         // NaN
Math.trunc(undefined) // NaN
复制代码
  • 模拟实现
Math.trunc = Math.trunc || function(x) {
  return x < 0 ? Math.ceil(x) : Math.floor(x);
};
复制代码

Math.sign

  • Math.sign方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
    1. 参数为正数,返回+1;
    2. 参数为负数,返回-1;
    3. 参数为 0,返回0;
    4. 参数为-0,返回-0;
    5. 其他值,返回NaN。
Math.sign(-5) // -1
Math.sign(5) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign(NaN) // NaN
复制代码
  • 如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN
Math.sign('')  // 0
Math.sign(true)  // +1
Math.sign(false)  // 0
Math.sign(null)  // 0
Math.sign('9')  // +1
Math.sign('foo')  // NaN
Math.sign()  // NaN
Math.sign(undefined)  // NaN
复制代码
  • 模拟实现
Math.sign = Math.sign || function(x) {
  x = +x; // convert to a number
  if (x === 0 || isNaN(x)) {
    return x;
  }
  return x > 0 ? 1 : -1;
};
复制代码

Math.cbrt

  • Math.cbrt()方法用于计算一个数的立方根。
Math.cbrt(-1) // -1
Math.cbrt(0)  // 0
Math.cbrt(1)  // 1
Math.cbrt(2)  // 1.2599210498948732
复制代码
  • 对于非数值,Math.cbrt()方法内部也是先使用Number()方法将其转为数值。
Math.cbrt('8') // 2
Math.cbrt('hello') // NaN
复制代码
  • 模拟实现
Math.cbrt = Math.cbrt || function(x) {
  var y = Math.pow(Math.abs(x), 1/3);
  return x < 0 ? -y : y;
};
复制代码

Math.hypot

  • Math.hypot方法返回所有参数的平方和的平方根。
Math.hypot(3, 4);        // 5
Math.hypot(3, 4, 5);     // 7.0710678118654755
Math.hypot();            // 0
Math.hypot(NaN);         // NaN
Math.hypot(3, 4, 'foo'); // NaN
Math.hypot(3, 4, '5');   // 7.0710678118654755
Math.hypot(-3);          // 3
复制代码
  • 上面代码中,3 的平方加上 4 的平方,等于 5 的平方。
  • 如果参数不是数值,Math.hypot方法会将其转为数值。只要有一个参数无法转为数值,就会返回 NaN