[20211226] 유사배열
유사배열(혹은 유사배열 객체)?
배열이 아닌데 배열처럼 사용할 수 있는 것.
객체의 key가 숫자고, length라는 속성을 가지고 있을 때
유사배열 예시
// 직접 만든 유사배열
const yoosa = {
0: "a",
1: "b",
2: "c",
length: 3,
};
// 흔히 사용하는 유사배열
const nodes = document.querySelectorAll("div"); // NodeList [div, div, div, ...]
const elements = document.body.children; // HTMLCollection [nonscript, div, script, ...]
function foo() {
arguments; // foo(1, 2, 3)로 호출된 경우를 가정, Arguments [1, 2, 3, ...]
}
위 예시 모두 배열처럼 사용할 수 있지만 배열이 아닌 유사배열이다.
유사배열 판별
- Array.isArray()
- instanceof
const nodes = document.querySelectorAll("div");
Array.isArray([]); // true
Array.isArray(nodes); // false
[] instanceof Array; // true
nodes instanceof Array; // false
배열과 유사배열의 차이
유사배열도 배열처럼 특정 인덱스에 접근할 수 있고, 길이도 알 수 있다.
하지만, 배열 메서드를 사용하지 못한다.
즉, Array.prototype을 사용할 수 없다.
// NodeList의 상위 프로토타입는 Object (NodeList -> Object)
const nodes = document.querySelectorAll("div");
// HTMLCollection의 상위 프로토타입도 Object (HTMLCollection -> Object)
const elements = document.body.children;
질문) NodeList 사용할 때, forEach 쓸 수 있던데요?? forEach 그거 Array.prototype에만 있는거 아닌가요??
const nodes = document.querySelectorAll("div");
nodes.forEach(console.log); // 모든 div 출력
NodeList의 상위 프로토타입은 Object이다.
그래서 여기서 사용된 forEach는 Array.prototype.forEach일 수 없다.
왜냐아면, NodeList 프로토타입 체인에 Array가 없기 때문.
정답은 NodeList.prototype에서 Array.prototype.forEach와 동일한 메서드를 제공하고 있다.
유사배열에서 push나 reduce와 같이 배열의 다른 모든 메서드는 사용할 수 없다.
사용할 수 있는 메서드는 유사배열 객체에서 제공해주는 메서드이다.
유사배열로 배열 메소드 사용하기
- call, apply 사용
const nodes = document.querySelectorAll("div");
// Function.prototype.call(thisArg, func...)
Array.prototype.forEach.call(nodes, (el) => console.log(el));
[].forEach.call(nodes, (el) => console.log(el));
- 유사배열을 배열로 변경
- slice()
- slice함수에 인자가 없으면 0번 인덱스부터 length까지 배열을 자른다.
- 즉, 인자가 없으면 똑같은 배열을 반환
Array.prototype.slice.call(유사배열);
- Array.from() → ES6부터
MDN Web docs : The
Array.from()
static method creates a new, shallow-copiedArray
instance from an array-like or iterable object.Array.from(유사배열);
-
Spread operator (…) → ES6부터
- iterables를 array로 변경 가능하다.
[...유사배열] nodeList.map(...) // undefined [...nodeList].map(...) // 정상적으로 map 함수 실행
결론
[ ]로 감싸져 있다고 해서 모두 배열이 아니다.
출처
카일 심슨 저자, YOU DON’T KNOW JS 타입과 문법, 스코프와 클로저 편
(JavaScript) 배열과 유사배열