ECMAScript 6的一些注意点 第三部分(数组的拓展)

拓展运算符

1.由三个点组成(...),将一个数组转为用逗号分隔的参数序列

2.扩展运算符后面还可以放置表达式,貌似仅限数组中使用

const arr = [
  ...(x > 0 ? ['a'] : []),
  'b',
];

3.后面是空数组,不产生任何效果。

4.扩展运算符如果单独放在括号中,JavaScript 引擎就会认为这是函数调用。如果这时不是函数调用,就会报错。

//这种情况:
(...[1])

替代函数的 apply 方法

1.不再需要apply()将数组转化为函数参数:

function f(a,b){}
let arr = [0,1];
//ES5
f.apply(null,arr)
//ES6
f(...arr)

2.数组Math.max方法:

Math.max(...[1,2,3])

3.数组push数组:

let arr1 = [1,2];
let arr2 = [3,4];
arr1.push(...arr2);    //[1,2,3,4]

4.用数组创建Date实例:

new Date(...[2015, 1, 1]);    //Sun Feb 01 2015 00:00:00 GMT+0800 (中国标准时间)

应用

1.复制数组:(数组时复合数据类型,直接复制只是复制了指针 -- 修改克隆数组会导致原数组的改变

在ES5中使用concat()方法,什么是concat方法? 

示例:

let a = [1,2];
let cloneA = a.concat();    //返回a的副本
cloneA[0] = 2;
a;    //[1,2]

ES6拓展写法:

let a = [1,2];
//写法1
let cloneA = [...a];
//写法2
let [...a] = cloneA;

2.合并数组:

[...arr1 , ...arr2 , ...arr3]

它属于浅拷贝(如果修改了原数组的成员,会同步反映到新数组)

let a1 = [{name:"jack"}];
let a2 = [{age:20}];
let ES6 = [...a1 , ...a2];
let ES5 = a1.concat(a2);
ES6[0].name;               //jack
ES5[0].name;               //jack
a1[0].name = 'tom';
console.log(ES5[0].name)    //tom
console.log(ES6[0].name)    //tom

3.与解构赋值相结合(用于生成数组)

var list = [1,2,3,45]
ES5:
let a= list[0],
rest = list.slice(1);
console.log(a,rest);     //  1 , [2,3,45]
ES6:
let [b,...restb] = list;
console.log(b ,restb)    //  1 , [2,3,45]

拓展运算符,只能放在参数的最后一位,否则会报错

let [...arr , last ] = [ 1, 2 , 3 , 4 ];    //error

4.可以将字符串转为数组

[..."hello"]    //['h','e','l','l','o']

能够正确识别四个字节的 Unicode 字符,涉及到操作四个字节的 Unicode 字符的函数,最好都用扩展运算符改写。

5.实现Iterator接口的对象,只要定义了遍历器接口的对象都可以转为真正数组:

let arr = [...nodeList]

对于没有部署遍历器的类数组对象,可以使用Array.from转换为数组:

let arrayLike = {
  '0': 'a',
  '1': 'b',
  '2': 'c',
  length: 3
};

6.Map,Set解构,Generator函数同上

如果对没有 Iterator 接口的对象,使用扩展运算符,将会报错。


Array.from() - 将两类对象转为真正的数组(类似数组的对象,可遍历对象)

0.类数组对象的本质特征:具有length属性。

1.如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组。

2.Array.from可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

Array.from([1,2,3], (x) => x * x);    //[1,4,9]

技巧:

   1、提取DOM结点内容:

let spans = document.querySelectorAll('span.name');
// Array.from()
let names2 = Array.from(spans, s => s.textContent)

   2、将数组中空位填成0:

Array.from([ 1, ,2 , , 3] , (n) => n || 0 );
//[1,0,2,0,3]

3.若map函数里面用到了this关键字,还可以传入Array.from的第三个参数,用来绑定this

4.只要有一个原始的数据结构,你就可以先对它的值进行处理,然后转成规范的数组结构,进而就可以使用数量众多的数组方法。

Array.from( { length : 2 } , () => 'jack' );    //['jack' , 'jack']

5.字符串转为数组,然后返回字符串的长度。因为它能正确处理各种 Unicode 字符,可以避免 JavaScript 将大于\uFFFF的 Unicode 字符,算作两个字符的 bug。

function countSymbols(string) {
  return Array.from(string).length;
}

Array.of() - 将一组值,转换为数组

1.可以用来替代Array()new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。

Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]
Array.of(1, 2) // [1, 2]

2.Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。


数组实例的coplyWithin() - 使用这个方法,会修改当前数组

1.用法:

Array.prototype.copyWithin(target, start = 0, end = this.length)

它接受三个参数。

  • target(必需):从该位置开始替换数据。如果为负值,表示倒数。
  • start(可选):从该位置开始读取数据,默认为 0。如果为负值,表示倒数。
  • end(可选):到该位置前停止读取数据,默认等于数组长度。如果为负值,表示倒数。

这三个参数都应该是数值,如果不是,会自动转为数值。

let arr = [1, 2, 3, 4, 5, 6, 7];
let arr1 = arr.copyWithin(0, 3)
log(arr1) //[4,5,6,7,5,6,7]     
//表示:将 从3号位开始 到 数组结束的成员 [4,5,6,7] 复制到 从零开始的位置

// 将3号位复制到0号位
[1, 2, 3, 4, 5].copyWithin(0, 3, 4)
// [4, 2, 3, 4, 5]

// -2相当于3号位,-1相当于4号位
[1, 2, 3, 4, 5].copyWithin(0, -2, -1)
// [4, 2, 3, 4, 5]

// 将3号位复制到0号位
[].copyWithin.call({length: 5, 3: 1}, 0, 3)
// {0: 1, 3: 1, length: 5}

// 将2号位到数组结束,复制到0号位
let i32a = new Int32Array([1, 2, 3, 4, 5]);
i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]

// 对于没有部署 TypedArray 的 copyWithin 方法的平台
// 需要采用下面的写法
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]

数组实例的find()方法和findIndex()

find():它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员,未成立返回undeifned

//找出第一个大于9的成员
let arr = [1, 2, 3, 4, 5, 6, 7,10,11];
let arr1 = arr.find((value,index,arr)=>{
    return value > 9 
})
l(arr1)    //10

findIndex,符合条件返回数组成员位置,不符合返回-1

let arr = [1, 2, 3, 4, 5, 6, 7,10,11];
let arr1 = arr.findIndex((value,index,arr)=>{
return value > 9 
})
l(arr1)    //7

这两个方法都可以接受第二个参数,用来绑定回调函数的this对象

let arr = [1, 2, 30];

function f(v) {
    return v > this.age;
}
let person = {
    name: "Job",
    age: 20
};
let a = arr.find(f, person);
a    //30

find函数接收了第二个参数person对象,回调函数中的this对象指向person对象。

这两个方法都可以发现NaN,弥补了数组的indexOf方法的不足。

[NaN].indexOf(NaN)
// -1

[NaN].findIndex(y => Object.is(NaN, y))
// 0

fill()方法 - 使用给定值,填充一个数组(修改原数组)

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

1.数组中已有的元素,会被全部抹去。

2.可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。

3.如果填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。

let arr = new Array(2).fill({name:"jack"});
arr    //[{name:"jack"},{name:"jack"}]
arr[0].name = 'tom'
arr    //[{name:"tom"},{name:"tom"}]

let arr1 = new Array(2).fill([]);
arr1[0].push(5)
arr1    //[ [5] , [5] , [5] ]

entries(),keys() 和 values()

1.用于遍历数组,都返回一个遍历器对象。

2.可以用for...of循环进行遍历,唯一的区别是keys()是对键名的遍历values()是对键值的遍历entries()是对键值对的遍历

let arr = [ "a" , "b" ];
for (let i of arr.keys()){
    console.log(i);    //0   1
}
for(let e of arr.values()){
    console.log(e);    //a    b
}
for(let [i,e] of arr.entries()){
    console.log(i,e);    //0 "a" 1"b"
}

3.不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历

    let arr2 = ['a','b','c'];

    let entries = arr2.entries();
    entries.next().value;     //[0,"a"]
    entries.next().value;     //[1,"b"]
    entries.next().value;     //[2,"c"]

    let values = arr2.values();
    values.next().value;      //a
    values.next().value;      //b
    values.next().value;      //c

    let keys = arr2.keys();
    keys.next().value;        //0
    keys.next().value;        //1
    keys.next().value;        //2    

includes() - 返回一个布尔值,表示某个数组是否包含给定的值

0.对象数组无效。

let arr3  = [{name:'jack'},{name:"tom"}];
let obj = {name:'jack'};
let bool = arr3.includes(obj); //false

1.该方法的第二个参数表示搜索的起始位置,默认为0

2.如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度,则会重置为从0开始

3.indexOf使用===,会造成对NaN的误判,includes不会

4.Map 和 Set 数据结构有一个has方法,需要注意与includes区分。

  • Map 结构的has方法,是用来查找键名的,比如Map.prototype.has(key)WeakMap.prototype.has(key)Reflect.has(target, propertyKey)
  • Set 结构的has方法,是用来查找值的,比如Set.prototype.has(value)WeakSet.prototype.has(value)

数组实例的 flat(),flatMap()

1.flat()用于将嵌套的数组变成一维的数组,该方法返回一个新数组,对原数据没有影响。

2.flat()默认只会将二维数组转换,如果想更深层,在()中写入层数

let arr  = [1,2,[3,4]];
arr = arr.flat();       //[1,2,3,4];
let arr1 = [1,2,3,[4,5,[6,7]]];
arr1 = arr1.flat(2);    //[1,2,3,4,5,6,7]

3.如果不管有多少层嵌套,都要转成一维数组,可以用Infinity关键字作为参数。

4.flat()方法会跳过空位。

5.flatMap()方法对原数组的每个成员执行一个函数.

// 相当于 [[2, 4], [3, 6], [4, 8]].flat()
[2, 3, 4].flatMap((x) => [x, x * 2])
// [2, 4, 3, 6, 4, 8]

6.flatMap()只能展开一层数组。

// 相当于 [[[2]], [[4]], [[6]], [[8]]].flat()
[1, 2, 3, 4].flatMap(x => [[x * 2]])
// [[2], [4], [6], [8]]

7.flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。

8.flatMap()方法的参数是一个遍历函数,该函数可以接受三个参数,分别是当前数组成员、当前数组成员的位置(从零开始)、原数组。

9.flatMap()方法还可以有第二个参数,用来绑定遍历函数里面的this

注意:

 


数组的空位

1.数组的某一个位置没有任何值。

var arr = new Array(3);
arr    //[, , ,]

2.空位不是undefined,一个位置的值等于undefined,依然是有值的,可以用in运算符求证:

in:如果指定的属性在指定的对象或其原型链中,则in 运算符返回true

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false

3.ES5 对空位的处理,已经很不一致了,大多数情况下会忽略空位。

  • forEach()filter()reduce()every() 和some()都会跳过空位。
  • map()会跳过空位,但会保留这个值
  • join()toString()会将空位视为undefined,而undefinednull会被处理成空字符串。

4.Array.from方法会将数组的空位,转为undefined。

5.扩展运算符(...)也会将空位转为undefined

6.copyWithin()会连空位一起拷贝。

7.fill()会将空位视为正常的数组位置。

8.for...of循环也会遍历空位。

9.entries()keys()values()find()findIndex()会将空位处理成undefined

 

 

 

 

 

 

おすすめ

転載: blog.csdn.net/weixin_41564885/article/details/88033598
おすすめ