犀牛书——数组

把犀牛书中数组部分简单粗暴的敲了一遍,引入即可在控制台看到结果

let a = [1, 2, 3]
let b = [4, ...a, 6]
console.log(b) // [4,1,2,3,6]
// 可用于浅拷贝

//可展开字符串
let str = 'hello world'
let strArr = [...str]
console.log(strArr) // ["h", "e", "l", "l", "o", " ", "w", "o", "r", "l", "d"]
//去重
console.log([...new Set(strArr)]);// ["h", "e", "l", "o", " ", "w", "r", "d"]



//Array()构造函数
//不传参调用
let arr = new Array()
console.log(arr) // []
//传递一个参数
let arr1 = new Array(3)
console.log(arr1) // [empty × 3]
//传入两个或多个参数,或者传入一个非数值参数
let arr2 = new Array(1, 2, 3, 'a', 'b')
console.log(arr2) // [1, 2, 3, "a", "b"]



// 这种方法不能创建只有一个元素的数组,因为传入的参数会被当做数组的长度
// Array.of()方法可以
let arr3 = Array.of(1)
console.log(arr3) // [1]



// Array.from()方法可以将类数组对象转换为数组
let original = { 0: 'a', 1: 'b', 2: 'c', length: 3 }
let arr4 = Array.from(original)
console.log(arr4) // ["a", "b", "c"]

//读写数组
// 只有介于0和232-2之间的整数属性名才是索引
let o = []
o[1] = 'a'
o[-1] = 'b'
console.log(o["1"]);//a
console.log(o[1]);//a
console.log(o[-1]);//b  负数也可以作为索引



//稀疏数组
//稀疏数组是指数组的某些位置没有任何值
let arr5 = new Array(3)
arr5[100] = 'a'
console.log(arr5.length) // 101
console.log(arr5) // (101) [empty × 100, 'a']
console.log(arr5[0]) // undefined;
// 可以把稀疏数组当成包含undefined元素的非稀疏数组。




//数组长度
let arr6 = [1, 2, 3, 4, 5, 6, 7, 8]
console.log(arr6.length) // 8
arr6.length = 3
console.log(arr6) // [1, 2, 3]
arr6.length = 0
console.log(arr6) // []
arr6.length = 5
console.log(arr6) // [empty × 5]
// 设置小于当前长度的值,会截断数组
let arr7 = [1, 2, 3, 4, 5, 6, 7, 8]
arr7.length = 10
console.log(arr7) // [1, 2, 3, 4, 5, 6, 7, 8, empty × 2]
// 设置大于当前长度的值,会在数组末尾创建一个稀疏区域




//添加和删除元素
// pop push shift unshift
// pop()方法用于删除数组的最后一个元素,返回值是被删除的元素
let arr8 = [1, 2, 3, 4, 5, 6, 7, 8]
let last = arr8.pop()
console.log(last) // 8
console.log(arr8) // [1, 2, 3, 4, 5, 6, 7]
// push()方法用于在数组的末尾添加一个或多个元素,返回值是数组的新长度
let arr9 = [1, 2, 3, 4, 5, 6, 7, 8]
let newLength = arr9.push(9)
console.log(newLength) // 9
console.log(arr9) // [1, 2, 3, 4, 5, 6, 7, 8, 9]
// shift()方法用于删除数组的第一个元素,返回值是被删除的元素
let arr10 = [1, 2, 3, 4, 5, 6, 7, 8]
let first = arr10.shift()
console.log(first) // 1
console.log(arr10) // [2, 3, 4, 5, 6, 7, 8]
// unshift()方法用于在数组的开头添加一个或多个元素,返回值是数组的新长度
let arr11 = [1, 2, 3, 4, 5, 6, 7, 8]
let newLength1 = arr11.unshift(0)
console.log(newLength1) // 9
console.log(arr11) // [0, 1, 2, 3, 4, 5, 6, 7, 8]

//delete方法——不改变数组长度
// delete方法用于删除数组的某个元素,但是会留下一个空位
let arr12 = [1, 2, 3, 4, 5, 6, 7, 8]
delete arr12[0]
console.log(arr12) // [empty, 2, 3, 4, 5, 6, 7, 8]
// 删除数组元素类似于(但不完全等同于)给该元素赋undefined
// 值。注意,对数组元素使用delete操作符不会修改length属性,也
// 不会把高索引位的元素向下移动来填充被删除属性的空隙。从数组
// 中删除元素后,数组会变稀疏。


//迭代数组
// 到ES6为止,遍历一个数组(或任何可迭代对象)的最简单方式 就是使用for/of循环
let letters = [..."hello world"]
console.log(letters);
let string = ""
for (let letter of letters) {
  string += letter
}
console.log(string) // helloworld


//使用for of,并且想知道当前元素的索引,可以使用entries()方法配合结构赋值
let everyother = ""
for (let [index, letter] of letters.entries()) {
  if (index % 2 === 0) { // 偶数索引
    everyother += letter
  }
}
console.log(everyother) // hlowrd
//for of                                        不能感知稀疏数组
let arr131 = [1, 2, 3, 4, , , , 6, 7, 8]
let string11 = ""
for (let element of arr131) {
  string11 += element
}
console.log('forof: ', string11) //1234undefinedundefinedundefined678


//forEach
// forEach()方法接受一个函数作为参数,该函数会对数组的每个元素执行一次
let upCase = ""
letters.forEach((letter) => {
  upCase += letter.toUpperCase()
})
console.log(upCase) // HELLO WORLD

// 与for/of循环不同,forEach()                         能够感知稀疏数组,不会对没有的元素数组调用函数。
let arr13 = [1, 2, 3, 4, , , , 6, 7, 8]
let string1 = ""
arr13.forEach((element) => {
  string1 += element
})
console.log('forEach: ', string1) // 1234678



//传统的for循环
// 传统的for循环可以使用break和continue语句来控制循环的流程
let arr14 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
let string2 = ""
//开启计时
console.time('未优化计时器')
for (let i = 0; i < arr14.length; i++) {
  string2 += arr14[i]
}
//结束计时
console.timeEnd('未优化计时器')  //0.033935546875 ms
// console.log('未优化', string2)

//性能优化: 当数组较长 且 为稠密数组时:
console.time('优化计时器')
for (let i = 0, len = arr.length; i < len; i++) {
  string2 += arr[i]
}
console.timeEnd('优化计时器') //0.0029296875 ms
// console.log('优化', string2);
//这种只会在循环开始时获取一次数组长度的写法,比每次循环都获取数组长度的写法要快得多。




//多维数组
//js并不支持正真的多维数组,但是可以通过数组的元素来模拟多维数组
let table = new Array(10)
for (let i = 0; i < table.length; i++) {
  table[i] = new Array(10)
}
//初始化数组
for (let row = 0; row < table.length; row++) {
  for (let col = 0; col < table[row].length; col++) {
    table[row][col] = row * col
  }
}
//打印数组
console.log(table[5][7]);//35




//数组迭代器方法
//forEach (不能提前退出循环,不能跳过某些元素)
let data = [1, 2, , , , 3, 4, 5]
let sumOfSquares = 0
data.forEach((value) => { sumOfSquares += value })
console.log('forEach:', sumOfSquares) // 15

//递增每个元素
data.forEach((value, index, array) => { array[index] = value + 1 })
console.log(data) // [2, 3, 4, 5, 6]

//map
data = data.map(x => x * x)  //这个函数接收x作为参数,返回x*x的值
console.log('map: ', data) // [4, 9, 16, 25, 36]

//filter——可以跳过稀疏数组中缺失的元素
data = data.filter(x => x > 10) //这个函数接收x作为参数,返回x%2===0的值
console.log('filter: ', data) // [16, 25, 36]

//可以使用filter()方法来删除数组中的空元素
data = [1, 2, , , , 3, 4, 5]
data = data.filter(() => true)
console.log('filter: ', data) // [1, 2, 3, 4, 5]

//如果既想清理空隙 邮箱清理undefined和null,可以:
data = [1, 2, , undefined, null, 3, 4, 5]
data = data.filter(x => x != null && x != undefined)
console.log('filter: ', data) // [1, 2, 3, 4, 5]

// find() 和 findIndex()的区别
// find返回值,findIndex返回索引
//没有找到返回undefined,没有找到返回-1
data = [1, 2, 3, 4, 5]
console.log('find: ', data.find(x => x === 3)) // 3;
console.log('find: ', data.find(x => x === 8)) // undefined;
console.log('findIndex: ', data.findIndex(x => x === 3)) // 3;
console.log('findIndex: ', data.findIndex(x => x === 8)) // -1;

// every和some
// every:它在且只在断言函数对数组的所有元素都返回true时才返回true:
data = [1, 2, 3, 4, 5]
console.log('every: ', data.every(x => x < 10)) // true
console.log('every: ', data.every(x => x < 4)) // false

// some:它在且只在断言函数对数组的至少一个元素返回true时才返回true:
data = [1, 2, 3, 4, 5]
console.log('some: ', data.some(x => x < 4)) // true
console.log('some: ', data.some(x => x < 0)) // false

//every()和some()都会在它们知道要返回什么值时 停止迭代数组。

//如果是空数组,every()返回true,some()返回false。
data = []
console.log('some: ', data.some(x => x < 4)) // false
console.log('every: ', data.every(x => x < 4)) // true



// reduce和reduceRight
// reduce()和reduceRight()方法都是将数组中的元素归并为一个值。
// reduce()方法从数组的第一个元素开始,逐个遍历到最后。
data = [1, 2, 3, 4, 5]
console.log(data.reduce((a, b) => a + b, 0));//15
console.log(data.reduce((a, b) => a + b, 11));//26
console.log(data.reduce((a, b) => a * b, 1));//120
console.log(data.reduce((a, b) => a > b ? a : b));//5

// reduceRight()方法则从数组的最后一个元素开始,向前遍历到第一个元素。
//幂计算符合reduceRight()方法的一个很好的例子 2^(3^4)
data = [2, 3, 4]
let result = data.reduceRight((a, b) => Math.pow(b, a))
console.log(result) // 2.4178516392292583e+24

//flat——打平
//flat()方法会创建一个新数组,这个新数组是一个平坦的数组,也就是说,新数组中的元素
// 通常都是直接从原数组中提取的,而不是经过任何处理的。
//flat()方法接收一个可选的参数,表示要提取的嵌套数组的层数,默认值为1。
data = [1, 2, [3, 4, [5, 6]]]
console.log(data.flat()) // [1, 2, 3, 4, [5, 6]]
console.log(data.flat(2)) // [1, 2, 3, 4, 5, 6]

//flatMap——打平并映射
//flatMap()方法是map()方法和flat()方法的结合体。
//flatMap()方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。
//flatMap()方法对原数组的修改,flatMap()方法不会改变原数组。
data = ["the WORLD", "I want drink"]
console.log(data.flatMap(x => x.split(' '))) // ["the", "WORLD", "I", "want", "drink"]
// 调用a.flatMap(f)等同于(但效率远高于)a.map(f).flat():
console.log(data.map(x => x.split(' '))) // [["the", "WORLD"], ["I", "want", "drink"]]
console.log(data.map(x => x.split(' ')).flat()) // ["the", "WORLD", "I", "want", "drink"]

//concat
data = [1, 2, 3]
console.log(data.concat(4, 5, 6)) // [1, 2, 3, 4, 5, 6]
console.log(data.concat([4, 5], [6])) // [1, 2, 3, 4, 5, 6] 打平
console.log(data.concat([4, [5, 6]])) // [1, 2, 3, 4, [5, 6]] 不会打平嵌套的数组
console.log(data);// [1, 2, 3]原始数组不变

//通过push()、pop()、shift()和unshift()实现栈和队列操作
// push()和pop()方法可以把数组作为栈来操作。
// 这两个方法都会就地修改数组,而不会创建新数组。
// push与concat不同,push不会打数组参数
let stack = []
stack.push(1, 2)
console.log(stack) // [1, 2]
stack.pop()
console.log(stack) // [1]
stack.push([3, 4])
console.log(stack) // [1, [3, 4]]
stack.pop()
console.log(stack) // [1]
stack.pop()
console.log(stack) // []
//如果想打平传入的数组参数:
stack.push(...[3, 4])
console.log(stack) // [3, 4]

// 使用push()在数组末尾添加元素,使用shift()在数组开头删除元素来实现队列:
let queue = []
queue.push(1, 2)
console.log(queue) // [1, 2]
queue.shift()
console.log(queue) // [2]
queue.push(3, 4)
console.log(queue) // [2, 3, 4]
queue.shift()
console.log(queue) // [3, 4]
queue.shift()
console.log(queue) // [4]
queue.shift()
console.log(queue) // []

// 在给unshift()传多个参数时,这些参数会一次性插入数组。这意味着一次插入与多次插入之后的数组顺序不一样:
queue.unshift(1)
queue.unshift(2)
console.log(queue) // [2, 1]
queue = []
queue.unshift(1, 2)
console.log(queue) // [1, 2]



// slice()、splice()、fill()和copyWithin()
//slice
var a1 = [1, 2, 3, 4, 5];
console.log(a1.slice(0, 3)); // [1, 2, 3]
console.log(a1.slice(3)); // [4, 5]
console.log(a1.slice(1, -1)); // [2, 3, 4]
console.log(a1.slice(-3, -2)); // [3]
//参数为负数时,表示倒数第几个元素

//splice
// 第一个参数指定插入或删除操作的起点位置。第二个参数指定要从数组中删除(切割出来)的元素个数
// (注意,这里是两个方法的另一个不同之处。slice()的第二个参数是终点。而splice()的第二个参数是长度)。
let a2 = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(a2.splice(4)); // [5, 6, 7, 8]
console.log(a2); // [1, 2, 3, 4]
console.log(a2.splice(1, 2)); // [2, 3]
console.log(a2); // [1, 4]
//splice()方法还可以向数组中插入元素。第一个参数指定插入的位置,第二个参数指定插入的元素个数,后面的参数是要插入的元素。
let a3 = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(a3.splice(4, 0, 'a', 'b')); // []
console.log(a3); // [1, 2, 3, 4, "a", "b", 5, 6, 7, 8]

//fill
//fill()方法使用给定值,填充一个数组。
let a4 = new Array(3).fill(7);
console.log(a4); // [7, 7, 7]
//fill()方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
let a5 = [1, 2, 3, 4, 5, 6, 7, 8];
a5.fill(7, 2, 5);
console.log(a5); // [1, 2, 7, 7, 7, 6, 7, 8]
//如果省略第二个参数,fill()方法会从0号位开始向后填充。
//如果省略第三个参数,fill()方法会一直填充到数组结束。

//copyWithin
//copyWithin()方法在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),
// 然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
let a6 = [1, 2, 3, 4, 5];
a6.copyWithin(0, 3);
console.log(a6); // [4, 5, 3, 4, 5]
//上面代码表示将从3号位直到数组结束的成员(4和5),复制到从0号位开始的位置,结果覆盖了原来的1和2。
//copyWithin()方法的三个参数,都应该是数值,如果不是,会自动转为数值。
//copyWithin()方法的第一个参数表示将要复制到的目标位置(从0开始),
// 第二个参数表示从源数组的哪个位置开始复制(从0开始),
// 第三个参数表示到源数组的哪个位置结束(不包括该位置,如果省略,就一直复制到源数组的最后一个位置)。
//如果第一个参数是负数,表示倒数。
//如果第二个参数是负数,表示从倒数第几个开始复制。
//如果第三个参数是负数,表示复制到倒数第几个位置结束。
let a7 = [1, 2, 3, 4, 5];
a7.copyWithin(0, -2, -1);
console.log(a7); // [4, 2, 3, 4, 5]
//上面代码表示将从-2号位(也就是倒数第二个位置)开始复制,复制到-1号位(也就是倒数第一个位置)结束,
// 即只复制了最后一个元素4,然后覆盖了原来的1。





//数组索引与排序方法
// indexOf()和lastIndexOf()
//indexOf()方法返回给定元素在数组中的第一个索引,如果没有找到,则返回-1。
//lastIndexOf()方法返回给定元素在数组中的最后一个索引,如果没有找到,则返回-1。
let a8 = [1, 2, 3, 4, 5, 4, 3, 2, 1];
console.log(a8.indexOf(4)); // 3
console.log(a8.lastIndexOf(4)); // 5
console.log(a8.indexOf(4, 4)); // 5
console.log(a8.lastIndexOf(4, 4)); // 3
//indexOf()方法可以接受第二个参数,表示搜索的起始位置。
//lastIndexOf()方法也可以接受第二个参数,表示搜索的起始位置,但是它是从数组尾部开始向前搜索。

//字符串也有这个两个方法,在字符串中,第二个参数如果是负值会被当成0。


//includes()
//includes()方法返回一个布尔值,表示某个数组是否包含给定的值。
let a9 = [1, true, 3, NaN]
console.log(a9.includes(1)) // true
console.log(a9.includes(NaN)) // true
// indexOf()无法检测数组中的NaN值,但includes()可以:因为indexOf()内部使用的是严格相等运算符(===),
console.log(a9.indexOf(NaN)) // -1;


//sort
//sort()方法用于对数组成员进行排序,会直接修改当前数组。
//在不传参数的情况下,sort()方法按照默认顺序排序。
let a10 = ["d", "c", "b", "a"];
a10.sort();
console.log(a10); // ["a", "b", "c", "d"]
//对于数字,sort()方法默认按照从小到大的顺序排列。
let a11 = [4, 3, 2, 1];
console.log(a11.sort()); // [1, 2, 3, 4]
//可以传入一个比较函数,决定哪个值排在前面。
let a12 = [4, 3, 2, 1];
a12.sort(function (a, b) {
  return a - b;
});
console.log(a12); // [1, 2, 3, 4]
console.log(a12.sort((a, b) => a - b)); // [1, 2, 3, 4]
console.log(a12.sort((a, b) => b - a)); // [4, 3, 2, 1]

//如果不区分大小写,可以这样写。将所有字母都转为大写(或小写),
let a13 = ['Alice', 'bob', 'Tiff', 'Bruce', 'Alice'];
a13.sort(function (s1, s2) {
  let a = s1.toUpperCase();
  let b = s2.toUpperCase();
  if (a < b) {
    return -1;
  }
  if (a > b) {
    return 1;
  }
  return 0;
});
//区分大小写
console.log(a13); // ["Alice", "Alice", "Bruce", "Tiff", "bob"]


// reverse
//reverse()方法用于颠倒数组的顺序,会直接修改当前数组。
let a14 = [1, 2, 3, 4, 5];
console.log(a14.reverse()); // [5, 4, 3, 2, 1]





//数组到字符串的转换
// join()
// 可以指定一个可选的字符串参数,用于分隔结果字符串中的元素。如果不指定分隔符,则默认使用逗号
let a15 = [1, 2, 3, 4, 5];
console.log(a15.toString()); // "1,2,3,4,5"
console.log(a15.join('')); // "12345"
console.log(a15.join('-')); // "1-2-3-4-5"
// join()方法执行的是String.split()方法的反向操作,后者通过把字符串分割为多个片段来创建数组。
console.log(a15.toLocaleString()); // "1,2,3,4,5"





// 静态数组函数(包括前面的Array.of()和Array.from()),还有
// Array.isArray(),用于判断参数是否为数组。
console.log(Array.isArray([])); // true
console.log(Array.isArray(new Array())); // true
console.log(Array.isArray({}))// false





// 类数组对象
// 由于类数组对象不会继承Array.prototype,所以无法直接在它们上面调用数组方法。为此,可以使用Function.call()方法
let bb = { "0": "a", "1": "b", "2": "c", length: 3 };
Array.prototype.join.call(bb, '-'); // 'a-b-c'
Array.prototype.slice.call(bb, 0); // ['a', 'b', 'c']
Array.prototype.map.call(bb, function (x) {
  return x.toUpperCase();
}); // ['A', 'B', 'C']
Array.prototype.slice.call(bb, 0); // ['a', 'b', 'c']//真正的数组副本
Array.from(bb); // ['a', 'b', 'c']//更容易的数组复制




// 作为数组的字符串
let s = 'hello';
console.log(s.charAt(0)); // "h"
console.log(s[1]); // "e"
//着我们可以对字符串使用泛型的字符串方法。比如:
console.log(Array.prototype.join.call("javascript", ' ')) // "j a v a s c r i p t"
// 字符串是不可修改的值,因此在把它们当成数组来使用时,它们是只读数组。像push()、sort()、reverse()和splice()这些就地修改数组的数组方法,
// 对字符串都不起作用。但尝试用数组方法修改字符串并不会导致错误,只会静默失败。
// console.log(s.reverse()) //TypeError: s.reverse is not a function
console.log(Array.from(s).reverse().join('')) // "olleh"


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值