JavaScriptのcopyWithin():配列内の範囲を長さを変えずに上書きする
Array.prototype.copyWithin()で同じ配列内の要素を上書きコピーする方法を解説。引数・戻り値、ブラウザーとNode.jsでの実行手順、範囲の重なりや参照共有の注意点を学べます。
copyWithin()でできること
Array.prototype.copyWithin()は、配列の一部分を、同じ配列内の別の位置へコピーするメソッドです。コピー先の要素を上書きし、配列の長さは変えません。一定数のデータを保持する処理や、既存の作業配列で値をずらす処理に使えます。
例えば、直近4回の計測値を持つ配列で、古い値を除いて残りを左へ寄せる場面を考えます。copyWithin(0, 1)で2番目以降を先頭へコピーし、最後の枠に新しい値を代入すれば、4要素の配列を使い続けられます。
押さえる点は、コピー元の値がその場から消えるわけではないことです。コピー先にならなかった場所には元の値が残ります。また、戻り値は新しい配列ではなく、変更した配列自身です。MDNのcopyWithin()リファレンス
動作環境と実行方法
ブラウザーで実行する
2026年11月4日時点で、MDNはこの機能を広く利用可能な機能とし、2015年9月以降のブラウザー間で利用できると説明しています。現在のChrome、Edge、Firefox、Safariで使用できます。古いブラウザーや組み込みWebViewを対象にする場合は、搭載の有無を確認してください。MDNの対応状況
本記事のコードはDOMを使いません。ブラウザーで空のタブを開き、開発者ツールのConsoleにJavaScriptコード全体を貼り付けて実行できます。各コードをブロックで囲んでいるため、同じConsoleで再実行しても、トップレベルの定数名が衝突しにくい形です。
Node.jsで実行する
Node.jsでも利用できます。本記事ではNode.js 22以降を実行対象にします。これは記事の対象バージョンであり、このAPIが初めて使えるようになったバージョンを示すものではありません。ライブラリーのインストールや実験用フラグは不要です。
Node.jsはV8を使い、安定したJavaScript機能を標準で有効にします。Node.jsのJavaScript対応方針
次の完成コードをテキストエディターでcopy-within-demo.jsに保存し、そのファイルがあるフォルダーでターミナルを開きます。
node --version
node copy-within-demo.js最初のコマンドでバージョンを確認し、次のコマンドで実行します。ファイル名をnodeに渡すのが基本の実行方法です。Node.jsのスクリプト実行手順
引数と戻り値を理解する
呼び出し方はarray.copyWithin(target, start, end)です。添字は先頭を0として数えます。
targetはコピー先の開始位置です。startはコピー元の開始位置です。endはコピー元の終了位置で、その位置の要素は含みません。省略すると配列末尾までが対象です。- 戻り値は変更後の同じ配列です。コピーした要素数ではありません。
コピーはコピー先の末尾で打ち切られます。targetが配列の長さ以上なら何もコピーされません。endがstart以下になる場合も、コピー対象はありません。
負の添字は末尾からの位置として扱われます。例えば、長さ5の配列で-2は添字3です。通常の利用では、まず非負の整数で範囲を指定すると読みやすくなります。引数には整数への変換も行われるため、入力値の検証を省略するための仕組みとは考えないでください。MDNの引数説明
完成コード:直近4回の計測値を更新する
次のコードは外部データや追加ファイルに依存せず、ブラウザーとNode.jsの両方で実行できます。
{
"use strict";
function appendReading(readings, value) {
if (!Array.isArray(readings)) {
throw new TypeError("計測値は配列で指定してください");
}
if (readings.length !== 4) {
throw new RangeError("計測値は4要素にしてください");
}
if (!readings.every(Number.isFinite)) {
throw new TypeError("既存の計測値は有限の数値にしてください");
}
if (!Number.isFinite(value)) {
throw new TypeError("新しい計測値は有限の数値にしてください");
}
const result = readings.copyWithin(0, 1);
readings[readings.length - 1] = value;
return result;
}
if (typeof Array.prototype.copyWithin !== "function") {
console.error("この環境はcopyWithin()に対応していません");
} else {
const readings = [18, 20, 19, 21];
console.log("更新前: " + JSON.stringify(readings));
const result = appendReading(readings, 22);
console.log("更新後: " + JSON.stringify(readings));
console.log("同じ配列: " + (result === readings));
console.log("要素数: " + readings.length);
try {
appendReading(readings, NaN);
} catch (error) {
console.log("入力エラー: " + error.message);
}
console.log("エラー後: " + JSON.stringify(readings));
}
}期待出力は次のとおりです。これは仕様に沿って追跡した出力であり、実機で実行した結果ではありません。
更新前: [18,20,19,21]
更新後: [20,19,21,22]
同じ配列: true
要素数: 4
入力エラー: 新しい計測値は有限の数値にしてください
エラー後: [20,19,21,22]コピー範囲が重なってもよい理由
copyWithin(0, 1)のコピー元は添字1から3、コピー先は添字0から2です。範囲は重なっていますが、コピー途中の上書きによってコピー元の並びが壊れることはありません。
コピー直後は[20,19,21,21]です。末尾の21はそのまま残るので、続く代入で22に置き換えています。この代入を忘れると、最新値が重複した配列になります。
入力検証は変更前にまとめています。そのため、この例のNaNによる失敗では計測配列は変化しません。処理は同期的で、awaitやPromiseの待機は不要です。
失敗例と制約
戻り値を別の配列だと思わない
戻り値を別の変数に入れても、元の配列と同じ実体を参照します。変更前の状態を残す必要がある場合は、先に配列を複製してから操作してください。
{
const original = [10, 20, 30, 40];
const edited = [...original];
edited.copyWithin(1, 0, 2);
console.log(JSON.stringify(original));
console.log(JSON.stringify(edited));
}期待出力は順に[10,20,30,40]と[10,10,20,40]です。ただし、この複製も浅いコピーです。配列内にオブジェクトが入っていれば、そのオブジェクトの参照は共有されます。JavaScriptの標準的な配列コピーが浅いコピーである点は、MDNのArray解説でも説明されています。
オブジェクトそのものは複製されない
{
const items = [{ score: 1 }, { score: 2 }];
items.copyWithin(1, 0, 1);
items[1].score = 9;
console.log(items[0].score);
console.log(items[0] === items[1]);
}期待出力は9とtrueです。添字0と1が同じオブジェクトを指すため、片方からの変更がもう片方にも見えます。独立した編集用データを作る目的には、そのまま使えません。
書き換え可能な通常の配列を使う
要素を書き換えられない配列では、変更時にTypeErrorが発生する場合があります。また、特殊なgetterやsetterなどを持つ配列では、途中で例外が起きる可能性があります。例外が出たら全変更が元に戻る、という保証はありません。
完成コードは、アプリ側で作った、空きスロットのない通常の数値配列を前提にしています。every()は空きスロットを検査しないため、あらゆる疎配列を排除する検証にはなっていません。空きスロットを含む配列では、その空きもコピー先へ伝わります。
活用事例と導入時の改善案
このAPIが向くのは、直近の計測値、一定数の処理時間、固定幅の作業データなど、要素数を保って範囲をずらしたい場面です。通常の一覧編集で要素の挿入や削除をしたい場合は、必要な操作が異なります。
導入時は、完成コードのように更新処理を関数へまとめ、元の配列が変わることを呼び出し側にも伝えると安全です。複数の場所で同じ配列を共有している場合は、上書きの影響範囲を先に確認してください。
改善案として、大きな配列を高頻度で更新する用途では、毎回データをずらす必要があるかを検討しましょう。先頭位置を別に管理する設計なら、移動自体を減らせます。小さな固定長配列では、この例のような直接的な実装が理解しやすく、まず比較の基準にできます。
公式参考資料
Googleの優先するニュース提供元にSEの部屋を追加
Googleで、いつも読みたい情報源を選べます。登録可否はGoogleの画面で確認できます。
候補にSEの部屋が表示されない場合は、まだ追加できません。