pop/push, shift/unshift 方法

数组用例

一、JavaScript 中的数组既可以用作队列,也可以用作栈。它们允许你从首端/末端来添加/删除元素。
二、这在计算机科学中,允许这样的操作的数据结构被称为双端队列(deque)

队列

一、队列(queue))是最常见的使用数组的方法之一。在计算机科学中,这表示支持两个操作的一个有序元素的集合:

  • push在末端添加一个元素.
  • shift取出队列首端的一个元素,整个队列往前移,这样原先排第二的元素现在排在了第一。

image.png
1、这两种操作数组都支持。

【示例】队列的应用在实践中经常会碰到。例如需要在屏幕上显示消息队列。

数据结构栈

一、数组还有另一个用例,就是数据结构栈。
1、它支持两种操作:

  • push在末端添加一个元素.
  • pop从末端取出一个元素.

2、所以新元素的添加和取出都是从“末端”开始的。
二、栈通常被被形容成一叠卡片:要么在最上面添加卡片,要么从最上面拿走卡片:
image.png
三、对于栈来说,最后放进去的内容是最先接收的,也叫做 LIFO(Last-In-First-Out),即后进先出法则。而与队列相对应的叫做 FIFO(First-In-First-Out),即先进先出。

方法

作用于数组末端的方法

pop

一、取出并返回数组的最后一个元素:

| 【示例】```javascript let fruits = [“Apple”, “Orange”, “Pear”];

alert( fruits.pop() ); // 移除 “Pear” 然后 alert 显示出来

alert( fruits ); // Apple, Orange

  1. |
  2. | --- |
  3. <a name="kcxzy"></a>
  4. #### push
  5. 一、在数组末端添加元素
  6. | 【示例】```javascript
  7. let fruits = ["Apple", "Orange"];
  8. fruits.push("Pear");
  9. alert( fruits ); // Apple, Orange, Pear

1、调用fruits.push(…)与fruits[fruits.length] = …是一样的。 | | —- |

作用于数组首端的方法

shift

一、取出数组的第一个元素并返回它:

| 【示例】```javascript let fruits = [“Apple”, “Orange”, “Pear”];

alert( fruits.shift() ); // 移除 Apple 然后 alert 显示出来

alert( fruits ); // Orange, Pear

 |
| --- |

<a name="BVt21"></a>
#### unshift
一、在数组的首端添加元素:

| 【示例】```javascript
let fruits = ["Orange", "Pear"];

fruits.unshift('Apple');

alert( fruits ); // Apple, Orange, Pear

| | —- |

二、push和unshift方法都可以一次添加多个元素:

| 【示例】```javascript let fruits = [“Apple”];

fruits.push(“Orange”, “Peach”); fruits.unshift(“Pineapple”, “Lemon”);

// [“Pineapple”, “Lemon”, “Apple”, “Orange”, “Peach”] alert( fruits );

 |
| --- |

<a name="fLHtP"></a>
## 性能
一、push/pop方法运行的比较快,而shift/unshift比较慢。<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/355497/1619515501968-b38ce3de-b479-406d-bff6-c501857d1cdf.png#clientId=u520d37b0-7516-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=170&id=vA5lL&margin=%5Bobject%20Object%5D&name=image.png&originHeight=170&originWidth=354&originalType=binary&ratio=1&rotation=0&showTitle=false&size=9599&status=done&style=none&taskId=u4d7ab9fe-2c35-447c-b1c7-ac736ae0edf&title=&width=354)
<a name="FFAIK"></a>
### 为什么作用于数组的末端会比首端快
一、让我们看看shift / unshift 在执行期间都发生了什么:
```javascript
fruits.shift(); // 从首端取出一个元素

1、只获取并移除数字0对应的元素是不够的。其它元素也需要被重新编号。
2、shift操作必须做三件事:
(1)移除索引为0的元素。
(2)把所有的元素向左移动,把索引1改成0,2改成1以此类推,对其重新编号。
(3)更新length属性。
image.png
3、数组里的元素越多,移动它们就要花越多的时间,也就意味着越多的内存操作。
4、unshift也是一样:为了在数组的首端添加元素,我们首先需要将现有的元素向右移动,增加它们的索引值。
二、那push/pop是什么样的呢?

fruits.pop(); // pop操作的行为:从末端取走一个元素

1、它们不需要移动任何东西。
2、如果从末端移除一个元素,pop方法要做的事情
(1)清理末端索引值
(2)缩短length就可以了。
image.png
3、 pop方法不需要移动任何东西,因为其它元素都保留了各自的索引。这就是为什么pop会特别快。
4、 push方法也是一样的。

splice(aSuncat-20210527:常用)

一、如何从数组中删除元素?

| 【示例】数组是对象,所以我们可以尝试使用delete:```javascript let arr = [“I”, “go”, “home”];

delete arr[1]; // remove “go”

alert( arr[1] ); // undefined

// now arr = [“I”, , “home”]; alert( arr.length ); // 3

1、元素被删除了,但数组仍然有 3 个元素,我们可以看到arr.length == 3。<br />2、这很正常,因为delete obj.key是通过key来移除对应的值。对于对象来说是可以的。但是对于数组来说,我们通常希望剩下的元素能够移动并占据被释放的位置。我们希望得到一个更短的数组。<br />3、所以应该使用特殊的方法。 |
| --- |

三、arr.splice方法可以说是处理数组的瑞士军刀。它可以做所有事情:添加,删除和插入元素。<br />1、语法是:
```javascript
arr.splice(start[, deleteCount, elem1, ..., elemN])

2、它从索引start开始修改arr:删除deleteCount个元素并在当前位置插入elem1, …, elemN。改变原始数组,最后返回已被删除元素的数组。

| 【示例】从索引1开始删除1个元素。```javascript let arr = [“I”, “study”, “JavaScript”];

arr.splice(1, 1); // 从索引 1 开始删除 1 个元素

alert( arr ); // [“I”, “JavaScript”]

 |
| --- |

| 【示例】我们删除了 3 个元素,并用另外两个元素替换它们:```javascript
let arr = ["I", "study", "JavaScript", "right", "now"];

// remove 3 first elements and replace them with another
arr.splice(0, 3, "Let's", "dance");

alert( arr ) // now ["Let's", "dance", "right", "now"]

| | —- |

| 【示例】splice返回了已删除元素的数组:```javascript let arr = [“I”, “study”, “JavaScript”, “right”, “now”];

// 删除前两个元素 let removed = arr.splice(0, 2);

alert( removed ); // “I”, “study” <— 被从数组中删除了的元素

 |
| --- |

| 【示例】我们可以将deleteCount设置为0,splice方法就能够插入元素而不用删除任何元素:```javascript
let arr = ["I", "study", "JavaScript"];

// 从索引 2 开始
// 删除 0 个元素
// 然后插入 "complex" 和 "language"
arr.splice(2, 0, "complex", "language");

alert( arr ); // "I", "study", "complex", "language", "JavaScript"

| | —- |

| 【项目示例5】项目中,删除符合某个条件的某一项
方法1、findIndex:项目中,可以先把某一项id符合某个条件的数据找出来,再删除这项```javascript const categoryData = [ { id: 1, }, { id: 2, } ] const id = 2;

// 先用findIndex找到符合要求的行的index,然后用slice复制数组,最后用splice删除1项 const index = categoryData.findIndex((item) => item.id === id); // index => 1 const newCate = categoryData.slice() newCate.splice(index, 1);

console.log(newCate); // 得到的数据如下 [ { id: 1, }, ]

方法2:filter(推荐)```javascript
const categoryData = [
  {
      id: 1,
  },
  {
      id: 2,
  }
]
const id = 2;

const newCate = categoryData.filter((item) => item.id !== id);

console.log(newCate);
// 得到的数据如下
[
  {
      id: 1,
  },
]

| | —- |

四、允许负向索引
1、在这里和其他数组方法中,负向索引都是被允许的。它们从数组末尾计算位置

| 【示例】```javascript let arr = [1, 2, 5];

// 从索引 -1(尾端前一位) // 删除 0 个元素, // 然后插入 3 和 4 arr.splice(-1, 0, 3, 4);

alert( arr ); // 1,2,3,4,5

 |
| --- |


<a name="NF8NM"></a>
# slice(aSuncat-20210527:常用)
一、arr.slice方法比arr.splice简单得多。<br />1、语法是:
```javascript
arr.slice([start], [end])

2、它会返回一个新数组,将所有从索引start到end(不包括end)的数组项复制到一个新的数组。start和end都可以是负数,在这种情况下,从末尾计算索引。
二、它和字符串的str.slice方法有点像,就是把子字符串替换成子数组。

| 【示例】```javascript let arr = [“t”, “e”, “s”, “t”];

alert( arr.slice(1, 3) ); // e,s(复制从位置 1 到位置 3 的元素)

alert( arr.slice(-2) ); // s,t(复制从位置 -2 到尾端的元素)

 |
| --- |

三、我们也可以不带参数地调用它:arr.slice()会创建一个arr的副本。其通常用于获取副本,以进行不影响原始数组的进一步转换。<br />1、slice方法参数为空时,同concat方法一样,都是浅复制生成一个新数组。

| 【示例】项目中,级联选择,如果选择当前行,需要先把后面的数据清空,就用到了这个方法```json
// 数据根据categoryPids的长度来定循环几列
const pids = categoryPids.slice(0, level); // level:当前选择的是第几列
setCategoryPids([
  ...pids,
]);

| | —- |

concat

一、arr.concat创建一个新数组,其中包含来自于其他数组和其他项的值。
二、语法:

arr.concat(arg1, arg2...)

1、参数

  • 它接受任意数量的参数 —— 数组或值都可以。
  • 如果参数argN是一个数组,那么其中的所有元素都会被复制。否则,将复制参数本身。

2、结果是一个包含来自于arr,然后是arg1,arg2的元素的新数组。

| 【示例】```javascript let arr = [1, 2];

// create an array from: arr and [3,4] alert( arr.concat([3, 4]) ); // 1,2,3,4

// create an array from: arr and [3,4] and [5,6] alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6

// create an array from: arr and [3,4], then add values 5 and 6 alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6

 |
| --- |

二、通常,它只复制数组中的元素。其他对象,即使它们看起来像数组一样,但仍然会被作为一个整体添加:

| 【示例】```javascript
let arr = [1, 2];

let arrayLike = {
  0: "something",
  length: 1
};

alert( arr.concat(arrayLike) ); // 1,2,[object Object]

| | —- |

1、但是,如果类似数组的对象具有Symbol.isConcatSpreadable属性,那么它就会被concat当作一个数组来处理

| 【示例】此对象中的元素将被添加:```javascript let arr = [1, 2];

let arrayLike = { 0: “something”, 1: “else”,

length: 2 };

alert( arr.concat(arrayLike) ); // 1,2,something,else ``` | | —- |

【示例】以下js操作Array的方法中不能添加元素的是:()
A. push
B. pop
C. unshift
D. splice
答案:B