자바스크립트의 타입(Type)은 한국말로 자료형으로 해석되기도 합니다. 변수의 타입은 다양한 데이터를 용도에 맞게 쓰기 위해서 사용합니다. 예를 들어 1234와 같은 숫자는 number type으로, ‘jeju’와 같은 문자는 string type으로 나누어 각각의 데이터 형에 맞는 여러 기능들을 지원합니다. 컴퓨터에 저장되는 값은 둘 다 2진수임에도 두 개의 + 연산(1 + 2, “hello” + “world”
)은 다른 결과를 가지게 됩니다. 이처럼 변수의 타입은 컴퓨터에게 해당 데이터가 앞으로 어떻게 처리될지를 정하게 합니다.
타입은 단순한 데이터를 저장하는 원시타입, 그리고 객체로서 저장되는 참조타입으로 크게 구별할 수 있습니다.
💡 보통 프로그래밍 언어에서는 변수의 자료형과 함께 변수를 선언하지만 자바스크립트는 자료형을 함께 쓸 필요는 없습니다.String str = new String("Java"); // Java의 변수 선언식
System.out.println(str);
원시타입의 특징은 값이 변경 불가능하며 값을 변수에 저장하거나 전달할 때 값에 의한 전달를 한다는 것입니다. 때문에 원시 값을 다른 변수에 할당 할때는 값의 참조가 저장되는 것이 아닌, 값 자체(가리키고 있는 값을 따라가서 실제 메모리에 저장된 주소)가 복사되어 저장됩니다.
let str1 = 'hello';
let str2 = str1;
console.log(str2); // 'hello'
str1 = 'world';
console.log(str2); // str2에 할당된 값은 여전히 'hello' 입니다.
string, number, bigint, boolean, undefined, symbol, null이 원시타입에 속합니다.
🧐 원시타입은 str2입장에서 str1의 값을 바꿀 수는 없습니다. 참조타입은 str2입장에서 str1의 값을 바꿀 수 있습니다.나 진짜 이해가 안돼....
객체타입의 특징은
let arr1 = [1, 2, 3];
let arr2 = arr1;
console.log(arr2);
arr1[0] = 10;
// arr1 = [10, 20];
console.log(arr2);
// 비교해보세요.
let value1 = 10;
let value2 = value1;
console.log(value2);
value1 = 20;
console.log(value2);
💡 원시타입도 메서드가 존재했던것 같은 느낌적인 느낌이 있습니다!
맞습니다. 원시타입도 프로퍼티와 메서드를 사용했었죠? 자바스크립트는 원시타입도 마치 객체타입처럼 사용할 수 있게 autoboxing 이라는 과정을 거치게 됩니다.
이런 과정을 거치는 이유는 원시타입도 객체타입처럼 사용할 수 있게 함으로써 일관적인 사용 경험을 사용자에게 제공하기 위해서입니다.
let val = 'hello!';
console.log(val.toUpperCase());
// 위의 코드가 내부적으로는 아래처럼 실행됩니다. 이것이 바로 autoboxing 입니다.
let val = 'hello!';
let temp = new String('hello!');
console.log(temp.toUpperCase());
temp = null;
### 배열 (Array)
배열(Array)은 데이터를 순서대로 저장하는 객체입니다. 하나의 데이터를 표현하는 원시타입과 달리 여러개의 데이터를 한 변수에 저장할 수 있기 때문에 데이터를 추가하거나, 제거, 정렬, 검색 등 다양한 작업을 수행할 수 있도록 여러가지 메소드를 제공합니다.
배열의 특징
배열은 빈 배열로 생성하거나 요소가 포함된 배열로 생성할 수 있습니다.
const arr = [];
const arr = [1, 2, 3];
const arr2 = new Array(4, 5, 6);
const arr2 = new Array(3);
배열은 숫자를 사용하여 값에 접근할 수 있습니다. 이때 숫자는 값의 순서를 의미하며, 이 순서를 인덱스(index), 그리고 배열안에 존재하는 값을 원소(elements)라고 부릅니다. 심지어 존재하지 않는 원소에도 접근이 가능합니다.
const arr = [1, 2, 3];
// 배열 안의 원소에 접근하기 위해서는 인덱스 번호를 이용합니다.
console.log(arr[0]); // 1
console.log(arr[1]); // 2
console.log(arr[2]); // 3
console.log(arr[3]); // ??
배열은 가지고 있는 원소의 길이를 나타내는 length 프로퍼티를 가지고 있습니다. (문자열에서도 사용했었죠?)
const myArray = [1, 2, 3, 4, 5];
console.log(myArray.length); // 5
배열은 배열 안에 다른 배열을 포함할 수 있습니다. 이러한 배열을 다차원 배열이라고 합니다.
const arr2 = [
[1, 2],
[3, 4],
[5, 6]
];
console.log(arr[0][0]);
console.log(arr[2][1]);
arr2 배열은 배열안에 세개의 배열을 원소로 가지고 있습니다. 이러한 배열을 2차원 배열이라고 합니다.
const arr3 = [
[
[1, 2],
[3, 4]
],
[
[5, 6],
[7, 8]
]
];
console.log(arr[0][1][0]);
console.log(arr[1][0][1]);
위와 같은 코드로 배열안의 배열안의 배열인 3차원 배열도 만들어 볼 수 있습니다.
배열의 메소드
push() 메소드는 배열의 끝에 요소를 추가하고 길이를 반환합니다, pop() 메소드는 배열의 마지막 요소를 꺼내어 반환합니다. 꺼낸 요소는 배열에서 제외됩니다.
const arr = [1, 2, 3];
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
arr.pop();
console.log(arr); // [1, 2, 3]
shift() 메소드는 배열에서 첫 번째 요소를 꺼내고 반환합니다, unshift() 메소드는 배열의 첫 번째 요소로 새로운 요소를 추가합니다
const myArray = ["사과", "바나나", "수박"];
myArray.shift();//[바나나,수박]
console.log(myArray);
myArray.unshift("오이", "배");//[오이,배,바나나,수박
console.log(myArray);
splice() 메소드는 배열의 요소를 추가, 제거 또는 교체합니다.
메소드는 3개의 전달인자를 받습니다. 첫 번째 인자는 삭제나 추가를 시작할 인덱스입니다. 두 번째 인자는 삭제할 요소의 개수입니다. 세 번째 인자 부터는 추가할 요소들입니다. 추가할 요소가 없다면 생략할 수 있으며 이때는 요소를 삭제만 하게됩니다.
const arr = [1, 2, 3];
arr.splice(1, 0, 4);
console.log(arr); // [1, 4, 2, 3]
arr.splice(2, 1, 5);
console.log(arr); // [1, 4, 5, 3]
🤔 엥? 그런데 const는 상수를 정하는거 아냐? 어떻게 splice같은 방법으로 변경할 수 있는거야??
😎 메모리에 할당되어있는 데이터의 주소까지 변하게 하지는 않잖아! 그렇기 때문에 근본적인 부분은 변경하지는 않는거지!
slice() 메소드는 배열에서 요소들을 추출하여 새로운 배열로 반환하는 메서드입니다.
메소드는 2개의 전달인자를 받습니다. 첫 번째 인자는 추출을 시작할 인덱스입니다. 두 번째 인자는 추출을 끝낼 인덱스입니다. 추출할 요소는 첫 번째 인자에서 시작하여, 두 번째 인자에서 바로 이전 요소까지입니다. 두 번째 인자는 생략 가능하며, 생략하거나 배열의 길이보다 큰 값을 전달하면 배열의 끝까지 추출합니다.
const myArray = ["apple", "banana", "cherry", "durian", "elderberry"];
console.log(myArray.slice(1, 4));
console.log(myArray.slice());
console.log(myArray.slice(0, 10));
ex) slice(1,4) : 1이상 4 미만!
ex) slice() : 전체 다!
sort() 메소드는 배열의 요소를 정렬하는데 사용됩니다. 메소드를 호출하면 배열을 변경하며, 정렬된 배열을 반환합니다.
const avengers = ['아이언맨', '스파이더맨', '헐크', '토르'];
console.log(avengers.sort());
잘 작동하고 있습니다! 그럼 원소의 값을 숫자형으로 바꾸면 어떨까요??
const nums = [3, 1, 8, 6];
console.log(nums.sort());
const nums2 = [23, 5, 1000, 42];
console.log(nums2.sort());
숫자를 정렬하려고 하면 의도와는 다르게 정렬이 되는데요,
이때 정렬 방식은 원소를 문자열로 전환한 후에 유니코드 포인트(https://en.wikipedia.org/wiki/List_of_Unicode_characters)의 순서대로 변환하기 때문입니다.(포인트 : 문자에 부여한 고유한 16진수 숫자값)
숫자형 데이터 정렬의 이러한 단점을 해결하기 위해 비교 함수(compareFunction)를 사용할 수 있습니다.
비교 함수가 제공되면 원소의 순서는 비교 함수의 반환 값에 따라 정렬됩니다.
비교 함수의 두 인자 a, b를 비교해서(즉, 빼서) 0보다 작은 수 즉, 음수가 나오면 a를 앞으로 위치하고, 두 인자를 뺐는데 0보다 큰 양수가 나오면 b를 앞으로 위치합니다. 0이 나오면 위치를 변경하지 않습니다.
코드로 살펴보겠습니다.
const num3 = [13, 9, 10];
num3.sort(function (a, b) {
console.log('a: ' + a, 'b: ' + b);
return a - b;
});
/**
"a: 9"
"b: 13" // a - b는 음수임으로 a를 앞으로 => [**9**, **13**, 10]
"a: 10"
"b: 9" // a - b는 양수임으로 b를 앞으로 => [**9**, 13, **10**]
"a: 10"
"b: 13" // a - b는 음수임으로 a를 앞으로 => [9, **10, 13**]
"a: 10"
"b: 9" // a - b 는 양수임으로 b를 앞으로 => [**9**, **10,** 13]
*/
비교 함수가 제공되지 않으면 요소를 문자열로 변환하고 유니 코드 코드 포인트 순서로 문자열을 비교하여 정렬됩니다.
💡 Tim sort 알고리즘 JavaScript 의 sort 메소드가 원소를 정렬하는 방법은 Tim sort 알고리즘이라고 합니다.(Tim Peters라는 이름의 개발자가 만들었습니다.) Tim sort는 합병 정렬(Merge sort)과 삽입 정렬(Insertion sort)의 아이디어를 결합한 알고리즘으로 매우 안정적으로 동작하기 때문에 파이썬과 자바 등 다른 언어에서도 널리 사용되는 방법입니다.데이터를 여러 개의 덩어리로 분할하고, 이 덩어리들을 삽입 정렬 알고리즘으로 정렬한 다음, 합병 정렬 알고리즘을 이용해 정렬된 덩어리들을 하나로 합칩니다. 이렇게 분할하고 정렬하는 과정에서, 이미 정렬된 데이터를 인식하고 이를 활용함으로써 평균적인 수행 시간을 크게 줄일 수 있습니다.
참고 : https://d2.naver.com/helloworld/0315536
forEach() 메소드는 배열의 각 요소에 대해 주어진 함수를 실행합니다. 이 때, 함수는 인자로 배열 요소, 인덱스를 받습니다. forEach() 메소드는 배열의 요소를 순환하면서 해당 요소를 함수로 전달하고, 이 함수가 각 요소에 대해 실행됩니다. 즉, 배열 내에 들어있는 원소의 갯수많큼 반복된다는 뜻이죠?ㅎㅎ
const arr = ['참외', '키위', '감귤'];
arr.forEach(function(item, index) {
console.log(item, index);
arr[index] = index;
});
// 결과
// 참외 0
// 키위 1
// 감귤 2
forEach() 메소드는 배열의 각 요소에 대해 특정 작업을 수행할 때 사용됩니다. 예를 들어, 배열의 각 요소를 이용하여 다른 배열을 만들거나, 요소를 삭제하거나, 값을 변경하는 등의 작업을 수행할 수 있습니다.
const avengers = ['spiderman', 'ironman', 'hulk', 'thor'];
const newAvengers = [];
avengers.forEach(function (item) {
newAvengers.push('💖' + item + '💖');
});
map() 메소드는 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 새로운 배열로 반환합니다.
const arr = [1, 2, 3];
const newArr = arr.map(function(item, index) {
return item * index;
});
console.log(newArr);
map() 메소드의 첫 번째 인자로는 배열의 각 요소를 처리할 함수를, 두번째는 요소의 인덱스를 전달합니다. 이 함수는 배열의 각 요소를 매개변수로 받아 처리한 후, 그 결과를 반환합니다.
💡 forEach()와 map()은 별로 다르지 않아보여요! 맞습니다. forEach()와 map()은 둘 다 배열의 각 요소에 대해 주어진 함수를 실행합니다. 하지만 forEach 메소드의 경우 반환값이 없지만 map 메소드는 새로운 배열을 반환한다는 차이가 있습니다. 이러한 차이점은 배열의 원소를 변경하여 새로운 배열을 반환하고자 할때 더 잘 드러납니다.아직 배우지 않았지만 아래처럼 배열 안에 객체에서 데이터를 뽑는 형태로도 사용합니다.
const data = [
{
"_id": "642ba3980785cecff3f39a8d",
"index": 0,
"age": 28,
"eyeColor": "green",
"name": "Annette Middleton",
"gender": "female",
"company": "KINETICA"
},
{
"_id": "642ba398d0fed6e17f2f50c9",
"index": 1,
"age": 37,
"eyeColor": "green",
"name": "Kidd Roman",
"gender": "male",
"company": "AUSTECH"
},
{
"_id": "642ba39827d809511d00dd8d",
"index": 2,
"age": 39,
"eyeColor": "brown",
"name": "Best Ratliff",
"gender": "male",
"company": "PRISMATIC"
}
];
const ages = data.map((item) => item.age);
filter() 메소드는 기존의 배열에서 특정 조건을 만족하는 요소들만 추출하여 새로운 배열을 만듭니다.
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const newArr = arr.filter(function(el) {
return el % 2 === 0;
});
console.log(newArr);
const arr11 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const newArr = arr11.filter(el => el % 2 === 0);
console.log(newArr);
filter() 메소드는 배열에서 특정한 숫자나 날짜 등의 필요한 정보를 가진 원소만 추출할 때 매우 유용한 메소드입니다.
요소가 포함이 되어 있으면 true 아니면 false를 반환합니다.
const arr1 = ['hello', 'world', 'hojun']
arr1.includes('world')
const arr1 = ['hello', 'world', 'hojun']
arr1.includes('leehojun')
const arr1 = ['hello', 'world', 'hojun']
arr1.includes('jun')
객체는 앞서 살펴본 배열처럼 여러개의 데이터를 한 변수에 저장할 수 있는 자료형입니다. 차이점은 배열이 값에 접근하기 위해서는 배열 생성시 자동으로 부여되는 인덱스 번호를 이용해야 했지만, 객체는 특별한 키(key)를 통해 원하는 값(value)에 접근 할 수 있는 키-값 쌍으로 이루어져 있다는 점 입니다.
객체의 특징
객체의 리터럴 표현은 중괄호 {}를 사용하여 생성합니다. 객체는 key-value 쌍으로 이루어져 있으며, 각 key와 value는 콜론(:)으로 구분됩니다. 예를 들어, 다음과 같이 babaYaga 객체를 생성할 수 있습니다.
그리고 이러한 키 값 쌍을 합쳐서 자산(properties)이라 표현합니다. 만약 프로퍼티 값이 함수인 경우에는 메소드라고 부릅니다.
const babaYaga = {
name: "John Wick",
age: 53,
from: "벨라루스",
askingHim: function(){
console.log("Yeah, I'm thinking I'm back!");
}
};
또한 최신 문법을 사용하면 function 키워드 없이 메소드를 등록할 수 있습니다.
const babaYaga = {
name: "John Wick",
age: 53,
from: "벨라루스",
askingHim(){
console.log("Yeah, I'm thinking I'm back!");
}
};
객체의 속성값에 접근하기 위해서는 객체 이름 + 점 연산자 + 접근하고자 하는 값의 key를 입력합니다. 객체의 속성 이름이 변수명 규칙을 지켰다면, 대괄호([])를 사용하여 속성에 접근할 수도 있습니다.
console.log(`${babaYaga.name} from ${babaYaga.from}`);
console.log(`${babaYaga['name']} from ${babaYaga['from']}`);
객체에 속성을 추가하기 위해서는 객체 이름 뒤에 점(.)과 새로운 속성 이름을 입력하고, 새로운 값을 할당합니다.
babaYaga.job = "Killer";
객체에서 속성을 삭제하려면 delete 키워드를 사용합니다.
delete babaYaga.job;
in 연산자를 이용해 특정 프로퍼티가 객체안에 존재하는지 알 수 있습니다.
console.log('age' in babaYaga);
console.log('mercy' in babaYaga);
객체의 메소드
hasOwnProperty() 메소드는 객체가 특정 프로퍼티를 가지고 있는지를 나타내는 불리언 값을 반환합니다.
```jsx
const aespa = {
members: ['카리나', '윈터', '지젤', '닝닝'],
from: '광야',
sing: function(){
return "적대적인 고난과 슬픔은 널 더 popping 진화시켜!"
}
};
console.log(aespa.hasOwnProperty('itzy'));
console.log(aespa.hasOwnProperty('from'));
```
객체의 반복을 위해 만들어진 기능입니다. 주로 객체 안의 프로퍼티들에 접근하여 어떠한 키와 값을 가지는지 살펴보고 싶거나, 조건에 따라 값을 수정해야 할 경우 사용합니다.
```jsx
for (const variable in object) {
// ...
}
```
in 앞의 값에는 매번 반복마다 다른 속성이름(Value name)이 `변수(variable)`로 지정됩니다. in 뒤의 값에는 반복작업을 수행할 객체를 지정합니다.
```jsx
const person = {
name: '재현',
age: 20,
gender: 'male'
};
for (let key in person) {
console.log(`${key}: ${person[key]}`);
}
```
<aside>
💡 for … in 문 안에서 처리되는 프로퍼티들은 반드시 순서대로 반복되지 않습니다. 만약 처리 과정에 순서가 중요하다면 일반적인 반복문을 이용해 처리하는것을 권장합니다.
</aside>
keys(), values()
Object.keys() 메소드는 객체의 속성 이름(key)들을, Object.values() 메소드는 객체의 속성 값(value)들을 배열로 반환합니다. keys 메소드는 IE9 버전부터 지원하며, values 메소드는 IE를 지원하지 않습니다.
console.log(Object.keys(aespa));
console.log(Object.values(aespa));
💡 Object의 정체
위의 예시에서 갑자기 keys 메소드 앞에 Object 라는 객체가 나타났습니다! 이 객체는 사용자가 생성한 객체가 아니라 자바스크립트 안에 원래 내장되어 있는 객체입니다.
자바스크립트를 만들어낸 개발자들이 사용자가 언어를 편하게 사용할 수 있도록 여러가지 유용한 값들과 메소드를 미리 만들어둔 것이죠. 앞서서 배운 Math 객체와 같은 개념이라고 보시면 되겠습니다.