Trace the fixed program
Order A=10, B=2 and C=2 ascending. The source order must remain A, B, C; B and C should keep their relative order.
const source=[{id:'A',score:10},{id:'B',score:2},{id:'C',score:2}];
const sorted=[...source].sort((a,b)=>a.score-b.score);
console.log(JSON.stringify({sorted:sorted.map(r=>r.id),source:source.map(r=>r.id)}));
{"sorted":["B","C","A"],"source":["A","B","C"]}| Record | Score | Sorted position |
|---|---|---|
| B | 2 | First |
| C | 2 | After B: tied |
| A | 10 | Last |
Explain the result
sort mutates its receiver. Spread supplies a new receiver, and the numeric difference comparator orders the scores. A comparator result of zero preserves the input order of ties under stable sorting. Object references remain shared; inconsistent comparators or NaN scores need a separate input policy.
Test the alternative
Calling source.sort directly changes source. Omitting a comparator sorts these numbers by their string form, giving 10 before 2.
const source=[10,2];const result=source.sort();
console.log(JSON.stringify({source,result,sameArray:source===result}));
{"source":[10,2],"result":[10,2],"sameArray":true}Work the boundary case
How can the sorted array be new while its B object is still shared?
Show the worked answer
Spread copies the array entries, which are object references. It protects array order, not later mutations inside each row.
const source=[{id:'A',score:10},{id:'B',score:2}];const sorted=[...source].sort((a,b)=>a.score-b.score);
const direct=[10,2];direct.sort((a,b)=>a-b);
console.log(JSON.stringify({differentArray:sorted!==source,sameB:sorted[0]===source[1],sourceIds:source.map(r=>r.id),direct}));
{"differentArray":true,"sameB":true,"sourceIds":["A","B"],"direct":[2,10]}