---
type: reference
language: javascript
slug: array/push
title: "push() / pop() / shift() / unshift()"
title_tag: "JavaScript の push と pop — 戻り値と非破壊の書き換え"
summary: >
  4つとも元の配列を書き換えます。それぞれの戻り値、空配列で何が返るか、配列を丸ごと足すと
  入れ子になる理由、元を変えずに同じことをする書き方までを実行して確かめます。
description: >
  push は追加後の長さ、pop は取り出した要素を返します。空配列では undefined です。
  配列を push すると入れ子になる理由と、元を変えない書き換え方まで実行して示します。
status: published
difficulty: 1
minutes: 8

versions:
  verified: "Node 22.22.3"
  since: "ES3"
  deprecated: null
  removed: null

sources:
  - title: "Array.prototype.push — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.push"
  - title: "Array.prototype.shift — ECMAScript® 2026 Language Specification"
    url: "https://tc39.es/ecma262/#sec-array.prototype.shift"
  - title: "Array.prototype.with — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/with"

terms: [破壊的メソッド, 戻り値, スプレッド構文]

links:
  related:
    - javascript/learn/array/basics
    - javascript/reference/array/slice
    - javascript/how-to/object/merge

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

**4つとも[bad:元の配列を書き換えます]。** 新しい配列は返りません。

```js run
const items = [1, 2, 3];

console.log(items.push(4));
console.log(items);
console.log(items.pop());
console.log(items);
```
```output
4
[ 1, 2, 3, 4 ]
4
[ 1, 2, 3 ]
```

**戻り値が違います。**

- `push()` … 足したあとの[key:長さ]
- `pop()` … 取り出した[key:要素]

## 4つの違い

| メソッド | 場所 | 戻り値 |
|---|---|---|
| `push(値)` | 末尾に足す | 足したあとの**長さ** |
| `pop()` | 末尾から取る | 取った**要素** |
| `unshift(値)` | 先頭に足す | 足したあとの**長さ** |
| `shift()` | 先頭から取る | 取った**要素** |

```js run
const items = [1, 2, 3];

console.log(items.shift());
console.log(items);
console.log(items.unshift(0));
console.log(items);
```
```output
1
[ 2, 3 ]
3
[ 0, 2, 3 ]
```

**足す系は長さ、取る系は要素**、と覚えると取り違えません。

[dim:先頭を触る `shift()` / `unshift()` は、後ろの要素を全部ずらします。件数が多いと末尾より遅くなります。]

## 空の配列では

```js run
const items = [];

console.log(items.pop());
console.log(items.shift());
console.log(items.length);
console.log(items.push());
```
```output
undefined
undefined
0
0
```

**例外にはなりません。** `undefined` が返るだけです。

[bad:「取れた」のか「空だった」のかを、戻り値だけでは区別できません。]
`undefined` を要素として入れている配列では、なおさら分かりません。
先に `length` を見てください。

## 配列を足すと入れ子になる

```js bad
const items = [1, 2];

items.push([3, 4]);

console.log(items);
```
```output
[ 1, 2, [ 3, 4 ] ]
```

`push()` は**渡したものをそのまま1つの要素として**入れます。

中身を並べたいなら、[key:スプレッド構文]で開いてください。

```js run
const items = [1, 2];

items.push(...[3, 4]);

console.log(items);
```
```output
[ 1, 2, 3, 4 ]
```

`concat()` なら、元を変えずに繋げた新しい配列が返ります。

```js run
const items = [1, 2];

console.log(items.concat([3, 4]));
console.log(items);
```
```output
[ 1, 2, 3, 4 ]
[ 1, 2 ]
```

[dim:`push(...huge)` は引数として全部展開するので、要素が非常に多いと上限に当たることがあります。件数が読めないときは `concat()` かループを使ってください。]

## 元を変えたくないとき

**書き換えたくないなら、そもそも使わない**のがいちばん簡単です。

```js run
const items = [1, 2, 3];

console.log([...items, 4]);
console.log([0, ...items]);
console.log(items);
```
```output
[ 1, 2, 3, 4 ]
[ 0, 1, 2, 3 ]
[ 1, 2, 3 ]
```

取り除く・置き換える側にも、元を変えない対があります（ES2023）。

```js run
const items = [1, 2, 3];

console.log(items.toSpliced(0, 1));
console.log(items.with(0, 99));
console.log(items.toReversed());
console.log(items);
```
```output
[ 2, 3 ]
[ 99, 2, 3 ]
[ 3, 2, 1 ]
[ 1, 2, 3 ]
```

| 書き換える | 元を変えない |
|---|---|
| `push()` / `unshift()` | `[...items, x]` / `[x, ...items]` |
| `pop()` / `shift()` | `items.slice(0, -1)` / `items.slice(1)` |
| `splice()` | `toSpliced()` |
| `items[0] = x` | `with(0, x)` |
| `reverse()` | `toReversed()` |
| `sort()` | `toSorted()` |

[dim:`toSpliced()` / `with()` / `toReversed()` は Node 20 / Chrome 110 / Safari 16 より前では使えません。]

→ [slice() と splice()](/ja/javascript/reference/array/slice/)

## よくある間違い

### 戻り値を新しい配列だと思う

```js bad
const items = [1, 2, 3];
const added = items.push(4);

console.log(added);
```
```output
4
```

返るのは[key:長さ]です。**配列ではありません。**
`added.map(...)` と書けば、そこで落ちます。

### `const` だから安全だと思う

```js run
const items = [1, 2, 3];

items.push(4);

console.log(items);
```
```output
[ 1, 2, 3, 4 ]
```

`const` が固定するのは[key:名前と値の結びつき]で、中身ではありません。
→ [TypeError: Assignment to constant variable.](/ja/javascript/errors/assignment-to-constant-variable/)

**共有している配列に `push()` すると、見ている全員に影響します。**

### 繰り返しの中で `shift()` する

```js bad
const queue = [1, 2, 3];

for (let i = 0; i < queue.length; i++) {
  queue.shift();
}

console.log(queue);
```
```output
[ 3 ]
```

取り出すたびに `length` が減るので、**途中で条件が成立して止まります。**

全部取り出すなら `while` にしてください。

```js run
const queue = [1, 2, 3];
const done = [];

while (queue.length > 0) {
  done.push(queue.shift());
}

console.log(done, queue);
```
```output
[ 1, 2, 3 ] []
```

## まとめ

- 4つとも[bad:元を書き換える]
- **足す系は長さ、取る系は要素**を返す
- 空配列では `undefined`。例外にはならない
- 配列を `push()` すると[bad:入れ子]になる。`...` で開く
- 元を変えないなら `[...items, x]` や `toSpliced()` / `with()`
- **`const` でも中身は変わる**
