0
点赞
收藏
分享

微信扫一扫

【ES】151-重温基础:ES6系列(二)

【ES】151-重温基础:ES6系列(二)_数组

ES6系列目录

  • 1 let 和 const命令
  • 2 变量的解构赋值
  • 3 字符串的拓展
  • 4 正则的拓展
  • 数值的拓展
  • 函数的拓展
  • 数组的拓展
  • 8 对象的拓展
  • 9 Symbol
  • 10 Set和Map数据结构
  • 11 Proxy
  • 12 Promise对象
  • 13 Iterator和 for...of循环
  • 14 Generator函数和应用
  • 15 Class语法和继承
  • 16 Module语法和加载实现


所有整理的文章都收录到我《Cute-JavaScript》系列文章中,访问地址:http://js.pingan8787.com


5 数值的拓展

5.1 Number.isFinite(), Number.isNaN()

Number.isFinite()​​ 用于检查一个数值是否是有限的,即不是 ​Infinity​​,若参数不是 ​Number​​类型,则一律返回 ​false​ 。

  1. Number.isFinite(10);            // true
  2. Number.isFinite(0.5);           // true
  3. Number.isFinite(NaN);           // false
  4. Number.isFinite(Infinity);      // false
  5. Number.isFinite(-Infinity);     // false
  6. Number.isFinite('leo');         // false
  7. Number.isFinite('15');          // false
  8. Number.isFinite(true);          // false
  9. Number.isFinite(Math.random()); // true

Number.isNaN()​​用于检查是否是 ​NaN​​,若参数不是 ​NaN​​,则一律返回 ​false​。

  1. Number.isNaN(NaN);      // true
  2. Number.isNaN(10);       // false
  3. Number.isNaN('10');     // false
  4. Number.isNaN(true);     // false
  5. Number.isNaN(5/NaN);    // true
  6. Number.isNaN('true' / 0);      // true
  7. Number.isNaN('true' / 'true'); // true

区别
与传统全局的 ​​isFinite()​​和 ​isNaN()​方法的区别,传统的这两个方法,是先将参数转换成数值,再判断。
而ES6新增的这两个方法则只对数值有效, ​Number.isFinite()​对于非数值一律返回 ​false​​, ​Number.isNaN()​​只有对于 ​NaN​​才返回 ​true​​,其他一律返回 ​false​。

  1. isFinite(25);          // true
  2. isFinite("25");        // true
  3. Number.isFinite(25);   // true
  4. Number.isFinite("25"); // false

  5. isNaN(NaN);            // true
  6. isNaN("NaN");          // true
  7. Number.isNaN(NaN);     // true
  8. Number.isNaN("NaN");   // false

5.2 Number.parseInt(), Number.parseFloat()

这两个方法与全局方法 ​parseInt()​​和 ​parseFloat()​一致,目的是逐步减少全局性的方法,让语言更模块化

  1. parseInt('12.34');     // 12
  2. parseFloat('123.45#'); // 123.45

  3. Number.parseInt('12.34');     // 12
  4. Number.parseFloat('123.45#'); // 123.45

  5. Number.parseInt === parseInt;     // true
  6. Number.parseFloat === parseFloat; // true

5.3 Number.isInteger()

用来判断一个数值是否是整数,若参数不是数值,则返回 ​false​。

  1. Number.isInteger(10);   // true
  2. Number.isInteger(10.0); // true
  3. Number.isInteger(10.1); // false

5.4 Math对象的拓展

ES6新增17个数学相关的静态方法,只能在Math对象上调用。

  • Math.trunc:
    用来去除小数的小数部分,返回整数部分
    若参数为非数值,则先转为数值
    若参数为空值无法截取整数的值,则返回NaN
  1. // 正常使用
  2. Math.trunc(1.1);     // 1
  3. Math.trunc(1.9);     // 1
  4. Math.trunc(-1.1);    // -1
  5. Math.trunc(-1.9);    // -1
  6. Math.trunc(-0.1234); // -0

  7. // 参数为非数值
  8. Math.trunc('11.22'); // 11
  9. Math.trunc(true);    // 1
  10. Math.trunc(false);   // 0
  11. Math.trunc(null);    // 0

  12. // 参数为空和无法取整
  13. Math.trunc(NaN);       // NaN
  14. Math.trunc('leo');     // NaN
  15. Math.trunc();          // NaN
  16. Math.trunc(undefined); // NaN

ES5实现

  1. Math.trunc = Math.trunc || function(x){
  2.    return x < 0 ? Math.ceil(x) : Math.floor(x);
  3. }
  • Math.sign():
    判断一个数是正数负数是零,对于非数值,会先转成数值
    返回值:
  • 参数为正数, 返回 +1
  • 参数为负数, 返回 -1
  • 参数为0, 返回 0
  • 参数为-0, 返回 -0
  • 参数为其他值, 返回 NaN
  1. Math.sign(-1);   // -1
  2. Math.sign(1);    // +1
  3. Math.sign(0);    // 0
  4. Math.sign(-0);   // -0
  5. Math.sign(NaN);  // NaN

  6. Math.sign('');   // 0
  7. Math.sign(true); // +1
  8. Math.sign(false);// 0
  9. Math.sign(null); // 0
  10. Math.sign('9');  // +1
  11. Math.sign('leo');// NaN
  12. Math.sign();     // NaN
  13. Math.sign(undefined); // NaN

ES5实现

  1. Math.sign = Math.sign || function (x){
  2.    x = +x;
  3.    if (x === 0 || isNaN(x)){
  4.        return x;
  5.    }
  6.    return x > 0 ? 1: -1;
  7. }
  • Math.cbrt():
    用来计算一个数的立方根,若参数为非数值则先转成数值。
  1. Math.cbrt(-1); // -1
  2. Math.cbrt(0);  // 0
  3. Math.cbrt(1);  // 1
  4. Math.cbrt(2);  // 1.2599210498

  5. Math.cbrt('1');   // 1
  6. Math.cbrt('leo'); // NaN

ES5实现

  1. Math.cbrt = Math.cbrt || function (x){
  2.    var a = Math.pow(Math.abs(x), 1/3);
  3.    return x < 0 ? -y : y;
  4. }
  • Math.clz32():
    用于返回一个数的 32 位无符号整数形式有多少个前导 0。
  1. Math.clz32(0) // 32
  2. Math.clz32(1) // 31
  3. Math.clz32(1000) // 22
  4. Math.clz32(0b01000000000000000000000000000000) // 1
  5. Math.clz32(0b00100000000000000000000000000000) // 2
  • Math.imul():
    用于返回两个数以 32 位带符号整数形式相乘的结果,返回的也是一个 32 位的带符号整数。
  1. Math.imul(2, 4)   // 8
  2. Math.imul(-1, 8)  // -8
  3. Math.imul(-2, -2) // 4
  • Math.fround():
    用来返回一个数的2位单精度浮点数形式。
  1. Math.fround(0)   // 0
  2. Math.fround(1)   // 1
  3. Math.fround(2 ** 24 - 1)   // 16777215
  • Math.hypot():
    用来返回所有参数的平方和的平方根
  1. Math.hypot(3, 4);        // 5
  2. Math.hypot(3, 4, 5);     // 7.0710678118654755
  3. Math.hypot();            // 0
  4. Math.hypot(NaN);         // NaN
  5. Math.hypot(3, 4, 'foo'); // NaN
  6. Math.hypot(3, 4, '5');   // 7.0710678118654755
  7. Math.hypot(-3);          // 3
  • Math.expm1():
    用来返回 ​​ex-1​​,即 ​​Math.exp(x)-1​​。
  1. Math.expm1(-1) // -0.6321205588285577
  2. Math.expm1(0)  // 0
  3. Math.expm1(1)  // 1.718281828459045

ES5实现

  1. Math.expm1 = Math.expm1 || function(x) {
  2.  return Math.exp(x) - 1;
  3. };
  • Math.log1p():
    用来返回 ​​1+x​​的自然对数,即 ​​Math.log(1+x)​​。如果x小于 ​​-1​​,返回 ​​NaN​​。
  1. Math.log1p(1)  // 0.6931471805599453
  2. Math.log1p(0)  // 0
  3. Math.log1p(-1) // -Infinity
  4. Math.log1p(-2) // NaN

ES5实现

  1. Math.log1p = Math.log1p || function(x) {
  2.  return Math.log(1 + x);
  3. };
  • Math.log10():
    用来返回以 ​​10​​为底的 ​​x的对数​​。如果x小于 0,则返回 ​​NaN​​。
  1. Math.log10(2)      // 0.3010299956639812
  2. Math.log10(1)      // 0
  3. Math.log10(0)      // -Infinity
  4. Math.log10(-2)     // NaN
  5. Math.log10(100000) // 5

ES5实现

  1. Math.log10 = Math.log10 || function(x) {
  2.  return Math.log(x) / Math.LN10;
  3. };
  • Math.log2():
    用来返回以 ​​2​​ 为底的 ​​x的对数​​。如果 ​​x​​小于 ​​0​​,则返回 ​​NaN​​。
  1. Math.log2(3)       // 1.584962500721156
  2. Math.log2(2)       // 1
  3. Math.log2(1)       // 0
  4. Math.log2(0)       // -Infinity
  5. Math.log2(-2)      // NaN
  6. Math.log2(1024)    // 10
  7. Math.log2(1 << 29) // 29

ES5实现

  1. Math.log2 = Math.log2 || function(x) {
  2.  return Math.log(x) / Math.LN2;
  3. };
  • 双曲函数方法:
  • ​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)

5.5 指数运算符

新增的指数运算符( ​**​):

  1. 2 ** 2; // 4
  2. 2 ** 3; // 8

  3. 2 ** 3 ** 2; // 相当于 2 ** (3 ** 2); 返回 512

指数运算符( ​**​​)与 ​Math.pow​的实现不相同,对于特别大的运算结果,两者会有细微的差异。

  1. Math.pow(99, 99)
  2. // 3.697296376497263e+197

  3. 99 ** 99
  4. // 3.697296376497268e+197

6 函数的拓展

6.1 参数默认值

  1. // ES6 之前
  2. function f(a, b){
  3.    b = b || 'leo';
  4.    console.log(a, b);
  5. }

  6. // ES6 之后
  7. function f(a, b='leo'){
  8.    console.log(a, b);
  9. }

  10. f('hi');          // hi leo
  11. f('hi', 'jack');  // hi jack
  12. f('hi', '');      // hi leo

注意:

  • 参数变量是默认声明的,不能用 ​let​​和 ​​const​​再次声明:
  1. function f (a = 1){
  2.    let a = 2; // error
  3. }
  • 使用参数默认值时,参数名不能相同:
  1. function f (a, a, b){ ... };     // 不报错
  2. function f (a, a, b = 1){ ... }; // 报错

与解构赋值默认值结合使用

  1. function f ({a, b=1}){
  2.    console.log(a,b)
  3. };
  4. f({});         // undefined 1
  5. f({a:2});      // 2 1
  6. f({a:2, b:3}); // 2 3
  7. f();           // 报错

  8. function f ({a, b = 1} = {}){
  9.    console.log(a, b)
  10. }
  11. f();  // undefined 1

尾参数定义默认值:
通常在尾参数定义默认值,便于观察参数,并且非尾参数无法省略。

  1. function f (a=1,b){
  2.    return [a, b];
  3. }
  4. f();    // [1, undefined]
  5. f(2);   // [2, undefined]
  6. f(,2);  // 报错

  7. f(undefined, 2);  // [1, 2]

  8. function f (a, b=1, c){
  9.    return [a, b, c];
  10. }
  11. f();        // [undefined, 1, undefined]
  12. f(1);       // [1,1,undefined]
  13. f(1, ,2);   // 报错
  14. f(1,undefined,2); // [1,1,2]

在给参数传递默认值时,传入 ​undefined​​会触发默认值,传入 ​null​不会触发。

  1. function f (a = 1, b = 2){
  2.    console.log(a, b);
  3. }
  4. f(undefined, null); // 1 null

函数的length属性:
​​length​​属性将返回,没有指定默认值的参数数量,并且rest参数不计入 ​length​属性。

  1. function f1 (a){...};
  2. function f2 (a=1){...};
  3. function f3 (a, b=2){...};
  4. function f4 (...a){...};
  5. function f5 (a,b,...c){...};

  6. f1.length; // 1
  7. f2.length; // 0
  8. f3.length; // 1
  9. f4.length; // 0
  10. f5.length; // 2

6.2 rest 参数

rest​​参数形式为( ​...变量名​),其值为一个数组,用于获取函数多余参数。

  1. function f (a, ...b){
  2.    console.log(a, b);
  3. }
  4. f(1,2,3,4); // 1 [2, 3, 4]

注意

  • rest​参数只能放在最后一个,否则报错:
  1. function f(a, ...b, c){...}; // 报错
  • 函数的 ​length​​属性不包含 ​​rest​​参数。
  1. function f1 (a){...};
  2. function f2 (a,...b){...};
  3. f1(1);   // 1
  4. f2(1,2); // 1

6.3 name 属性

用于返回该函数的函数名。

  1. function f (){...};
  2. f.name;    // f

  3. const f = function g(){...};
  4. f.name;    // g

6.4 箭头函数

使用“箭头”( ​=>​​)定义函数。
基础使用

  1. // 有1个参数
  2. let f = v => v;
  3. // 等同于
  4. let f = function (v){return v};

  5. // 有多个参数
  6. let f = (v, i) => {return v + i};
  7. // 等同于
  8. let f = function (v, i){return v + i};

  9. // 没参数
  10. let f = () => 1;
  11. // 等同于
  12. let f = function (){return 1};

箭头函数与变量结构结合使用

  1. // 正常函数写法
  2. function f (p) {
  3.    return p.a + ':' + p.b;
  4. }

  5. // 箭头函数写法
  6. let f = ({a, b}) => a + ':' + b;

简化回调函数

  1. // 正常函数写法
  2. [1, 2, 3].map(function (x){
  3.    return x * x;
  4. })


  5. // 箭头函数写法
  6. [1, 2, 3].map(x => x * x);

箭头函数与rest参数结合

  1. let f = (...n) => n;
  2. f(1, 2, 3); // [1, 2, 3]

注意点

  • 1.箭头函数内的 ​this总是指向定义时所在的对象,而不是调用时。
  • 2.箭头函数不能当做构造函数,即不能用 ​new​命令,否则报错。
  • 3.箭头函数不存在 ​arguments​​对象,即不能使用,可以使用 ​​rest​​参数代替。
  • 4.箭头函数不能使用 ​yield​命令,即不能用作Generator函数。

不适用场景

  • 1.在定义函数方法,且该方法内部包含 ​this​。
  1. const obj = {
  2.    a:9,
  3.    b: () => {
  4.        this.a --;
  5.    }
  6. }

上述 ​b​如果是普通函数,函数内部的 ​this​​指向 ​obj​​,但是如果是箭头函数,则 ​this​会指向全局,不是预期结果。

  • 2.需要动态 ​this​时。
  1. let b = document.getElementById('myID');
  2. b.addEventListener('click', ()=>{
  3.    this.classList.toggle('on');
  4. })

上诉按钮点击会报错,因为 ​b​​监听的箭头函数中, ​this​是全局对象,若改成普通函数, ​this​就会指向被点击的按钮对象。

6.5 双冒号运算符

双冒号暂时是一个提案,用于解决一些不适用的场合,取代 ​call​​、 ​apply​​、 ​bind​​调用。
双冒号运算符( ​​::​)的左边是一个对象,右边是一个函数。该运算符会自动将左边的对象,作为上下文环境(即 ​this​对象),绑定到右边函数上。

  1. f::b;
  2. // 等同于
  3. b.bind(f);

  4. f::b(...arguments);
  5. // 等同于
  6. b.apply(f, arguments);

若双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定到该对象上。

  1. let f = a::a.b;
  2. // 等同于
  3. let f = ::a.b;

7 数组的拓展

7.1 拓展运算符

拓展运算符使用( ​...​​),类似 ​rest​​参数的逆运算,将数组转为用( ​,​)分隔的参数序列。

  1. console.log(...[1, 2, 3]);   // 1 2 3
  2. console.log(1, ...[2,3], 4); // 1 2 3 4

拓展运算符主要使用在函数调用。

  1. function f (a, b){
  2.    console.log(a, b);
  3. }
  4. f(...[1, 2]); // 1 2

  5. function g (a, b, c, d, e){
  6.    console.log(a, b, c, d, e);
  7. }
  8. g(0, ...[1, 2], 3, ...[4]); // 0 1 2 3 4

若拓展运算符后面是个空数组,则不产生效果

  1. [...[], 1]; // [1]

替代apply方法

  1. // ES6之前
  2. function f(a, b, c){...};
  3. var a = [1, 2, 3];
  4. f.apply(null, a);

  5. // ES6之后
  6. function f(a, b, c){...};
  7. let a = [1, 2, 3];
  8. f(...a);

  9. // ES6之前
  10. Math.max.apply(null, [3,2,6]);

  11. // ES6之后
  12. Math.max(...[3,2,6]);

拓展运算符的运用

  • (1)复制数组
    通常我们直接复制数组时,只是浅拷贝,如果要实现深拷贝,可以使用拓展运算符。
  1. // 通常情况 浅拷贝
  2. let a1 = [1, 2];
  3. let a2 = a1;
  4. a2[0] = 3;
  5. console.log(a1,a2); // [3,2] [3,2]

  6. // 拓展运算符 深拷贝
  7. let a1 = [1, 2];
  8. let a2 = [...a1];
  9. // let [...a2] = a1; // 作用相同
  10. a2[0] = 3;
  11. console.log(a1,a2); // [1,2] [3,2]
  • (2)合并数组
    注意,这里合并数组,只是浅拷贝。
  1. let a1 = [1,2];
  2. let a2 = [3];
  3. let a3 = [4,5];

  4. // ES5
  5. let a4 = a1.concat(a2, a3);

  6. // ES6
  7. let a5 = [...a1, ...a2, ...a3];

  8. a4[0] === a1[0]; // true
  9. a5[0] === a1[0]; // true
  • (3)与解构赋值结合
    与解构赋值结合生成数组,但是使用拓展运算符需要放到参数最后一个,否则报错。
  1. let [a, ...b] = [1, 2, 3, 4];
  2. // a => 1  b => [2,3,4]

  3. let [a, ...b] = [];
  4. // a => undefined b => []

  5. let [a, ...b] = ["abc"];
  6. // a => "abc"  b => []

7.2 Array.from()

类数组对象可遍历的对象,转换成真正的数组。

  1. // 类数组对象
  2. let a = {
  3.    '0':'a',
  4.    '1':'b',
  5.    length:2
  6. }
  7. let arr = Array.from(a);

  8. // 可遍历的对象
  9. let a = Array.from([1,2,3]);
  10. let b = Array.from({length: 3});
  11. let c = Array.from([1,2,3]).map(x => x * x);
  12. let d = Array.from([1,2,3].map(x => x * x));

7.3 Array.of()

将一组数值,转换成数组,弥补 ​Array​方法参数不同导致的差异。

  1. Array.of(1,2,3);    // [1,2,3]
  2. Array.of(1).length; // 1

  3. Array();       // []
  4. Array(2);      // [,] 1个参数时,为指定数组长度
  5. Array(1,2,3);  // [1,2,3] 多于2个参数,组成新数组

7.4 find()和findIndex()

find()​​方法用于找出第一个符合条件的数组成员,参数为一个回调函数,所有成员依次执行该回调函数,返回第一个返回值为 ​true​​的成员,如果没有一个符合则返回 ​undefined​。

  1. [1,2,3,4,5].find( a => a < 3 ); // 1

回调函数接收三个参数,当前值、当前位置和原数组。

  1. [1,2,3,4,5].find((value, index, arr) => {
  2.    // ...
  3. });

findIndex()​​方法与 ​find()​类似,返回第一个符合条件的数组成员的位置,如果都不符合则返回 ​-1​。

  1. [1,2,3,4].findIndex((v,i,a)=>{
  2.    return v>2;
  3. }); // 2

7.5 fill()

用于用指定值填充一个数组,通常用来初始化空数组,并抹去数组中已有的元素。

  1. new Array(3).fill('a');   // ['a','a','a']
  2. [1,2,3].fill('a');        // ['a','a','a']

并且 ​fill()​的第二个和第三个参数指定填充的起始位置结束位置

  1. [1,2,3].fill('a',1,2);//  [1, "a", 3]

7.6 entries(),keys(),values()

主要用于遍历数组, ​entries()​​对键值对遍历, ​keys()​​对键名遍历, ​values()​对键值遍历。

  1. for (let i of ['a', 'b'].keys()){
  2.    console.log(i)
  3. }
  4. // 0
  5. // 1

  6. for (let e of ['a', 'b'].values()){
  7.    console.log(e)
  8. }
  9. // 'a'
  10. // 'b'

  11. for (let e of ['a', 'b'].entries()){
  12.    console.log(e)
  13. }
  14. // 0 'a'
  15. // 1 'b'

7.7 includes()

用于表示数组是否包含给定的值,与字符串的 ​includes​方法类似。

  1. [1,2,3].includes(2);     // true
  2. [1,2,3].includes(4);     // false
  3. [1,2,NaN].includes(NaN); // true

第二个参数为起始位置,默认为 ​0​​,如果负数,则表示倒数的位置,如果大于数组长度,则重置为 ​0​开始。

  1. [1,2,3].includes(3,3);    // false
  2. [1,2,3].includes(3,4);    // false
  3. [1,2,3].includes(3,-1);   // true
  4. [1,2,3].includes(3,-4);   // true

7.8 flat(),flatMap()

flat()​​用于将数组一维化,返回一个新数组,不影响原数组。
默认一次只一维化一层数组,若需多层,则传入一个整数参数指定层数。
若要一维化所有层的数组,则传入 ​​Infinity​作为参数。

  1. [1, 2, [2,3]].flat();        // [1,2,2,3]
  2. [1,2,[3,[4,[5,6]]]].flat(3); // [1,2,3,4,5,6]
  3. [1,2,[3,[4,[5,6]]]].flat('Infinity'); // [1,2,3,4,5,6]

flatMap()​​是将原数组每个对象先执行一个函数,在对返回值组成的数组执行 ​flat()​​方法,返回一个新数组,不改变原数组。
​​flatMap()​只能展开一层。

  1. [2, 3, 4].flatMap((x) => [x, x * 2]);
  2. // [2, 4, 3, 6, 4, 8]


【ES】151-重温基础:ES6系列(二)_默认值_02


举报

相关推荐

0 条评论