게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌57 - JavaScript - 6년 전 등록 / 5년 전 수정

배열과 유사배열

안녕하세요. 이번 시간에는 배열과 유사배열에 대해서 살펴보겠습니다.

배열은 다들 아실겁니다. 그런데 유사배열은 잘 모르는 입문자분들이 많이 계십니다. 한 번 둘의 차이를 알아봅시다.

var array = [1, 2, 3];
array; // [1, 2, 3]
var nodes = document.querySelectorAll('div'); // NodeList [div, div, div, div, div, ...]
var els = document.body.children; // HTMLCollection [noscript, link, div, script, ...]

nodes와 els는 프론트엔드 개발을 하다보면 많이 접하는 친구들이죠. 위 예제에서 array는 배열이고, nodes와 els는 유사배열입니다. 둘의 차이를 아시겠나요? 겉만 봐서는 잘 모릅니다. 둘 다 비슷하게 []로 감싸져 있거든요. Array.isArray 메서드(배열인지를 판단해주는 메서드)를 사용해서 뭐가 배열인지 확인해보겠습니다.

Array.isArray(array); // true
Array.isArray(nodes); // false
Array.isArray(els); // false

직접 배열 리터럴로 선언한 array만 배열입니다. 비슷한 방법으로, array instanceof Array로도 판단할 수 있습니다.

nodes나 els처럼 []로 감싸져있지만 배열이 아닌 친구들을 유사배열이라고 부릅니다. 어떻게 이런 친구들이 만들어지는지 알아봅시다.

var yoosa = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};

yoosa 객체가 바로 유사배열입니다. 키가 숫자고, length라는 속성을 가지고 있습니다. 배열도 객체라는 성질을 이용한 트릭입니다. 배열처럼 yoosa[0], yoosa[1], yoosa.length같은 것을 모두 활용할 수 있습니다.

배열과 유사배열을 구분해야 하는 이유는, 유사배열의 경우 배열의 메서드를 쓸 수 없기 때문입니다.

array.forEach(function(el) { console.log(el); }); // 1, 2, 3
els.forEach(function(el) { console.log(el); }); // Uncaught TypeError: els.forEach is not a function

els에 forEach같은 배열 메서드를 사용하면 에러가 발생합니다. (nodes는 프로토타입에 forEach가 있어서 됩니다.) 배열이 아니므로 발생하는 것입니다. 이럴 때 메서드를 빌려 쓰는 방법이 있습니다. 배열 프로토타입에서 forEach 메서드를 빌려오는 것이죠. 바로 call이나 apply입니다. 이 강좌에서 설명했습니다.

Array.prototype.forEach.call(nodes, function(el) { console.log(el); });
[].forEach.call(els, function(el) { console.log(el); });

이제 유사배열에도 forEach를 사용할 수 있습니다. map이나 filter, reduce 등의 다른 배열 메서드도 사용 가능합니다.

최신 자바스크립트에서는 Array.from으로 더 간단하게 할 수 있습니다.

Array.from(nodes).forEach(function(el) { console.log(el) });

자주 보는(ES6에서는 더 이상 안 보이지만) 유사배열이 하나 더 있습니다. function의 arguments입니다. 함수선언문에 넣은 인자 목록을 표시하죠.

function arrayLike() {
  console.log(arguments);
}
arrayLike(4, 5, 6); // Arguments [4, 5, 6, callee, Symbol]

역시 forEach같은 배열 메서드를 쓸 수 없으므로 문제가 됩니다. 위에서 설명한 방법을 적용해야 합니다.

function arrayLike() {
  console.log(arguments);
  [].forEach.call(arguments, function(el) { console.log(el) });
}
arrayLike(4, 5, 6);

유사배열, 별 거 아니죠? []로 감싸져 있다고 다 같은 배열이 아니라는 것과, Array.isArray로 판별하는 방법, 배열 프로토타입에서 메서드를 빌려쓰는 방법에 대해서 알아두시면 좋습니다! 유사배열과 자주 만나는 프론트엔드에서는 필수입니다!

다음 시간에는 this에 대해 좀 더 자세하게 알아보겠습니다.

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

11개의 댓글이 있습니다.
3년 전
이해하기 쉬운 설명 감사합니다.
혹시 유사배열을 사용하는 이유가 뭔지 알 수 있을까요?
3년 전
직접 사용할 이유는 없다고 보시면 됩니다. 브라우저가 데이터를 유사배열로 줘서 어쩔 수 없이 알고 있어야 합니다.
4년 전
call, apply, bind는 this를 바꿔주는 역할을 하는 것으로 알고 있습니다.
그러면 Array.prototype.forEach 내부 구현에 this가 들어가는 로직이 있기 때문에 바꿔서 사용하는것인가요 ?
3년 전
여기서는 그냥 forEach 함수를 빌려쓰는 용도입니다.
4년 전
잘봤습니다
5년 전
리듀서에서 2개의 객체를 가진 배열을 initialState 로 넣고 해당 initialState 를 컴포넌트에서 불러오면 arguments 에 한번 들어갖다 나와서 그런지 배열이 아닌 유사배열객체가 됩니다. 그래서 배열의 map 메소드가 작동하지 않고, Array.from 같은 기능도, 가벼운 복사만을 하기 때문에 복사가 되지 않습니다. 어떻게 처리를 해야할까요 ㅜㅜ 혹시 몰라 깃링크도 첨부합니다. https://github.com/bohaesoju/ShoppingCart
5년 전
희한하네요. mapStateToProps를 하더라도 원래 배열이 유지되는 게 맞습니다. arguments 객체는 쓰시면 안됩니다.
5년 전
당분간 ZeroCho님을 스토킹할듯.... 또하나 배워갑니다. Node교과서랑 병행하니 진도가 좀 더디네요.
5년 전
붉은색 '이강좌' 링크를 누르면 본페이지에 머무릅니다. call, apply 글로 가야할것 같은데 오류인가요?
5년 전
수정했습니다 감사합니다!
6년 전
Nodejs 교과서 7장 sequelize.js 첫 문장이 [].forEach.call(....로 시작해서 멘붕왔는데 너무 친절한 설명 감사합니다
6년 전
안녕하세요, 잘 봤습니다. 그런데 일반 객체와 유사배열을 구별할 방법은 없을까요?
6년 전
유사배열도 일반 객체이기 때문에 구별하기 힘듭니다. 배열과는 구별 가능합니다.
6년 전
덕분에 유사배열이란 걸 알게되었네요 감사합니당ㅎㅎㅎㅎ
6년 전
좋은내용이네요 잘봤습니다.
6년 전
안녕하세요, 질문이 있습니다. 배열과 유사배열을 구분해야 하는 이유는, 유사배열의 경우 배열의 메서드를 쓸 수 없기 때문이라고 하셨는데, 이제 유사배열에도 forEach를 사용할 수 있다면 배열과 유사배열을 구분지을 필요가 없다는 거 아닌가요?
6년 전
아니죠. 구분지었기 때문에 forEach를 배열에서 빌려와 사용한겁니다. 반대로 생각하셔야합니다.