在 JavaScript 中,您可以使用数组构造函数或使用链表文字 [] 创建链表,后者是首选方法。 Array对象继承自Object.prototype,在链表上执行typeof运算符返回对象而不是数组。 然而,[]instanceofArray 也返回true。 换句话说,类字段对象的实现更加复杂,例如字符串对象和参数对象。 Arguments对象不是Array的实例,但是有length属性,可以通过索引获取值,因此可以像字段一样进行循环。
在本文中,我将介绍一些现场原型技术并探索这种方法的用法。
1 个循环:.fofEach
这是JavaScript中最简单的方式,但是IE7和IE8不支持这种方式。
.forEach 有一个回调函数作为参数。 遍历链表时,会对每个链表元素进行调用。 回调函数接受三个参数:
此外,可以传递可选的第二个参数作为每个函数调用的上下文 (this)。
['_', 't', 'a', 'n', 'i', 'f', ']'].forEach(函数 (值, 索引, 数组) {
this.push(String.fromCharCode(value.charCodeAt() + index + 2))
}, 输出 = [])
出去。 加入('')
//
.join 后面会提到,本例中用于连接链表中的不同元素,效果类似 out[0] + '' + out[1] + '' + out[2] + ' ' + 输出[n]。
.forEach 循环不能被中断,抛出异常也是不明智的。 幸运的是,我们还有另一种方法来中断操作。
2 判断:.some 和 .every
如果您在.NET中使用过枚举,这两个方法类似于.Any(x => x.IsAwesome)和.All(x => x.IsAwesome)。
与 .forEach 的参数类似,它需要一个包含三个参数的回调函数:值、索引和数组,并且还有一个可选的第二个上下文参数。 MDN 对 .some 的描述如下:
some会对链表中的每个元素执行回调函数,直到回调函数返回true。 如果找到目标元素,some 立即返回 true,否则 some 返回 false。 回调函数只对已经赋值的链表索引执行; 对于已删除或未赋值的元素,不会调用它。
最大值 = -无穷大
满意 = [10, 12, 10, 8, 5, 23].some(函数 (值, 索引, 数组) {
如果(值 > 最大值)最大值 = 值
返回值 < 10
})
安慰。 日志(最大)
//
使满意
//
注意,当回调函数的值<10时,函数循环被中断。 .every 的工作方式与 .some 类似,但回调函数返回 false 而不是 true。
3 区分.join和.concat
.join 和 .concat 经常被混淆。 .join(separator) 将链表中以separator为分隔符的元素连接起来,并返回一个字符串。 如果未提供分隔符,则将使用默认的 , 。 .concat 将创建一个新的链表作为源链表的浅表副本。
浅拷贝意味着新列表保留与原始列表相同的对象引用,这通常是一件好事。 例如:
var a = { foo: 'bar' }
var b = [1, 2, 3, a]
var c = b.concat()
控制台.log(b === c)
//
b[3] === a && c[3] === a
//
4 栈和队列的实现:.pop、.push、.shift 和 .unshift
大家都知道 .push 可以向链表末尾添加元素,但是你知道吗,你可以使用 [].push('a', 'b', 'c', 'd', 'z') 来一次添加多个元素? ?
.pop 方法与 .push 方法相反,它返回被删除的列表末尾的元素。 如果链表为空,则返回 void 0(未定义)。 使用 .pop 和 .push 创建 LIFO(后进先出)堆栈。
(上下滑动查看代码)
函数堆栈(){
这个._stack = []
Stack.prototype.next = function () {
返回 this._stack。 流行音乐()
stack.prototype.add = function () {
返回 this._stack.push.apply(this._stack, 参数)
堆栈 = 新堆栈()
堆。 添加(1,2,3)
堆。 下一个()
//
相反,.shift 和 .unshift 可用于创建 FIFO(先进先出)队列。
函数队列(){
这个._queue = []
Queue.prototype.next = function () {
返回 this._queue.shift()
Queue.prototype.add = function () {
返回 this._queue.unshift.apply(this._queue, 参数)
队列 = 新队列()
队列.add(1,2,3)
队列.next()
//
使用 .shift(或 .pop)是循环一组数组元素的简单方法,同时在此过程中耗尽数组。
列表 = [1,2,3,4,5,6,7,8,9,10]
while (item = list.shift()) {
控制台.log(项目)
列表
//
5 模型映射:.map
.map为链表中的每个元素提供了一个bounce方法,并返回一个由调用结果组成的新链表。 回调函数只对已经赋值的链表索引执行; 对于已删除或未赋值的元素,不会调用它。
Array.prototype.map 与前面提到的 .forEach、.some 和 .every 的参数格式相同: .map(fn(value, index, array), thisArgument)
值= [void 0, null, false, '']
值[7] = 无效 0
结果=值。 映射(函数(值,索引,数组){
控制台.log(值)
返回值
})
//
undefined × 3 很好地解释了 .map 不会在已删除或未指定的元素上调用,但仍会包含在结果字段中。 .map 在创建或更改链接列表时特别有用,请参见下面的示例:
// 铸造
[1, '2', '30', '9'].map(函数(值) {
返回parseInt(值,10)
})
// 1, 2, 30, 9
[97, 119, 101, 115, 111, 109, 101].map(String.fromCharCode).join('')
//
// 一个常用的模式是映射到新对象
items.map(函数(项目){
返回 {
id: 项目.id,
名称:计算名称(项目)
})
6 查询:.filter
filter 对每个链表元素执行一次回调函数javascript 引用函数,并返回一个由回调函数返回 true 的元素组成的新链表。 仅对已赋值的链表项才会调用回调函数。
常见用法:.filter(fn(value, index, array), thisArgument),类似于C#中的LINQ表达式和SQL中的where语句。 .filter 仅返回在回调函数中返回 true 值的元素。
[无效 0、空、假、''、1]。 过滤器(函数(值){
返回值
})
//
[无效 0、空、假、''、1]。 过滤器(函数(值){
返回!值
})
//
7 排序:.sort(compareFunction)
如果未提供compareFunction,则元素将转换为字符串并按字典顺序排序。 例如,“80”排序在“9”之前,而不是之后。
与大多数排序函数类似,Array.prototype.sort(fn(a,b)) 需要一个包含两个测试参数的回调函数,其返回值如下:
[9,80,3,10,5,6].sort()
//
[9,80,3,10,5,6].sort(函数(a,b){
返回 a - b
})
//
8 计算:.reduce 和 .reduceRight
这两个函数比较难理解。 .reduce 将从左到右遍历链表,而 .reduceRight 将从右到左遍历链表。 两者的典型用法是: .reduce(callback(previousValue,currentValue,index,array),initialValue) 。
previousValue是最后一个回调函数的返回值,initialValue是它的初始值,currentValue是当前元素值,index是当前元素索引,array是调用.reduce的链表。
一个典型的用例,使用 .reduce 的 sum 函数。
Array.prototype.sum = 函数() {
返回 this.reduce(函数 (部分, 值) {
返回部分+值
}, 0)
};
[3,4,5,6,10].sum()
//
如果想将链表拼接成字符串,可以使用.join来实现。 但是,如果链表值是一个对象,.join 不会按照我们的预期返回值,除非该对象有合理的 valueOf 或 toString 方法。 在这些情况下,可以用.reduce来实现:
函数连接(输入){
返回 input.reduce(函数 (部分, 值) {
如果(部分){
部分 += ', '
返回部分+值
}, '')
连接([
{ 名称:'乔治' },
{名称:'山姆'}javascript 引用函数,
{ 名称: '梨' }
])
//
9 复制:.slice
与 .concat 类似,调用不带参数的 .slice() 返回源列表的浅表副本。 .slice 有两个参数:开始位置和结束位置。
Array.prototype.slice 可用于将类似字段的对象转换为真正的链表。
Array.prototype.slice.call({ 0: 'a', 1: 'b', 长度: 2 })
//
这不适用于 .concat,因为它用列表包装了类似列表的对象。
Array.prototype.concat.call({ 0: 'a', 1: 'b', 长度: 2 })
//
此外,.slice 的另一个常见用途是从参数列表中删除元素,这会将类似字段的对象转换为真正的链表。
函数格式(文本,粗体){
如果(粗体){
文本 = '' + 文本 + ''
var value = Array.prototype.slice.call(arguments, 2)
值.forEach(函数(值){
文本 = 文本.replace('%s', 值)
})
返回文本
格式('some%thing%s %s', true, '一些', '其他', '东西')
10 强大的.splice
.splice 是我最喜欢的原生链表函数。 只需调用一次,即可删除元素、插入新元素,同时执行删除和插入操作。 需要注意的是,与`.concat和.slice不同,这个函数会改变源链表。
var 源 = [1,2,3,8,8,8,8,8,9,10,11,12,13]
var 拼接=源。 拼接(3,4,4,5,6,7)
控制台.log(来源)
//
拼接的
//
如您所见,.splice 将返回删除的元素。 如果您想迭代长期删除的链表,这尤其方便。
var 源 = [1,2,3,8,8,8,8,8,9,10,11,12,13]
var spliced = source.splice(9)
拼接的。 forEach(函数(值){
安慰。 日志('已删除',值)
})
//
//
//
//
控制台.log(来源)
//
11 查找:.indexOf
使用.indexOf查找链表中某个元素的位置,如果没有匹配的元素则返回-1。 我经常使用 .indexOf 的情况是当我进行比较时,例如: a === 'a' || a === 'b' || a === 'c',或者只有两次比较时,可以使用 .indexOf: ['a', 'b', 'c'].indexOf(a) !== -1。
请注意,如果提供的引用相同,.indexOf 也可以查找对象。 第二个可选参数用于指定从哪里开始查找。
var a = { foo: 'bar' }
var b = [a, 2]
安慰。 log(b.indexOf(1))
//
安慰。 log(b.indexOf({ foo: 'bar' }))
//
安慰。 log(b.indexOf(a))
//
安慰。 log(b.indexOf(a, 1))
//
b.indexOf(2, 1)
//
如果要向后搜索,可以使用.lastIndexOf。
12 操作员:在
新手在笔试中常犯的一个错误就是混淆了.indexOf和in运算符:
变量 a = [1, 2, 5]
1 在一个
//
5 合一
//
问题在于 in 运算符检索对象的键而不是值。 当然,这在性能上比.indexOf快得多。
变量 a = [3, 7, 6]
1 a === !!a[1]
//
13 进场.倒车
该方法反转链表中的元素。
变量 a = [1, 1, 7, 8]
a.reverse()
// [8, 7, 1, 1]
.reverse 改变链表本身。