JavaScript 数组、字符串、Map、Set 方法整理
在线阅读
https://www.kancloud.cn/chenmk/web-knowledges/1080519
数组
- isArray():Array.isArray(value) 用于检测变量是否为数组类型
- toString():把数组转换为字符串,并返回结果,每一项以逗号分隔
- push() & pop():push() 方法用于数组末尾添加项,pop() 方法弹出数组末尾项并返回该项
- shift() & unshift():移除数组中的第一个项并返回该项 / 数组最前端添加项
- reverse():反转数组顺序,会改变原数组并返回反转后的数组
- sort():排序数组,默认为升序;可接受一个自定义的比较函数作为参数
- concat():基于当前数组的所有项创建一个新数组,该方法会先创建一个当前数组的副本,然后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组
- slice():基于当前数组中的一或多个项创建一个新数组
- splice():删除数组中的项或往数组中插入项
- indexOf() & lastIndexOf():接收两个参数,要查找的项和可选的表示查找起点位置的索引
- 迭代方法:迭代方法都不会修改原数组。每个方法都接收两个参数:要在每一项上运行的函数和 (可选的)运行该函数的作用域对象——影响 this 的值。传入这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象本身。
- every():对数组中的每一项运行给定函数,如果该函数对每一项都返回 true,则返回 true
- some():对数组中的每一项运行给定函数,如果该函数对任一项返回 true,则返回 true
- filter():对数组中的每一项运行给定函数,返回该函数会返回 true 的项组成的数组
- forEach():对数组中的每一项运行给定函数。这个方法没有返回值
- map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组
- reduce & reduceRight():归并方法,迭代数组的所有项,然后得到一个最终返回的值
- join(seperator):把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。seperator 是可选参数,默认使用','分隔
下面通过一些示例来加深对一些稍微复杂的函数的理解:
1.sort()
values.sort(compare)
,比较函数(compare)接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数
function compare (value1, value2) {
if(value1 < value2){
return -1
} else if (value1 > value2) {
return 1
} else {
return 0
}
}
对于数值类型或者其 valueOf() 方法会返回数值类型的对象类型,可以使用一个更简单的比较函数。这个函数只要用第二个值减第一个值即可
function compare (value1, value2) { return value2 - value1 }
由于比较函数通过返回一个小于零、等于零或大于零的值来影响排序结果,因此减法操作就可以适当地处理所有这些情况
2.concat() 与 slice() 与 splice()
在没有给 concat()
方法传递参数的情况下,它只是复制当前数组并返回副本。如果传递给 concat() 方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。如果传递的值不是数组,这些值就会被简单地添加到结果数组的末尾。
var colors = ["red", "green", "blue"]
var colors2 = colors.concat("yellow", ["black", "brown"])
alert(colors) // red,green,blue
alert(colors2) // red,green,blue,yellow,black,brown
slice()
方法可以接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的情况下,slice() 方法返回从该参数指定位置开始到当前数组末尾的所有项。如果有两个参数,该方法返回起始和结束位置之间的项,但不包括结束位置的项。注意,slice() 方法不会影响原始数组。
var colors = ["red", "green", "blue", "yellow", "purple"]
var colors2 = colors.slice(1)
var colors3 = colors.slice(1,4)
alert(colors2) // green,blue,yellow,purple
alert(colors3) // green,blue,yellow
splice()
:
- 删除:可以删除任意数量的项,只需指定 2 个参数:要删除的第一项的位置和要删除的项数。例如,
splice(0,2)
会删除数组中的前两项。 - 插入:可以向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。如果要插入多个项,可以再传入第四、第五,以至任意多个项。例如
splice(2,0,"red","green")
会从当前数组的位置 2 开始插入字符串"red"和"green"。 - 替换:可以向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定 3 个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数不必与删除的项数相等。例如,
splice (2,1,"red","green")
会删除当前数组位置 2 的项,然后再从位置 2 开始插入字符串 "red" 和 "green"。(先删除再插入) - 返回值:splice() 方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(如果没有删除任何项,则返回一个空数组)
3.迭代方法的使用
var numbers = [1,2,3,4,5,4,3,2,1]
var filterResult = numbers.filter(function (item, index, array) {
return (item > 2)
})
alert(filterResult) // [3,4,5,4,3]
来看一道常见的面试题:['1', '2', '3'].map(parseInt)
答案是多少
答案 :[1, NaN, NaN]
解析:parseInt 接收两个参数 (sting, radix),其中 radix 代表进制。省略 radix 或 radix = 0,则数字将以十进制解析
因此,map 遍历 ['1', '2', '3'],相应 parseInt 接收参数如下
parseInt('1', 0) // 1
parseInt('2', 1) // NaN
parseInt('3', 2) // NaN
通过下面一些示例你可以更清晰地理解 parseInt() 方法:
parseInt("10") //返回 10
parseInt("19",10) //返回 19 (10+9)
parseInt("11",2) //返回 3 (2+1)
parseInt("17",8) //返回 15 (8+7)
parseInt("1f",16) //返回 31 (16+15)
4.归并方法的使用
reduce(function (prev, curr, index, arr) {}, optional)
- 参数依次为:前一个值,当前值,项的索引,数组对象。
- 函数返回的任何值都会作为第一个参数自动传给下一项,首次执行时 prev 就是数组第一个元素,curr 是数组的第二个元素。
- 还可以接受一个参数作为归并的初始值,如果传入了这个参数,首次执行的 prev 就是这个值,curr 是数组的第一个元素
通过这个常见面试题可以加深我们对 reduce 的理解:用数组的 reduce 实现 map 方法
// map(function (item, index, arr) {})
// 对数组的每个元素执行相应的操作,返回一个新数组,其由由操作后的元素组成;不会修改原数组
Array.prototype.map = function (callback) {
let arr = this // this->调用该方法的数组
return arr.reduce((prev, curr, index, arr ) => {
prev.push(callback(curr, index, arr)) // 数组中每一项执行传入的回调函数
return prev
}, []) // 最后返回的是prev,传入[]则第一轮prev = [], curr= 数组第1个元素
}
let m = [1, 2, 3, 4, 5].map((item, index, arr) => {
return item * item
})
console.log(m) // [1, 4, 9, 16, 25]
5.检测数组的方式
const myArray = [1, 3, 5, 7, 9]
const myValue = 1
// 1.使用 instanceof, 判断该对象的原型链上是否有 Array.prototype
console.log(myArray instanceof Array) // true
console.log(myValue instanceof Array) // false
// 2.使用 constructor, 注意实例本身是没有 constructor 属性的,
// 会从原型链上读取到 Array.prototype (如果是数组)
console.log(myArray.constructor === Array) // true
console.log(myValue.constructor === Array) // false
// 3.使用 Object.prototype.toString.call(arr) === '[object Array]'
// 即改变 this 指向, 调用 Object 原型上的 toString 方法
function myIsArray(arr) {
return Object.prototype.toString.call(arr)
}
let obj = {}
let fn = function() {}
console.log(myIsArray(myArray)) // [object Array]
console.log(myIsArray(myValue)) // [object Number]
console.log(myIsArray(obj)) // [object Object]
console.log(myIsArray(fn)) // [object Function]
// 4.ES5 定义了 Array.isArray
console.log(Array.isArray(myArray)) // true
ES6新增
- Array.from():该方法用于将两类对象转换为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)对象(包括 Set 和 Map)
// NodeList 对象
let ps = document.querySelectorAll('p')
Array.from(ps).forEach(function (p) { // 只有转换为真正的数组才能使用数组方法
console.log(p)
})
// arguments对象
function foo () {
var args = Array.from(arguments)
// ...
}
- Array.of():该方法用于将一组值转换为数组,总是返回参数值组成的数组,如果没有参数则返回一个空数组
// Array.of 弥补构造函数因参数个数不同而造成的的行为差异
Array.of(3, 11, 8) // [3, 11, 8]
Array.of(3) // [3]
Array.of(3).length // 1
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
- copyWithin(target, start, end):在当前数组内部将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。这个方法会修改当前数组
- target(必选):从该位置开始替换数据
- start(可选):从该位置开始读取数据,默认为 0;如果为负数,表示倒数
- end(可选):到该位置前停止读取数据,默认等于数组长度
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
- find() 和 findIndex():find 方法用于找出第一个符合条件的数组成员,参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为 true 的成员,然后返回该成员,如果没有符合条件的成员,则返回 undefined
- findIndex() 与 find() 类似,返回的是符合条件的成员的位置,如果都不符合,返回 -1
// 找出数组中第一个大于 9 的成员
// 回调函数可接受 3 个参数:当前的值,当前的位置,原数组
[1, 5, 10, 15].find(function (value, index, arr) {
return value > 9
}) // 10
[1, 5, 10, 15].findIndex(function (value, index, arr) {
return value > 9
}) // 2
// 这两个方法可以发现 NaN,弥补了数组的 IndexOf 方法的不足
[NaN].indexOf(NaN) // -1
[NaN].findIndex(y => Object.is(NaN, y)) // 0
- fill():fill 方法使用给定值填充一个数组
['a', 'b', 'c'].fill(7) // 7 7 7
// 用于初始化空数组
new Array(3).fill(7) // 7 7 7
// 还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
- includes():返回一个布尔值,表示某个数组是否包含给定的值
// 第二个参数表示搜索的起始位置,默认为0;如果为负数表示倒数的位置;如果大于数组长度,则会重置为0
[1, 2, 3].includes(3, 3) // false
[1, 2, 3].includes(3, -1) // true
字符串
- concat():拼接字符串
- slice(start, end) & substr(start, length) & substring(start, stop):功能类似,记 substr 和 substring 即可,根据是按长度来截取还是按指定下标来进行选择;不指定第二个参数就是截取从 start 位置到末尾的所有字符串
- indexOf(value ,index) & lastIndexOf():从一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回 -1)区别是从前还是从后开始
- trim():这个方法会创建一个字符串的副本,删除前置及后缀的所有空格,然后返回结果;有些浏览器还支持非标准的 trimLeft() 和 trimRgiht() 方法
- toLowerCase() & toLocaleLowerCase() & toUpperCase() & toLocaleUpperCase():大小写转换,Lcalel 是针对特定地区的实现。一般来说,在不知道自己的代码将在哪种语言环境中运行的情况下,还是使用针对地区的方法更稳妥一些
- 返回一个转换后的字符串(不影响原字符串),toLowerCase() 是转换为小写,toUpperCase()是转换为大写
- split(separator, howmany):基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中
- match():根据是否全局搜索,返回值会不同
- search():返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回 -1。而且,search() 方法始终是从字符串开头向后查找模式。
- replace():用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
较难理解的主要是最后三个模式匹配方法,在左侧目录的“正则表达式”部分中有介绍,这里不再赘述。
ES6 新增
- codePointAt():对于 2 字节存储的常规字符而言其返回结果与 charCodeAt() 相同,区别是其该方法能正确处理 4 字节存储的字符,返回这个字符的码点
- fromCodePoint():可识别大于 0xFFFF 的字符,弥补了 String.fromCharCode 方法的不足,作用上与 codePointAt 正好相反
- at():能正确返回码点大于 oxFFFF 的字符的位置
- 遍历器接口:ES6 为字符串添加了遍历器接口,使得字符串可以由 for...of 循环遍历
for (let codePoint of 'foo') {
console.log(codePoint)
}
// "f"
// "o"
// "o"
// 用 1-9a-zA-Z 生成 5 位随机数
let arr = []
for (let i = 1; i <= 9; i++) {
arr.push(i)
}
for (let i = 97; i <= 122; i++) { // a 的 ASCII 码为 97,z 为 122 -> 'a'.codePointAt(0)
arr.push(String.fromCodePoint(i)) // 字符转换成码点 + 1 后再转换为字符
}
for (let i = 65; i <= 90; i++) { // A 的 ASCII 码为 65,Z 为90
arr.push(String.fromCodePoint(i))
}
let randomString = ''
for (let i = 0; i < 5; i++) {
let randomIndex = Math.floor(arr.length * Math.random())
randomString += arr[randomIndex]
}
console.log(randomString)
- includes():返回布尔值,表示是否找到了参数字符串
- startsWith():返回布尔值,表示参数字符串是否在源字符串的头部
- endsWith():返回布尔值,表示参数字符串是否在源字符串的尾部
var s = 'Hello world'
// 都支持第二个参数,表示开始搜索的位置;endsWith 的行为与其他两个不同,
// 它针对前 n 个字符,而其他两个方法针对从第 n 个位置到字符串结束之间的字符
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
- repeat():返回一个新字符串,表示将原字符串重复 n 次。
'x'.repeat(3) // "xxx"
- padStart() & padEnd():字符串补全长度,padStart 用于头部补全,padEnd 用于尾部补全;如果某个字符串不够指定长度,会在头部或尾部补全
'x'.padStart(5, 'ab') // 'ababx'
'x'.padEnd(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
'x'.padEnd(4, 'ab') // 'xaba
// 如果省略第二个参数,则用空格来补全
'x'.padEnd(4) // 'x '
// 可以这么用
// 为数值补全位数
'12'.padStart(10, '0') // "0000000012"
// 提示字符串格式
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
- 模板字符串
- 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出中
- 在模板字符串中嵌入变量,需要将变量名写在
${}
中 ${fn()}
大括号内可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性,可以调用函数
Map
Map方法 | 描述 |
---|---|
Map() | 构造函数 |
set(key, value) | 设置 key 所对应的键值,然后返回整个 Map 结构。如果 key 已经有值,则键值被更新,否则新生成该键 |
get(key) | 读取 key 对应的键值,若未找到 key 则返回 undefined |
has(key) | 返回一个布尔值,表示某个键是否存在于 Map 结构中 |
delete(key) | 删除某个键,返回 true;删除失败返回 false |
clear() | 清除所有成员,没有返回值 |
keys() | 返回键名的遍历器 |
values() | 返回键值的遍历器 |
entries() | 返回键值对的遍历器 |
forEach() | 使用回调函数遍历每个成员,用法:map.forEach(function (value, key, map){ }) |
Set
Set 内部判断两个值是否相同使用的算法为“Same-value equality”,它类似于精确相等运算符(===),主要的区别是 NaN 等于自身,而精确相等运算符认为 NaN 不等于自身。
Set方法 | 描述 |
---|---|
Set() | 构造函数,可以接受一个数组,或者具有 iterable 接口的其他数据结构作为参数 |
add(value) | 添加某个值,返回 Set 结构本身 |
delete(value) | 删除某个值,返回布尔值,表示是否删除成功 |
has(value) | 返回布尔值,表示参数是否为 Set 的成员 |
clear() | 清除所有成员,没有返回值 |
keys() | 返回键名的遍历器,用法:for (let item of set.keys()) |
values() | 返回键值的遍历器 |
entries() | 返回键值对的遍历器 |
forEach() | 使用回调函数遍历每个成员 |
用途:
1.去除数组的重复元素
function dedupe (array){
return Array.from(new Set(array))
}
console.log(dedupe([1, 1, 2, 3])) // [1, 2, 3]
2.扩展运算符(...)内部使用 for...of 循环,所以也可以用于 Set 结构,扩展运算符和 Set结构相结合也可以去除数组的重复成员
let arr = [3, 5, 2, 2, 5, 5]
let unique = [...new Set(arr)]
console.log(unique) // [3, 5, 2]
3.利用 Set 实现并集(Union)、交集(Intersect)、差集(Difference)
let a = new Set([1, 2, 3])
let b = new Set([4, 3, 2])
// 并集
let union = new Set([...a, ...b])
console.log(union) // Set {1, 2, 3, 4}
// 交集
let intersect = new Set([...a].filter(x => b.has(x)))
console.log(intersect); // Set {2, 3}
// 差集
let difference = new Set([...a].filter(x => !b.has(x)))
console.log(difference) // Set {1}