美文网首页
ES6数组的扩展

ES6数组的扩展

作者: 那谁与我无关a | 来源:发表于2018-12-03 16:47 被阅读0次

最近一直在看es6新曾的一写数组的拓展,总结出了一些知识点

  • find,findIndex,inclueds
  • Map Set
  • 静态方法(from,of)

find,findIndex,inclueds

find和findIndex

语法

arr .find(callback(element[, index[, array]])[, thisArg])
arr .findIndex(callback(element[, index[, array]])[, thisArg])

参数

callback

函数对数组中的每个值执行,取三个参数

element

当前元素在数组中处理。

index(可选的)

数组中正在处理的当前元素的索引。

array(可选的)

该阵列find被召唤。

thisArg (可选的)

this在执行时使用的对象callback。

数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员的value。如果没有符合条件的成员,则返回undefined。

let inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

function findCherries(fruit) { 
    return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }

下面代码是找出数组中第一个大于9的成员

[1, 5, 10, 15].find((value, index, arr)=> {
  return value > 9;
}) // 10

[1, 5, 10, 15].find((value, index, arr)=> {
  if(index>2){
    return value > 9;
  }
}) // 15

数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。上面find一样,不赘述。

[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

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

function f(value){
  return value > this.age;
}
let person = {name: 'John', age: 20};
[10, 12, 26, 15].find(f, person);    // 26

includes

includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似

语法

arr .includes(searchElement [,fromIndex])

参数

searchElement

要在数组中定位的元素。

fromIndex (可选的)

用于开始搜索的索引。如果索引大于或等于数组的长度,则返回-1,这意味着不会搜索该数组。如果提供的索引值为负数,则将其作为数组末尾的偏移量。注意:如果提供的索引为负数,则仍会从前到后搜索数组。如果提供的索引为0,则将搜索整个数组。默认值:0(搜索整个数组)。

返回值

数组中元素的第一个索引; -1如果没有找到。

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

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

没有该方法之前,我们通常使用数组的indexOf方法,检查是否包含某个值。
indexOf方法有两个缺点,一是不够语义化,它的含义是找到参数值的第一个出现位置,所以要去比较是否不等于-1,表达起来不够直观。二是,它内部使用严格相等运算符(===)进行判断,这会导致对NaN的误判。
includes使用的是不一样的判断算法,就没有这个问题。

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

另外,这find(),findIndex()两个方法都可以发现NaN,也弥补了数组的indexOf方法的不足。

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

附: Object.is() , === 和 == 对比表


对比表
//Object.is()的实现原理
isObject = function(x, y) {
    if (x === y) { // Steps 1-5, 7-10
      // 针对 +0不等于-0
      return x !== 0 || 1 / x === 1 / y;
    } else {
      // 针对 NaN等于NaN
      return x !== x && y !== y;
    }
  };

数组的去重

//最原始方法
var array = [1, 1, '1', '1'];

function unique(array) {
    // res用来存储结果
    var res = [];
    for (var i = 0, arrayLen = array.length; i < arrayLen; i++) {
        for (var j = 0, resLen = res.length; j < resLen; j++ ) {
            if (array[i] === res[j]) {
                break;
            }
        }
        // 如果array[i]是唯一的,那么执行完循环,j等于resLen
        if (j === resLen) {
            res.push(array[i])
        }
    }
    return res;
}

console.log(unique(array)); // [1, "1"]


//indexOf
var array = [1, 1, '1'];

function unique(array) {
    var res = [];
    for (var i = 0, len = array.length; i < len; i++) {
        var current = array[i];
        if (res.indexOf(current) === -1) {
            res.push(current)
        }
    }
    return res;
}

console.log(unique(array));

//filter
var array = [1, 2, 1, 1, '1'];

function unique(array) {
    var res = array.filter(function(item, index, array){
        return array.indexOf(item) === index;
    })
    return res;
}

console.log(unique(array));

Map和Set

在以数组和对象为编程主力的JavaScript 语言,ES6 中引入了4种新的数据结构,分别是:集合(Set)、弱集合(WeakSet)、映射(Map)、弱映射(WeakMap)。

Set

Set 对象是值的集合,可以按照插入的顺序迭代它的元素。Set 中的元素只会出现一次,即 Set 中的元素是唯一的。

语法

new Set([ iterable ]);

参数

iterable
是一个可迭代的对象,它的所有元素将被添加到新的 Set 中。
由于 Set 中的值总是唯一的,所以需要判断两个值是否相等。在上面,内部使用Object.is()方法检测两个值是否一致,但+0、-0和0被视为是相等的元素,NaN 和 undefined 是可以被存储在 Set 中的,因为 NaN 在ES6中是严格相等的。

new Set([NaN, NaN, 2, "2", +0, -0]); // Set(4) {NaN, 2, '2', 0}

属性

Set.prototype.size:返回 Set 对象的值的个数。

let mySet1 = new Set([NaN, NaN, 2, 3, 5, 5]);
mySet1.size; // 4

方法

(1)、在 Set 对象尾部添加一个元素:Set.prototype.add(value)

let  mySet1=new Set([NaN,1,2,3]).add(NaN).add(2).add(4); //Set(5) {NaN, 1, 2, 3, 4}

(2)、清除 Set 中所有的元素:Set.prototype.clear()

let mySet2=new Set(NaN,1,2,3).clear();  //undefined

(3)、判断值是否存在于 Set 中:Set.prototype.has(value);

let mySet3=new Set([1,2,3,4,5]).has(2); //true
let mySet4=new Set([1,2,3,4,5]).has(7); //false

(4)、删除 Set 中的某个值: Set.prototype.delete(value);

var mySet = new Set();
mySet.add("foo");
mySet.delete("bar"); // 返回 false,不包含 "bar" 这个元素
mySet.delete("foo"); // 返回 true,删除成功
mySet.has("foo");    // 返回 false,"bar" 已经成功删除

WeakSet

1、WeakSet 结构与 Set 结构类似,WeakSet 是一个构造函数,可以使用 new 命令创建 WeakSet 数据结构。

const a= ["yuan", "monkey"];
const myWeakSet = new WeakSet(a);  // WeakSet {"yuan", "monkey" }

2、与 Set 区别
(1)、WeakSet 的成员只能是对象,而不能是其他类型的值。
(2)、WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用。 也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中。这是因为垃圾回收机制依赖引用计数,如果一个值的引用次数不为0,垃圾回收机制就不会释放这块内存。结束使用该值之后,有时会忘记取消引用,导致内存无法释放,进而可能会引发内存泄漏。WeakSet 里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。因此,WeakSet 适合临时存放一组对象,以及存放跟对象绑定的信息。只要这些对象在外部消失,它在 WeakSet 里面的引用就会自动消失。

由于上面这个特点,WeakSet 的成员是不适合引用的,因为它会随时消失。另外,由于 WeakSet 内部有多少个成员,取决于垃圾回收机制有没有运行,运行前后很可能成员个数是不一样的,而垃圾回收机制何时运行是不可预测的,因此 ES6 规定 WeakSet 不可遍历。

这些特点同样适用于本章后面要介绍的 WeakMap 结构。
(3)、WeakSet 没有size 属性,没有办法遍历其成员。
3、方法
(1)、WeakSet.prototype.add(value):添加新成员;
(2)、WeakSet.prototype.delete(value):清楚指定成员;
(3)、WeakSet.prototype.has(value):判断是否存在某个成员

Map

Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
一个Map对象以插入顺序迭代其元素 — 一个 for...of 循环为每次迭代返回一个[key,value]数组。

语法

new Map([ iterable ]);

参数

iterable
Iterable 可以是一个数组或者其他 iterable 对象,其元素或为键值对,或为两个元素的数组。 每个键值对都会添加到新的 Map。null 会被当做 undefined。

方法

(1)Map.prototype.set(key, value)
设置Map对象中键的值。返回该Map对象。
(2)Map.prototype.clear()
移除Map对象的所有键/值对 。
(3)Map.prototype.has(key)
返回一个布尔值,表示Map实例是否包含键对应的值。

myMap.set("bar", "baz");
myMap.set(1, "foo");

myMap.size;       // 2
myMap.has("bar"); // true

myMap.clear();

myMap.size;       // 0
myMap.has("bar")  // false

(4)Map.prototype.delete(key)
移除任何与键相关联的值,并且返回该值,该值在之前会被

var myMap = new Map();
myMap.set("bar", "foo");
myMap.delete("bar"); // 返回 true。成功地移除元素
myMap.has("bar");    // 返回 false。"bar" 元素将不再存在于 Map 实例中

应用

应用
(1)、Map 与 数组之间的相互转换

// Map 转数组
var myMap = new Map();
myMap.set("bar", "foo");
myMap.set(1, "bar");
[...myMap]; //  [ ["bar", "foo"], [1, "bar"] ]
// 数组转Map
const arr = new Map( [ ["bar", "foo"], [1, "bar"] ]);
console.log(arr);  // Map {"bar" => "foo", 1 => "bar"}

(2)、Map 与对象相互转换

// Map 转对象
function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k, v] of strMap) {
    obj[k] = v;
  }
  return obj;
}
 const myMap = new Map();
myMap.set("bar", "foo")
.set(1, "ooo");

strMapToObj(myMap ); // Object {1: "ooo", bar: "foo"}

// 对象转 Map
function objToStrMap(obj) {
  let strMap = new Map();
  for (let k of Object.keys(obj)) {
    strMap.set(k, obj[k]);
  }
  return strMap;
}
objToStrMap({1: "ooo", bar: "foo"}); // Map {"1" => "ooo", "bar" => "foo"}

(3)、Map 与 JSON 相互转换

// Map 转 JSON
// Map 的键名为字符串
function strMapToJson(jsonStr) {
  return JSON.stringify(strMapToObj(jsonStr));
}
const myMap = new Map();
myMap.set("bar", "foo")
.set(1, "ooo");
strMapToJson(myMap); // "{"1":"ooo","bar":"foo"}"

// Map 的键名为非字符串
function mapToArrayJson(map) {
  return JSON.stringify([...map]);
}
mapToArrayJson(myMap); // "[["bar","foo"],[1,"ooo"]]"

// Json 转 Map
// 正常情况下所有键名都为字符串
function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}
jsonToStrMap("{"1":"ooo","bar":"foo"}"); // Map {"1" => "ooo", "bar" => "foo"}

// 整个JSON 是数组
function jsonToMap(jsronStr) {
  return new Map(JSON.parse(jsronStr)); 
}
jsonToMap([["bar","foo"],[1,"ooo"]]); // Map {"1" => "ooo", "bar" => "foo"}

WeakMap

含义

WeakMap 结构与 Map结构类似,也是用于生成键值对的集合。

与 Map 区别

(1)WeakMap 只接受对象作为键名(null 除外),不接受其他类型的值作为键名。
(2)WeakMap 的键名所指向的对象不计入垃圾回收机制。
(3)没有keys()、values()、entries() 遍历操作。
(4)没有size 属性。
(5)不支持clear() 方法。
WeakMap 应用的典型场合就是 DOM 节点作为键名。下面是一个例子。

let myElement = document.getElementById('logo');
let myWeakmap = new WeakMap();

myWeakmap.set(myElement, {timesClicked: 0});

myElement.addEventListener('click', function() {
  let logoData = myWeakmap.get(myElement);
  logoData.timesClicked++;
}, false);

上面代码中,myElement是一个 DOM 节点,每当发生click事件,就更新一下状态。我们将这个状态作为键值放在 WeakMap 里,对应的键名就是myElement。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。

静态方法(from,of)

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

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

// ES5的写法
var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c']

// ES6的写法
let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']

//Set
let newArray=new Set(['a','b','c'])
let arr3=Array.from(newArray) //['a','b','c']

Array.to方法是用于将一组值,转换为数组。和Array()的用途相似,但是这个方法的主要目的,是弥补数组构造函数Array()的不足。因为参数个数的不同,会导致Array()的行为有差异。

Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]

Array.of() // []
Array.of(1) // [1]
Array.of(3,11,8) // [1, 2]

上面代码中,Array方法没有参数、一个参数、三个参数时,返回结果都不一样。只有当参数个数不少于 2 个时,Array()才会返回由参数组成的新数组。参数个数只有一个时,实际上是指定数组的长度。
Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。

数组的空值

数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。注意,空位不是undefined,一个位置的值等于undefined,依然是有值的。空位是没有任何值

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

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

// forEach方法
[,'a'].forEach((x,i) => console.log(i)); // 1

// filter方法
['a',,'b'].filter(x => true) // ['a','b']

// every方法
[,'a'].every(x => x==='a') // true

// reduce方法
[1,,2].reduce((x,y) => x+y) // 3

// some方法
[,'a'].some(x => x !== 'a') // false

// map方法
[,'a'].map(x => 1) // [,1]

// join方法
[,'a',undefined,null].join('#') // "#a##"

// toString方法
[,'a',undefined,null].toString() // ",a,,"

ES6中则是明确的将空处理成了undefined,由于空位的处理规则非常不统一,所以建议避免出现空位。
Array.from方法会将数组的空位,转为undefined,也就是说,这个方法不会忽略空位。

Array.from(['a',,'b'])
// [ "a", undefined, "b" ]

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

[...['a',,'b']]
// [ "a", undefined, "b" ]
copyWithin()会连空位一起拷贝。

[,'a','b',,].copyWithin(2,0) // [,"a",,"a"]
fill()会将空位视为正常的数组位置。

new Array(3).fill('a') // ["a","a","a"]
for...of循环也会遍历空位。

let arr = [, ,];
for (let i of arr) {
  console.log(1);
}
// 1
// 1

问题 :
1.不太了解静态方法和实例方法的区别
2.对promise概念有点模糊,async 的使用

相关文章

网友评论

      本文标题:ES6数组的扩展

      本文链接:https://www.haomeiwen.com/subject/fxpgqqtx.html