Array
创建数组
- 构造函数:new Array()
- 字面量:[]
- Array.from() — 将类数组结构转换为数组实例 Map Set ,可以进行浅复制,接受第二个参数为映射函数,第三个参数为指定映射函数的this ```javascript // 字符串会被拆分为单字符数组 console.log(Array.from(“Matt”)); // [“M”, “a”, “t”, “t”] // 可以使用 from()将集合和映射转换为一个新数组 const m = new Map().set(1, 2) .set(3, 4); const s = new Set().add(1) .add(2) .add(3) .add(4); console.log(Array.from(m)); // [[1, 2], [3, 4]] console.log(Array.from(s)); // [1, 2, 3, 4]
const a1 = [1, 2, 3, 4]; const a2 = Array.from(a1, x => x**2); // 第二个参数可接受一个像map一样的函数,简化操作
// 第三个参数是指定映射函数的this值,但是重写的 this 值在箭头函数中不适用 const a3 = Array.from(a1, function(x) {return x**this.exponent}, {exponent: 2}); console.log(a2); // [1, 4, 9, 16] console.log(a3); // [1, 4, 9, 16]
- Array.of() --- 用于将一组参数转换为数组实例,可以将 arguments 参数转换为 数组, 替代在 ES6之前常用的 Array.prototype. slice.call(arguments) ;
- ... 扩展运算符,也可以执行上面的部分操作。
<a name="C9X72"></a>
#### 空位数组
> 不建议使用--由于对每一个api的行为不一致和存在性能隐患,因此实践中要避免使用数组空位。如果确实需要 空位,则可以显式地用 undefined 值代替。
```javascript
const options = [,,,,,]; // 创建包含 5 个元素的数组
// ES6的方法,会认为的存在的元素,值为undefined
// ES6 之前的方法则会忽略这个空位,但具体的行为也会因方法而异:
const options = [1,,,,5];
// map()会跳过空位置
console.log(options.map(() => 6)); // [6, undefined, undefined, undefined, 6]
// join()视空位置为空字符串
console.log(options.join('-')); // "1----5"
数组索引
- 数组 length 属性的独特之处在于,它不是只读的 ,可以直接截取数组的长度。
使用 length 属性可以方便地向数组末尾添加元素
let colors = ["red", "blue", "green"]; // 创建一个包含 3 个字符串的数组
colors[colors.length] = "black"; // 添加一种颜色(位置 3)
colors[colors.length] = "brown"; // 再添加一种颜色(位置 4)
-
检测数组
Array.isArray()
数组方法
- 迭代器方法: keys()、values()和 entries() —- 不会改变原数组
```javascript
const aKeys = Array.from(a.keys()); // 取所有的key
const aValues = Array.from(a.values()); // 取所有的value
const aEntries = Array.from(a.entries()); // 返回key/value的数组格式 console.log(aKeys); // [0, 1, 2, 3] console.log(aValues); // [“foo”, “bar”, “baz”, “qux”] console.log(aEntries); // [[0, “foo”], [1, “bar”], [2, “baz”], [3, “qux”]]
// 用for of进行迭代 for (const [idx, element] of a.entries()) { alert(idx); alert(element); }
- 复制和填充方法:-- 两个方法都会改变原数组
1. 批量复制方法 copyWithin()
1. 填充数组方法 fill()
```javascript
// 两个方法都会静默忽略超出数组边界、零长度及方向相反的索引范围
// 用 7 填充索引大于等于 1 且小于 3 的元素
const zeroes = [0, 0, 0, 0, 0];
zeroes.fill(7, 1, 3);
console.log(zeroes); // [0, 7, 7, 0, 0];
zeroes.fill(0); // 重置
// 插入到索引 4 开始的位置
let ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
ints.copyWithin(4, 0, 3);
alert(ints); // [0, 1, 2, 3, 0, 1, 2, 7, 8, 9]
reset();
转换方法 toLocaleString()、toString()和 valueOf()方法 — 不会改变原数组
// alert()期待字符串,所以会在后台调用数组的 toString()方法;
// 如果数组中某一项是 null 或 undefined,则在 join()、toLocaleString()、toString()和 valueOf()返回的结果中会以空字符串表示
栈方法:— 两个方法都会改变原数组
- push() —- push后返回数组长度
- pop()方法 —- pop后返回当前删除的那一项
- 队列方法: — 都是会改变原数组
- shift() 出队和 push()入队 shift返回删除的那一项
- unshift() shift() 和 push pop类似, unshift 返回当前的数组长度
- 排序方法: — (两个方法都会改变原数组)
- reverse() reverse反转数组中的内容
- sort() —- sort 对数组中的内容排序,倒序正序都可以,具体比较方法: 如果第一个参数应该排在第二个参数前面,就返回负值;如果两个参数相 等,就返回 0;如果第一个参数应该排在第二个参数后面,就返回正值。
- 操作方法:
- concat() —- 合并数组 [Symbol.isConcatSpreadable] 置为false,可以强制不打平数组 — 不会改变原数组
- slice() —- 截取数组 —- 不会改变原数组
- splice() —- 删除,插入,替换数组的某一项 — 会改变原数组,返回值为删除的那一项
colors.splice(1, 0, "yellow", "orange"); // 在位置 1 插入两个元素
- 搜索和位置方法
- 3 个严格相等的搜索方法:indexOf()、lastIndexOf()和 includes()。
- 断言函数: find()和 findIndex()方法 ,找到匹配项之后,这两个参数都不会 继续搜索
// 接受三个参数,元素、索引和数组
const people = [
{
name: "Matt",
age: 27
},
{
name: "Nicholas",
age: 29
}
];
alert(people.find((element, index, array) => element.age < 28));
// {name: "Matt", age: 27}
alert(people.findIndex((element, index, array) => element.age < 28));
// 0
- 迭代方法 —- 都不改变原数组
- every():对数组每一项都运行传入的函数,如果对每一项函数都返回 true,则这个方法返回 true。
- filter():对数组每一项都运行传入的函数,函数返回 true 的项会组成数组之后返回
- forEach():对数组每一项都运行传入的函数,没有返回值。
- map():对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
- map():对数组每一项都运行传入的函数,返回由每次函数调用的结果构成的数组。
- 归并方法 —- 都不改变原数组
- reduce( 上一个归并值、当前项、当前项的索引和数 组本身 )
- reduceRight( 上一个归并值、当前项、当前项的索引和数 组本身 ) —- 倒序
会改变原数组的方法
copyWithin() fill() push() pop() shift() unshift() reverse() sort() splice()
Map
基本api
创建map使用构造函数:new Map()
- set()方法再添加键/值对
- 用 get()和 has()进行查询
- 通过 size 属性获取映射中的键/值对的数量
- 使用 delete()和 clear()删除值 ```javascript // 使用嵌套数组初始化映射 const m1 = new Map([ [“key1”, “val1”], [“key2”, “val2”], [“key3”, “val3”] ]); alert(m1.size); // 3
// 映射期待的键/值对,无论是否提供 const m3 = new Map([[]]); alert(m3.has(undefined)); // true alert(m3.get(undefined)); // undefined
m.set(“firstName”, “Matt”) .set(“lastName”, “Frisbie”); alert(m.has(“firstName”)); // true alert(m.get(“firstName”)); // Matt alert(m.size); // 2 m.delete(“firstName”); // 只删除这一个键/值对 m.clear(); // 清除这个映射实例中的所有键/值对
<a name="NqRQb"></a>
#### SameValueZero
> object.is的相等算法。所以在0 和 -0 的判断上是false, 在NaN的判断上是true
> SameValueZero 检查实例不会冲突
```javascript
const m = new Map();
const a = 0/"", // NaN
b = 0/"", // NaN
pz = +0,
nz = -0;
alert(a === b); // false
alert(pz === nz); // true
m.set(a, "foo");
m.set(pz, "bar");
alert(m.get(b)); // foo
alert(m.get(nz)); // bar
迭代
使用 entries 或 …
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
console.log([...m]); // [[key1,val1],[key2,val2],[key3,val3]]
forEach
const m = new Map([
["key1", "val1"],
["key2", "val2"],
["key3", "val3"]
]);
m.forEach((val, key) => alert(`${key} -> ${val}`));
// key1 -> val1
// key2 -> val2
// key3 -> val3
与object相比为什么要使用Map
- 创建一个Set new Set();
- 使用 add()增加值
- 使用 has()查询
- 通过 size 取得元素数量
使用 delete() 和 clear()删除元素
const s = new Set();
alert(s.has("Matt")); // false
alert(s.size); // 0
s.add("Matt")
.add("Frisbie");
alert(s.has("Matt")); // true
alert(s.size); // 2
s.delete("Matt");
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // true
alert(s.size); // 1
s.clear(); // 销毁集合实例中的所有值
alert(s.has("Matt")); // false
alert(s.has("Frisbie")); // false
alert(s.size); // 0
同样是用 SameValueZero 判断相等
add()和 delete()操作是幂等的。幂等:相同的输入,输出只有一次
迭代
… 或 for of 遍历 ```javascript // 直接使用… const s = new Set([“val1”, “val2”, “val3”]); console.log([…s]); // [“val1”, “val2”, “val3”]
// 适应for of key value的值是一样的 const s = new Set([“val1”, “val2”, “val3”]); for (let pair of s.entries()) { console.log(pair); } // [“val1”, “val1”] // [“val2”, “val2”] // [“val3”, “val3”]
- foreach
```javascript
const s = new Set(["val1", "val2", "val3"]);
s.forEach((val, dupVal) => alert(`${val} -> ${dupVal}`));
// val1 -> val1
// val2 -> val2
// val3 -> val3
Set的一些常用扩展操作
class XSet extends Set {
union(...sets) {
return XSet.union(this, ...sets);
}
intersection(...sets) {
return XSet.intersection(this, ...sets);
}
difference(set) {
return XSet.difference(this, set);
}
symmetricDifference(set) {
return XSet.symmetricDifference(this, set);
}
cartesianProduct(set) {
return XSet.cartesianProduct(this, set);
}
powerSet() {
return XSet.powerSet(this);
}
// 返回两个或更多集合的并集
static union(a, ...bSets) {
const unionSet = new XSet(a);
for (const b of bSets) {
for (const bValue of b) {
unionSet.add(bValue);
}
}
return unionSet;
}
// 返回两个或更多集合的交集
static intersection(a, ...bSets) {
const intersectionSet = new XSet(a);
for (const aValue of intersectionSet) {
for (const b of bSets) {
if (!b.has(aValue)) {
intersectionSet.delete(aValue);
}
}
}
return intersectionSet;
}
// 返回两个集合的差集
static difference(a, b) {
const differenceSet = new XSet(a);
for (const bValue of b) {
if (a.has(bValue)) {
differenceSet.delete(bValue);
}
}
return differenceSet;
}
// 返回两个集合的对称差集
static symmetricDifference(a, b) {
// 按照定义,对称差集可以表达为
return a.union(b).difference(a.intersection(b));
}
// 返回两个集合(数组对形式)的笛卡儿积
// 必须返回数组集合,因为笛卡儿积可能包含相同值的对
static cartesianProduct(a, b) {
const cartesianProductSet = new XSet();
for (const aValue of a) {
for (const bValue of b) {
cartesianProductSet.add([aValue, bValue]);
}
}
return cartesianProductSet;
}
// 返回一个集合的幂集
static powerSet(a) {
const powerSet = new XSet().add(new XSet());
for (const aValue of a) {
for (const set of new XSet(powerSet)) {
powerSet.add(new XSet(set).add(aValue));
}
}
return powerSet;
}
}