Array 전역 객체는 배열을 생성할 때 사용하는 리스트 형태의 고수준 객체다
배열은 프로토타입으로 탐색과 변형 작업을 수행하는 메서드를 갖는, 리스트와 비슷한 객체다
JavaScript에서 배열의 길이와 요소의 자료형은 고정되어 있지 않다 배열의 길이가 언제든지 늘어나거나 줄어들 수 있기 때문에 JavaScript 배열들은 밀집도가 보장되지 않는다
자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 객체와 연결되어 있고, 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메서드를 상속받아 사용할 수 있게 한다
이러한 부모 객체를 프로토타입(Prototype) 객체 또는 줄여서 프로토타입(Prototype)이라고 한다
MDN에 정의되어 있는 메서드는 Array.prototype.method() 혹은 Array.method() 두 가지 유형이다
전자는 인스턴스 메서드(Instance method), 후자는 정적 메서드(Static method)이다
인스턴스 메서드와 정적 메서드의 가장 큰 차이점은 객체 생성 여부이다
정적 메서드는 클래스 변수와 마찬가지로 객체를 생성하지 않고 클래스명.메서드명으로 호출 가능하다
인스턴스 메서드는 정적 메서드와는 달리, 반드시 객체를 생성한 후에 호출 가능하다
즉, 인스턴스 메서드는 인스턴스가 반드시 존재해야만 사용할 수 있다
Array 인스턴스
모든 Array 인스턴스는 Array.prototype을 상속한다
다른 생성자와 마찬가지로, Array() 생성자의 프로토타입을 수정하면 모든 Array 인스턴스도 수정의 영향을 받는다
예를 들면, 새로운 메서드와 속성을 추가해 모든 Array를 확장할 수 있으므로 폴리필에 쓰인다
그러나 배열 객체에 비표준 메서드를 추가하면 나중에 스스로, 혹은 JavaScript에 기능이 추가될 경우 문제가 될 수 있다
Array.prototype은 그 스스로 Array이다
Array.isArray(Array.prototype); // true
* 폴리필(Polyfill)
폴리필은 웹 개발에서 기능을 지원하지 않는 웹 브라우저 상의 기능을 구현하는 코드를 말한다
인스턴스 메서드(Instance Method)
변경자 메서드
변경자 메서드는 배열을 수정한다
arr.copyWithin(target[, start[, end]])
const array1 = ['a', 'b', 'c', 'd', 'e'];
// 0번째 값에 3번째 값을 넣는다
console.log(array1.copyWithin(0, 3, 4));
// ["d", "b", "c", "d", "e"]
// 1번째 값에 3번째 값을 넣는다
console.log(array1.copyWithin(1, 3));
// ["d", "d", "e", "d", "e"]
arr.fill(value[, start[, end]])
const array1 = [1, 2, 3, 4];
// index 2, index 3에 0을 넣는다
console.log(array1.fill(0, 2, 4));
// [1, 2, 0, 0]
// index 1부터 5를 넣는다
console.log(array1.fill(5, 1));
// [1, 5, 5, 5]
// 배열 전체에 6을 넣는다
console.log(array1.fill(6));
// [6, 6, 6, 6]
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2); // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 5); // [1, 2, 3]
Array(3).fill(4); // [4, 4, 4]
[].fill.call({ length: 3 }, 4); // {0: 4, 1: 4, 2: 4, length: 3}
// 참조에 의한 Object
var arr = Array(3).fill({}); // [{}, {}, {}]
arr[0].hi = "hi"; // [{ hi: "hi" }, { hi: "hi" }, { hi: "hi" }]
arr.pop()
const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];
console.log(plants.pop()); // "tomato"
console.log(plants);
// ["broccoli", "cauliflower", "cabbage", "kale"]
plants.pop();
console.log(plants);
// ["broccoli", "cauliflower", "cabbage"]
arr.push(element1[, ...[, elementN]])
const animals = ['pigs', 'goats', 'sheep'];
const count = animals.push('cows');
console.log(count); // 4
console.log(animals);
// ["pigs", "goats", "sheep", "cows"]
animals.push('chickens', 'cats', 'dogs');
console.log(animals);
// ["pigs", "goats", "sheep", "cows", "chickens", "cats", "dogs"]
a.reverse()
const array1 = ['one', 'two', 'three'];
console.log('array1:', array1);
// array1: ["one", "two", "three"]
const reversed = array1.reverse();
console.log('reversed:', reversed);
// reversed: ["three", "two", "one"]
// 원본 배열을 변형
console.log('array1:', array1);
// array1: ["three", "two", "one"]
arr.shift()
const array1 = [1, 2, 3];
const firstElement = array1.shift();
console.log(array1); // [2, 3]
console.log(firstElement); // 1
arr.unshift([...elementN])
const array1 = [1, 2, 3];
console.log(array1.unshift(4, 5)); // 5
console.log(array1); // [4, 5, 1, 2, 3]
arr.sort([compareFunction])
const months = ['March', 'Jan', 'Feb', 'Dec'];
months.sort();
console.log(months);
// ["Dec", "Feb", "Jan", "March"]
const array1 = [1, 30, 4, 21, 100000];
array1.sort();
console.log(array1);
// [1, 100000, 21, 30, 4]
const korArray1 = ["사과", "키위", "바나나"];
korArray1.sort();
console.log(korArray1);
// [ '바나나', '사과', '키위' ]
array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
const months = ['Jan', 'March', 'April', 'June'];
// index 4에 있는 값을 0개 삭제하고 "Feb"를 추가한다
months.splice(1, 0, 'Feb');
console.log(months);
// ["Jan", "Feb", "March", "April", "June"]
// index 4에 있는 값을 1개 삭제하고 "May"를 추가한다
months.splice(4, 1, 'May');
console.log(months);
// ["Jan", "Feb", "March", "April", "May"]
var myFish = ['angel', 'clown', 'trumpet', 'sturgeon'];
var removed = myFish.splice(0, 2, 'parrot', 'anemone', 'blue');
console.log(myFish);
// ["parrot", "anemone", "blue", "trumpet", "sturgeon"]
접근자 메서드
접근자 메서드는 배열을 수정하지 않고, 기존 배열의 일부에 기반한 새로운 배열 또는 값을 반환한다
array.concat([value1[, value2[, ...[, valueN]]]])
- 기존 배열을 변경하지 않는다
- 추가된 새로운 배열을 반환한다
- 만약 value1 ~ valueN 인자를 생략하면 기존배열의 얕은 복사본을 반환한다
const array1 = ['a', 'b', 'c'];
const array2 = ['d', 'e', 'f'];
const array3 = array1.concat(array2);
console.log(array3);
// ["a", "b", "c", "d", "e", "f"]
// 배열 세 개 이어붙이기
const num1 = [1, 2, 3];
const num2 = [4, 5, 6];
const num3 = [7, 8, 9];
num1.concat(num2, num3);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
// 배열에 값 이어붙이기
const alpha = ['a', 'b', 'c'];
alpha.concat(1, [2, 3]);
// ['a', 'b', 'c', 1, 2, 3]
arr.filter(callback(element[, index[, array]])[, thisArg])
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// Array ["exuberant", "destruction", "present"]
arr.includes(valueToFind[, fromIndex])
const array1 = [1, 2, 3];
console.log(array1.includes(2)); // true
const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // true
console.log(pets.includes('at')); // false
// 대소문자 구분
console.log(("T").includes("t")); // false
arr.indexOf(searchElement[, fromIndex])
const beasts = ['ant', 'bison', 'camel', 'duck', 'bison'];
console.log(beasts.indexOf('bison')); // 1
// index 2부터 시작 => 'camel'부터 0, 1, 2, 3, 4에 'bison' 위치
console.log(beasts.indexOf('bison', 2)); // 4
console.log(beasts.indexOf('giraffe')); // -1
arr.lastIndexOf(searchElement[, fromIndex])
const animals = ['Dodo', 'Tiger', 'Penguin', 'Dodo'];
console.log(animals.lastIndexOf('Dodo')); // 3
console.log(animals.lastIndexOf('Tiger')); // 1
arr.toLocaleString([locales[, options]]);
const array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
const localeString = array1.toLocaleString('en', { timeZone: 'UTC' });
console.log(localeString); // 1,a,12/21/1997, 2:12:00 PM
arr.join([separator])
const elements = ['Fire', 'Air', 'Water'];
console.log(elements.join()); // "Fire,Air,Water"
console.log(elements.join('')); // "FireAirWater"
console.log(elements.join('-')); // "Fire-Air-Water"
arr.toString()
const array1 = [1, 2, 'a', '1a'];
console.log(array1.toString()); // "1,2,a,1a"
const array1 = [1, 'a', new Date('21 Dec 1997 14:12:00 UTC')];
const localeString = array1.toLocaleString('en', { timeZone: 'UTC' });
console.log(localeString); // 1,a,12/21/1997, 2:12:00 PM
const joinedArray = array1.join();
console.log(joinedArray); // 1,a,Sun Dec 21 1997 23:12:00 GMT+0900 (Korean Standard Time)
const toStringArray = array1.toString();
console.log(toStringArray); // 1,a,Sun Dec 21 1997 23:12:00 GMT+0900 (Korean Standard Time)
console.log(joinedArray == toStringArray); // true
arr.slice([begin[, end]])
const animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];
console.log(animals.slice(2));
// ["camel", "duck", "elephant"]
console.log(animals.slice(2, 4));
// ["camel", "duck"]
console.log(animals.slice(1, 5));
// ["bison", "camel", "duck", "elephant"]
console.log(animals.slice(-2));
// ["duck", "elephant"]
console.log(animals.slice(2, -1));
// ["camel", "duck"]
순회 메서드
배열을 처리하면서 호출할 콜백 함수를 받는 메서드 여럿이 존재한다 이런 메서드를 호출하면 배열의 length를 기억하므로, 아직 순회를 끝내지 않았을 때 요소를 더 추가하면 콜백이 방문하지 않는다
arr.entries()
const array1 = ['a', 'b', 'c'];
const iterator1 = array1.entries();
console.log(iterator1.next());
// Object { value: Array [0, "a"], done: false }
console.log(iterator1.next().value);
// Array [0, "a"]
console.log(iterator1.next().value);
// Array [1, "b"]
// for ... of 루프 사용
var a = ['a', 'b', 'c'];
var iterator = a.entries();
for (let e of iterator) {
console.log(e);
}
// [0, 'a']
// [1, 'b']
// [2, 'c']
for(let data of a) {
console.log(data); // // a, b, c
}
arr.keys()
const array1 = ['a', 'b', 'c'];
const iterator = array1.keys();
// key는 index 값이다
for (const key of iterator) {
console.log(key);
}
// 0
// 1
// 2
arr.values()
const array1 = ['a', 'b', 'c'];
const iterator = array1.values();
for (const value of iterator) {
console.log(value);
}
// "a"
// "b"
// "c"
const isBelowThreshold = (currentValue) => currentValue < 40;
const array1 = [1, 30, 39, 29, 10, 13];
console.log(array1.every(isBelowThreshold)); // true
const array2 = [1, 30, 39, 29, 10, 13, 50];
console.log(array2.every(isBelowThreshold)); // false
arr.some(callback[, thisArg])
const array = [1, 2, 3, 4, 5];
// element가 짝수인지 체크
const even = (element) => element % 2 === 0;
console.log(array.some(even)); // true
arr.find(callback[, thisArg])
const array1 = [5, 12, 8, 130, 44];
const found = array1.find(element => element > 10);
console.log(found); // 12
// 배열에서 객체 찾기
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
const newObj = inventory.find(item => item.name === 'cherries');
console.log(newObj); // { name: 'cherries', quantity: 5 }
arr.findIndex(callback(element[, index[, array]])[, thisArg])
const array1 = [5, 12, 8, 130, 44];
const isLargeNumber = (element) => element > 13;
console.log(array1.findIndex(isLargeNumber)); // 3
arr.forEach(callback(currentvalue[, index[, array]])[, thisArg])
const array1 = ['a', 'b', 'c'];
array1.forEach(element => console.log(element));
// "a"
// "b"
// "c"
arr.map(callback(currentValue[, index[, array]])[, thisArg])
const array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
console.log(map1);
// [2, 8, 18, 32]
arr.reduce(callback[, initialValue])
- 누산기 (acc)
- 현재 값 (cur)
- 현재 인덱스 (idx)
- 원본 배열 (src)
const array1 = [1, 2, 3, 4];
const reducer = (previousValue, currentValue) => previousValue + currentValue;
// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer)); // 10
// 5(default 값) + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5)); // 15
var result = array1.reduce((acc, cur, i) => {
console.log(acc, cur, i); // 1 2 1, 3 3 2, 6 4 3
return acc + cur;
}, 5);
result; // 15
const arr = [1, 2];
arr.reduce((acc, cur, i) => {
// reduce는 누적값을 반드시 return 해줘야 한다
return acc;
}, initial);
* initial에 들어갈 수 있는 값
- string
- number -> sum, min, max
- array -> 조건에 맞는 arr를 넣어줄 수 있다 filter와 다르게 조건 여러 개 사용해서 더 다양하게 사용할 수 있다, unique(중복된 애들 찾는 거)
- object -> 학점 구하기
arr.reduceRight(callback[, initialValue])
const array1 = [[0, 1], [2, 3], [4, 5]].reduceRight(
(accumulator, currentValue) => accumulator.concat(currentValue)
);
console.log(array1);
// [4, 5, 2, 3, 0, 1]
const array2 = [1, 3, 4]
const result = array2.reduceRight((acc, curr, i) => {
console.log(acc, curr, i); // 4 3 1, 7 1 0
return acc + curr;
})
console.log(result); // 8
const strArray1 = korArray1.sort((a, b) => a.localeCompare(b));
const strArray2 = korArray1.sort((a, b) => b.localeCompare(a));
console.log(strArray2); // [ '바나나', '사과', '키위' ]
console.log(strArray2); // [ '키위', '사과', '바나나' ]
그 외 메서드
const newArr = arr.flat([depth])
const arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
const arr2 = [1, 2, [3, 4, [5, 6]]];
arr2.flat();
// [1, 2, 3, 4, [5, 6]]
const arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
const arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
const arr5 = [1, 2, , 4, 5];
arr5.flat();
// [1, 2, 4, 5]
// Infinity 값을 주면 depth 없이 평평하게 이어준다 ⭐️
console.log(arr2.flat(Infinity));
// [0, 1, 2, 3, 4]
arr.flatMap(callback(currentValue[, index[, array]])[, thisArg])
let arr1 = [1, 2, 3, 4];
arr1.map(x => [x * 2]);
// [[2], [4], [6], [8]]
arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]
// 한 레벨만 평탄화됨 => flat(1)과 동일
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
정적 메서드(Static Method)
Array.from(arrayLike[, mapFn[, thisArg]])
console.log(Array.from('foo')); // ["f", "o", "o"]
console.log(Array.from([1, 2, 3], x => x + x)); // [2, 4, 6]
function f() {
return Array.from(arguments);
}
f(1, 2, 3); // [1, 2, 3]
* 유사 배열 객체
유사 객체 배열은 배열처럼 보이지만 사실 key가 숫자이고 length 값을 가지고 있는 배열이 아닌 객체다
유사 배열은 전개 연산자나 for … of와 함께 사용할 수 없다
var arr = [1, 2];
var arrLikeObj = {0: 0, 1: 1};
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(arrLikeObj)); // false
* 반복 가능한 객체
- Array
- Map
- Set
- String
- TypedArray
- arguments
+ String은 유사배열 객체이면서 반복 가능한 객체다
Array.of(element0[, element1[, ...[, elementN]]])
인자의 수나 유형에 관계없이 가변 인자를 갖는 새 Array 인스턴스를 만든다
Array.of()와 Array 생성자의 차이는 정수형 인자의 처리 방법에 있다
Array.of(7)은 하나의 요소 7을 가진 배열을 생성하지만 Array(7)은 length 속성이 7인 빈 배열을 생성한다
Array.of(7); // [7]
Array.of(1, 2, 3); // [1, 2, 3]
Array(7); // [ , , , , , , ]
Array(1, 2, 3); // [1, 2, 3]
@ Array.from() vs Array.of() vs Array() 차이 ⚡️
Array.of()에 대한 설명에서 언급했듯이
Array.of(5)은 하나의 요소 5을 가진 배열을 생성하지만 Array(5)은 length 속성이 5인 비어 있는 배열을 생성한다
Array.from()은 유사 배열 객체(array-like object)로부터 배열을 생성하고
Array.of()은 주어진 요소(element)를 가지고 배열을 생성한다
Array.from({length: 5});
// [undefined, undefined, undefined, undefined, undefined]
Array.from("abc");
// ["a", "b", "c"]
Array.from({length: 5}, (v, i) => i);
// [0, 1, 2, 3, 4]
Array.from(["a", "b", "c"], (v, i) => v);
// ["a", "b", "c"]
Array.of(5);
// [5]
Array.of("abc");
// ["abc"]
Array(5);
// [비어 있음 × 5]
Array.isArray()
Array.isArray(obj)
인자가 Array인지 판별한다 Boolean 값을 반환한다
Array.isArray([1, 2, 3]); // true
Array.isArray({foo: 123}); // false
Array.isArray('foobar'); // false
Array.isArray(undefined); // false
// 모두 true 반환
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array('a', 'b', 'c', 'd'));
Array.isArray(new Array(3));
// Array.prototype은 스스로도 배열입니다
Array.isArray(Array.prototype);
// 모두 false 반환
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray({ __proto__: Array.prototype });
인스턴스 메서드 vs 정적 메서드 차이점
- Instance method are methods which require an object of its class to be created before it can be called. Static methods are the methods in Java that can be called without creating an object of class.
인스턴스 메서드는 호출하기 전에 해당 클래스의 개체(인스턴스)를 만들어야 하는 메서드이다 정적 메서드는 클래스 개체(인스턴스)를 생성하지 않고 호출할 수 있는 메서드이다 - Static method is declared with static keyword. Instance method is not with static keyword.
정적 메서드는 정적 키워드 static으로 선언된다 인스턴스 메서드에 정적 키워드가 없다 - Static method means which will exist as a single copy for a class. But instance methods exist as multiple copies depending on the number of instances created for that class.
정적 메서드는 클래스에 대한 단일 복사본으로 존재하는 메서드를 의미한다 그러나 인스턴스 메서드는 해당 클래스에 대해 만들어진 인스턴스 수에 따라 여러 복사본으로 존재한다 - Static methods can be invoked by using class reference. Instance or non static methods are invoked by using object reference.
정적 메서드는 클래스 참조를 사용하여 호출할 수 있다 인스턴스 메서드는 개체 참조를 사용하여 호출된다
ex) Array.from() ↔︎ [1, 2].join("") - Static methods can’t access instance methods and instance variables directly. Instance method can access static variables and static methods directly.
정적 메서드는 인스턴스 메서드와 인스턴스 변수에 직접 액세스할 수 없다 인스턴스 메서드는 정적 변수와 정적 메서드에 직접 액세스할 수 있다
- 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다
생성된 각각의 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수는 서로 다른 값을 유지한다 그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스 변수로 정의해야 한다 - static 메서드는 인스턴스를 생성하지 않아도 사용할 수 있다 static이 붙은 메서드는 클래스가 메모리에 올라갈 때 자동으로 생성되기 때문이다
- static 메서드는 인스턴스 변수를 사용할 수 없다 Static 메서드는 인스턴스 생성 없이 호출 가능하므로 static 메서드가 호출되었을 때, 인스턴스가 존재하지 않을 수도 있다 따라서, static 메서드에서 인스턴스 변수를 사용해서는 안 된다
이와 반대로, 인스턴스 메서드에서는 static이 붙은 멤버들을 사용하는 것이 항상 가능하다
(인스턴스 변수가 존재한다는 것은 static 변수가 이미 메모리에 존재한다는 것을 의미하기 때문이다) - 메서드 안에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없다 반대로 인스턴스 변수를 필요로 하지 않는다면 static을 붙이면 된다 메서드의 호출시간이 짧아지므로 성능이 향상된다
=> static을 안 붙인 메서드(인스턴스 메서드)는 실행 시, 호출되어야 할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸린다
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array