cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Slicing, splicing & joining

Copy parts of an array, change arrays in place, join values into strings, split strings back into arrays, and avoid the classic fill and shallow-copy traps.

By the end, you can
  • 01
    Choose mutating or non-mutating toolsPredict exactly when slice, splice, concat, fill, and copyWithin change the original array.
  • 02
    Move between arrays and stringsUse join and split with separators, defaults, empty fields, and limits.
  • 03
    Create arrays intentionallyUse spread, Array.from, and Array.of without falling into new Array(3) or shared-object fill bugs.

Copy parts, change parts, and turn lists into text

Arrays are ordered lists. In Array basics you met the list itself: indexes, length, adding items, removing items, and why holes from new Array(3) are surprising. This lesson is about the next everyday skill: choosing the right method when you need a piece of a list, a changed list, or a string made from list items.

The summary for this lesson is short but powerful: copy parts of an array, or change it in place. The important words are “copy” and “in place.” A method that copies returns a new value. A method that works in place mutates the original array: the same array object now holds different contents.

Mutates or returns new?
ToolChanges the receiver?ReturnsMemory note
slice(start, end)NoA shallow copy of the selected rangeNested objects are shared
splice(start, deleteCount, ...items)YesThe removed itemsUse carefully when other code keeps the same array
concat(...)NoA new shallow arrayArrays passed to concat are spread one level
join(separator)NoA stringnull and undefined become empty text
split(separator, limit)No string mutationA new array of stringsEmpty pieces are kept
fill(value, start, end)YesThe same arrayOne object value is shared in every filled slot
copyWithin(target, start, end)YesThe same arrayCopies inside the same array
Array.from(value, mapFn)NoA new arrayGood for array-likes and per-slot objects
Before we start: shallow copies

Spread, slice, and concat create a new outer array, but they do not deeply clone objects inside. That builds directly on Objects & references.

You will also reuse ideas from Strings and Default & rest parameters: separators turn arrays into strings, and spread expands values into a new array.

slice vs splice: photocopy or surgery?

INTERACTIVE
Real-life analogyslice is a photocopier; splice is book surgery

slice and splice differ by one letter, so learners mix them up constantly. Say the story out loud: slice is a photocopier; splice is surgery. One returns a copied range. The other edits the patient.

In real life: Photocopy pages 2 through 4
In JavaScript: array.slice(1, 4) returns copies of those items
In real life: The original book stays on the shelf
In JavaScript: slice does not mutate the original array
In real life: Cut pages out and glue new pages in
In JavaScript: array.splice(start, deleteCount, ...items) mutates
In real life: The removed pages land on your desk
In JavaScript: splice returns an array of removed items

Where the analogy stops: A photocopy duplicates paper. JavaScript's array copy is shallow: object elements are still shared references. You'll see that in the next section.

slice(start, end) starts at start and stops before end. The end is not included. Leave out end to copy to the end. Use a negative index to count from the right: slice(-2) means “last two items.”

splice(start, deleteCount, ...items) starts at start, removes deleteCount items, inserts any extra items, returns the removed items, and mutates the original array. That return value is a common source of bugs.

Run slice or splice on the same starting array
Method shapePop out in the code editor (opens in a new tab)JavaScript
const letters = ["a", "b", "c", "d"];letters.slice(start, end);letters.splice(start, deleteCount, ...items);
Real resultslice
return value["b","c"]
original after["a","b","c","d"]
abcd
Try it yourself

slice returned a copied range. The original boxes are unchanged, even with a negative start.

Both buttons create a fresh real array ["a", "b", "c", "d"] before running, so you can compare the methods fairly.

Try start = -2. With slice, you copy from the second-to-last item. With splice, you cut starting near the end. The lab runs real arrays each time, so the return value and the “original after” panel are the JavaScript result, not a drawing.

concat & spread: tape lists into a new list

STEP THROUGH

To combine arrays without changing the originals, use spread or concat. Spread opens an array inside a literal: [...a, ...b]. concat reads from a base array: a.concat(b, 4). Both return a new outer array.

Real-life analogyconcat and spread are tape

Imagine taping two lists onto a new page. The original pages still exist. But if both pages point to the same attached photo, scribbling on the photo changes what both pages show.

In real life: Tape two shopping lists onto a fresh sheet
In JavaScript: [...a, ...b] creates a new outer array
In real life: Add one handwritten item at the end
In JavaScript: a.concat(b, 4) can append arrays and values
In real life: A photo taped to both lists is the same photo
In JavaScript: Nested arrays and objects are shared references

Where the analogy stops: Tape creates a new sheet, not new copies of every object mentioned on the sheet. That is the shallow-copy limit.

Step through concat, spread, and a shallow copy
Step 0 of 8Ready
Your turn: follow the blue line

Predict which arrays change. Step through spread, concat, and one shallow-copy surprise.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const b = [3];const spread = [...a, ...b];const concatted = a.concat(b, 4);const nested = [["Ada"], ["Lin"]];const copy = nested.slice();copy[0].push("Grace");console.log(JSON.stringify(spread), JSON.stringify(concatted), JSON.stringify(nested[0]));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

The first two results are unsurprising: [...a, ...b] gives [1, 2, 3], and a.concat(b, 4) gives [1, 2, 3, 4]. The nested part matters professionally: slice, spread, and concat are shallow. If an item is an object or inner array, the copy and original share it.

join & split: strings and arrays trade places

INTERACTIVE
Real-life analogyjoin threads beads; split cuts the necklace

join takes array “beads” and threads one string through them. split takes a string necklace and cuts wherever the separator appears.

In real life: Thread beads with a dash between them
In JavaScript: ["a", "b", "c"].join("-") returns "a-b-c"
In real life: Use plain string between beads by default
In JavaScript: join() defaults to comma
In real life: Cut the necklace wherever you see a comma
In JavaScript: "a,b,,c".split(",") returns four pieces

Where the analogy stops: Real beads disappear when cut incorrectly. JavaScript strings are immutable: split returns a new array and leaves the original string alone.

Verified examples: ["a", "b", "c"].join("-") returns a-b-c; join() uses comma and returns a,b,c; [null, undefined, 1].join("-") returns --1 because null and undefined become empty text.

Going the other way, "a,b,,c".split(",") returns ["a","b","","c"]. The empty field between adjacent commas is kept. With a limit of 2 it returns ["a","b"]. And "hi".split("") returns ["h","i"]. For emoji, wait for Unicode & string internals: visible characters are not always one code unit.

Thread arrays into strings, then cut strings apart
Join and split shapesPop out in the code editor (opens in a new tab)JavaScript
const pieces = ["a", "b", "c"];pieces.join("-");"a,b,,c".split(",");
Live outputseparator ","
["a", "b", "c"].join(...)"a,b,c"
"a,b,,c".split(...)["a","b","","c"]
Try it yourself

join returns one string. split returns an array of strings. Empty pieces stay visible as "".

Try -, a space, and an empty separator. Empty separator is useful for simple text, but emoji need the later Unicode lesson.

Array.from & Array.of: create arrays on purpose

STEP THROUGH

Array.from creates a new array from something iterable or array-like. A string is iterable, so Array.from("hey") becomes ["h", "e", "y"]. An object with a length can be array-like, so Array.from({ length: 3 }, (_, i) => i * 2) becomes [0, 2, 4]. A Set is iterable too: [1,2] comes from Array.from(new Set([1, 1, 2])). The Set lesson comes later; for now, notice that the duplicate disappeared before Array.from read it.

Array.of fixes one old constructor surprise: Array.of(3) means “an array containing the item 3.” new Array(3) means “an array whose length is 3 but whose slots are empty.” That pitfall came from Array basics, and it is worth repeating because it causes real bugs.

Create arrays, then spot the fill trap
Step 0 of 8Ready
Your turn: follow the blue line

Change the length, predict the evens array, then step through the creation methods and mutation traps.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const evens = Array.from({ length: 4 }, (_, i) => i * 2);const oneNumber = Array.of(3);const emptySlots = new Array(3);const rows = new Array(3).fill({ done: false });rows[0].done = true;const shifted = [1, 2, 3, 4, 5].copyWithin(0, 3);console.log(letters, evens, oneNumber, emptySlots.length, rows[1].done, shifted);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 2: how long should the generated evens array be?

Changing the length starts a fresh recorded run.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

fill & copyWithin: useful, mutating, and easy to misuse

Real-life analogyfill paints lockers

fill is handy for primitive values: new Array(3).fill(0) gives [0, 0, 0]. But fill() puts the same object in every slot.

In real life: Paint lockers 2 through 5 blue
In JavaScript: array.fill("blue", 1, 5) writes into that range
In real life: Use the same stencil in every locker
In JavaScript: fill({}) puts the same object reference everywhere
In real life: Copy labels from one row of lockers to another
In JavaScript: copyWithin copies inside the same array

Where the analogy stops: Paint is a primitive-like value in the story. Objects are different: one object reference can be seen from many slots.

The replay above shows the trap: after rows[0].done = true, rows[1].done is also true. The fix is to create a fresh object for each slot:

Separate objects with Array.fromPop out in the code editor (opens in a new tab)JavaScript
const rows = Array.from({ length: 3 }, () => ({ done: false }));

copyWithin is rarer. It copies a slice of an array into another position inside the same array and mutates that array. A verified example: [1, 2, 3, 4, 5].copyWithin(0, 3) returns and leaves [4,5,3,4,5]. You may not write it often, but when you read it, know that it is in-place.

Where you’ll use this

These methods show up any time a user interface keeps lists: cart items, selected filters, open tabs, playlist songs, form rows, and text entered by a person.

Remove one item without mutatingPop out in the code editor (opens in a new tab)JavaScript
const items = ["red", "green", "blue", "gold"];const index = 1;const next = [...items.slice(0, index), ...items.slice(index + 1)];

That pattern keeps the old array available for code that still needs it. The upcoming Sorting & copying safely lesson teases toSpliced, a newer non-mutating cousin of splice.

  • split user text into tags, then join cleaned tags for display.
  • concat or spread server results onto an existing list without changing the old one.
  • Array.from create placeholder rows safely, one fresh object at a time.
  • slice preview the first few cards while keeping the full list intact.

Common misconceptions

“slice and splice are basically the same.”

No. slice copies; splice mutates and returns removed items.

“If I copied the array, nothing inside is shared.”

Array copies here are shallow. Object and nested-array elements are still shared references.

“join turns null and undefined into words.”

join treats null and undefined as empty text, so separators may sit next to each other.

“split always removes empty pieces.”

Empty pieces are kept. "a,b,,c".split(",") includes "".

“fill() makes separate objects.”

It writes the same object reference into every slot. Use Array.from with a factory function instead.

“copyWithin returns a safe copy.”

It mutates and returns the same array. The word “copy” means copied inside the receiver.

Does it mutate the original array?
  • items.slice(1, 3)
  • items.splice(1, 2, "x")
  • a.concat(b)
  • [...a, ...b]
  • items.join('-')
  • items.fill(0)
  • items.copyWithin(0, 2)
  • Array.from('hey')
Try it yourself
0 of 8 correct

Sort each expression. Read the explanation even when you guess correctly; the edge cases matter.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Practice: copy, cut, join, and create

5 EXERCISES
Exercise 1 · Warm-upPredict slice, splice, and the original

Predict all three logs. Use the answer box for the first log, then check the solution for the full trace.

Starter codePop out in the code editor (opens in a new tab)JavaScript
const letters = ["a", "b", "c", "d"];
const copied = letters.slice(1, 3);
const removed = letters.splice(2, 1, "X");
console.log(copied.join(""));
console.log(removed.join(""));
console.log(letters.join(""));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeRemove an item without mutating

    Remove green at index 1 without using splice. What does the new array print?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const items = ["red", "green", "blue", "gold"];
    const index = 1;
    const withoutGreen = [...items.slice(0, index), ...items.slice(index + 1)];
    console.log(withoutGreen.join(","));
    console.log(items.join(","));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeSplit words and join them back

      Turn "a b c" into ["a", "b", "c"], then back into one string with pipes.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      const words = "a b c".split(" ");
      console.log(words.join("|"));

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeBuild even numbers with Array.from

        Build [0, 2, 4, 6] without writing the four numbers by hand.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const evens = Array.from({ length: 4 }, (_, i) => i * 2);
        console.log(evens.join(","));

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeFix the shared-object fill bug

          Change the setup so mutating the first row does not affect the second row.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const rows = new Array(3).fill({ done: false });
          rows[0].done = true;
          console.log(rows[1].done);

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            8 QUESTIONS

            Trace return values and original arrays separately. Your first try counts, and every option explains itself.

            Lesson quiz · 8 questionsScore: first tries count
            1. Question 1 of 8Which statement best describes slice and splice?

              Choose an answer to see the explanation.

            2. Question 2 of 8What do slice(-2) and the untouched original print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const letters = ["a", "b", "c"];
              console.log(letters.slice(-2).join(""));
              console.log(letters.join(""));

              Choose an answer to see the explanation.

            3. Question 3 of 8What do the splice return value and final array print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const nums = [1, 2, 3, 4];
              console.log(nums.splice(1, 2, 9).join(","));
              console.log(nums.join(","));

              Choose an answer to see the explanation.

            4. Question 4 of 8What does [null, undefined, 1].join('-') produce?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log([null, undefined, 1].join("-"));

              Choose an answer to see the explanation.

            5. Question 5 of 8What do split with and without a limit print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log("a,b,,c".split(",").join("|"));
              console.log("a,b,,c".split(",", 2).join("|"));

              Choose an answer to see the explanation.

            6. Question 6 of 8Which expression creates [3] instead of an empty-slotted array of length 3?

              Choose an answer to see the explanation.

            7. Question 7 of 8What does the shared-object fill example print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const rows = new Array(2).fill({ done: false });
              rows[0].done = true;
              console.log(rows[1].done);

              Choose an answer to see the explanation.

            8. Question 8 of 8What does copyWithin print before and after?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const values = [1, 2, 3, 4, 5];
              console.log(values.copyWithin(0, 3).join(","));
              console.log(values.join(","));

              Choose an answer to see the explanation.

            Key takeaways

            • slice copies a shallow range; splice mutates and returns removed items.
            • Spread and concat make new outer arrays, but nested objects stay shared.
            • join returns a string; split returns an array of strings and keeps empty pieces.
            • Array.from builds arrays from iterables or array-likes; Array.of(3) means [3].
            • fill and copyWithin mutate. Avoid fill() unless shared objects are intentional.

            Remember the one-liner.
            Copy with slice, spread, concat, and Array.from; mutate with splice, fill, and copyWithin; bridge arrays and strings with join and split.

            Up next: Searching arrays.

            CompleteFrontend Clear concepts. Working examples.