最近一直在看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 的使用
网友评论