
어떤 정보에 이름을 붙여서 사용한다.
let은 선언 후에도 다른 값으로 변경 가능하다.
const는 절대로 바뀌지 않는 상수를 입력할 때 사용한다.
개념 정리
typeof는 다른 개발자가 사용한 변수의 타입을 알아내거나 API 통신 등을 통해 받아온 데이터들을 타입에 따라 다른 방식으로 처리해야 할 때 사용한다.
문자형끼리 더하면 이어지고, 문자형과 숫자형을 더하면 모두 문자형으로 취급된다.(자동 형변환)
사용자와 상호작용할 수 있는 대화상자이다.
단점: 스크립트 일시 정지, 스타일링 X
String() // 문자형으로 변환
Number() // 숫자형으로 변환
Boolean() // 불린형으로 변환
형변환이 필요한 이유: 서로 다른 자료형이면 의도치 않은 동작이 발생할 수 있기 때문이다.
의도를 가지고 형변환을 하는 것을 명시적 형변환 이라 한다.
그냥 외워야 한다.
Boolean() 형변환은 false 케이스만 기억하면 된다.
숫자 0
빈 문자열 ""
null
undefined
NaN
이 외에는 모두 true를 반환한다.
나머지를 어디에 사용?
홀수 : X % 2 = 1
짝수 : Y % 2 = 0
나머지가 0은 짝수, 1은 홀수 처럼 구분할 때 사용한다.
X % 5 = 0 ~ 4 사이의 값만 반환
어떠한 값이 들어와도 5를 넘기면 안될 때
거듭제곱은 곱하기 두번 연달아서 사용한다.
연산자 우선순위는 실제 수학과 같다.
비교 연산자는 boolean을 반환한다.
비교 연산자로 나온 값을 조건문에 이용한다.
case가 다양할 경우, 간결하게 작성할 수 있다.
case 조건 하나가 충족되면, 뒤에도 전부 출력되므로 모든 case마다 break 해주어야 한다.
|| (OR)
&& (AND)
! (NOT)
OR는 첫번째 true를 발견하는 즉시 평가를 멈춘다.
AND는 첫번째 false를 발견하는 즉시 평가를 멈춘다.
첫 번째 평가에서 빠르게 걸러낼수록 성능이 향상된다.
우선순위는 AND가 OR 보다 높다.
for문의 괄호는 순서대로 for(초기값; 조건; 반복문 한번 실행 후 작업) 으로 이루어진다.
do while 문은 코드를 실행하고 조건을 체크하므로 적어도 한번은 실행된다.
명확한 횟수가 정해져 있으면 for문, 아니면 while문
반복문은 코드를 줄이기 위한 핵심적인 방법이다.
function /*함수*/ sayHello /*함수명*/(name) /*매개변수 or 인수*/ {
// 매개변수는 여러개 입력 가능(name1, name2, name3)
// 매개변수와 인수는 완전히 동일한 의미는 아니다.
console.log(`Hello, ${name}`);
}
// 함수명 뒤에 괄호를 붙여서 호출할 수 있다.
// 매개변수가 필요하다면 괄호 안에 넣어준다.
sayHello("Mike");
어디서나 접근 가능한 변수를 전역 변수(global varable)라 한다.
함수 내부에 선언된 변수는 지역 변수(local varable)이다. (함수 내부에서만 사용 가능하다.)
전역 변수와 지역 변수는 서로 동일한 이름으로 선언할 수 있고 서로 간섭받지 않는다.
매개변수로 받은 값은 복사된 후, 함수에 지역변수가 된다.
전체 서비스에서 공통으로 바라봐야 하는 변수를 제외하고는 지역 변수를 쓰는 습관을 들이는 것이 좋다. (전역 변수가 많아지면 관리가 힘들어진다.)
return이 없는 함수 or return만 있는 함수는 undefined를 반환한다.
return 오른쪽에 있는 값을 반환하고 즉시 함수를 종료하기 때문에 함수 종료 목적으로 사용하기도 한다.
몇 가지 팁
한 번에 한 작업만 수행한다. (여러 작업을 한다면 더 잘게 나눠서 함수 작성)
읽기 쉽고 어떤 동작인지 알 수 있게 네이밍한다.
function sayHello() {
console.log("Hello");
}
sayHello();
어디서든 호출 가능 (호출을 선언문 위에 올려도 동작함)
js는 위에서부터 한 줄씩 코드를 읽으면서 실행하는데, 이렇게 순차적으로 실행되고 즉시 결과를 반환하는 프로그래밍 언어를 인터프리터 언어(Interpreted language) 라 한다.
그렇다면 왜 호출을 선언문 위에 올려도 동작하는가?
js는 실행 전 코드의 모든 함수 선언문을 찾아 생성해놓는다.
눈에 보이는 건 아래에 있지만, 실제 함수를 사용할 수 있는 범위는 위로 올라가게 되는 것이다. 이를 호이스팅(hoisting) 이라 한다.
(코드 위치가 실제로 올라간다는 것은 아니다)
let sayHello = function () {
console.log("Hello");
};
sayHello();
let add = (num1, num2) => {(
num1 + num2;
)};
function이 없어지고 화살표로 작성
return이 없어지고 소괄호로 작성 가능
return문이 한 줄이라면 괄호도 생략 가능
인수가 하나라면 인수쪽 괄호 생략 가능
인수가 없는 함수라면 괄호 생략 불가능
return문이 존재한다 해도, 이전 코드가 여러줄 있을 경우는 소괄호를 사용할 수 없다.
// 객체 생성
const superman = {
name: "clark",
age: 33,
};
// 접근
superman.name; // 'clark'
superman["age"]; // 33
// 추가
superman.gender = "male";
superman["hairColor"] = "black";
// 삭제
delete superman.hairColor;
// 단축 프로퍼티
const name = "clark";
const age = 33;
const superman = {
name, // name : name
age, // age : age
gender: "male",
};
// in 연산자
"birthDay" in superman; // false
"age" in superman; //true
// for ... in 반복문
for (let key in superman) {
console.log(key);
console.log(spuerman[key]);
}
존재하지 않는 프로퍼티에 접근한다면 undefined가 나온다.
in 연산자를 사용하면 프로퍼티를 확인할 수 있다. (어떤 값이 넘어올 지 확신할 수 없을 때 사용한다)
for ... in 반복문을 사용하면 객체를 순회하면서 값을 얻어올 수 있다.
const superman = {
name: "clark",
age: 33,
// fly 함수가 superman 객체의 메소드이다!
// fly() 로 줄여서 작성할 수 있다 (function 키워드 생략 가능)
fly: function () {
console.log("날아갑니다");
},
};
superman.fly(); // 날아갑니다
메소드 : 객체 프로퍼티로 할당된 함수
객체와 메소드의 관계
const user = {
name: "Mike",
sayHello: function () {
// 이 방식은 문제가 발생할 수 있다!
// user 대신에 this를 사용해야 한다!
console.log(`Hello, I'm ${user.name}`);
},
};
// 여기의 user가 sayHello의 this가 된다!
user.sayHello();
this는 실행하는 시점, 즉 런타임에 결정된다.
메소드를 화살표 함수로 선언하면 동작이 전혀 달라진다.
화살표 함수는 일반 함수와는 달리 자신만의 this를 가지지 않는다.
화살표 함수 내부에서 this를 사용하면, 그 this는 외부에서 값을 가져온다.
객체의 메소드를 작성할 때는 화살표 함수를 쓰지 않는 것이 좋다.
let boy = {
name: "Mike",
sayHello: () => {
console.log(this); // 전역 객체를 가리킨다
},
};
// this != boy
boy.sayHello();
브라우저 환경 전역 객체 : window
Node.js 전역 객체 : global
순서가 있는 리스트(list)
배열을 탐색할 때는 고유 번호를 사용한다. 이를 인덱스(index)라 한다. 인덱스는 0부터 시작한다.
let students = ["철수", "영희", "영수"];
console.log(students[0]); // 철수
console.log(students[1]); // 영희
console.log(students[2]); // 영수
// 수정
students[0] = "민정";
console.log(students[0]); // 민정
// 배열의 길이
students.length;
// push() : 배열 끝에 추가
students.push("기영");
console.log(students); // ["민정", "영희", "영수", "기영"]
//pop() : 배열 끝 요소 제거
students.pop();
console.log(students); // ["민정", "영희", "영수"]
// unshift() : 배열 앞에 추가
students.unshift("철수");
console.log(students); // ["철수", "민정", "영희", "영수"]
// shift() : 배열 앞에 제거
students.shift();
console.log(students); // ["민정", "영희", "영수"]
배열의 특징
// 예제
let arr = [
"민수", // string
3, // number
false, // boolean
{
// object
name: "Mike",
age: 30,
},
// function
function () {
console.log("TEST");
},
];
length : 배열의 길이(배열이 가지고 있는 요소의 갯수를 반환)
배열의 메소드
push() : 배열 맨 뒤에 요소를 추가해 주는 메소드
pop() : 배열 맨 뒤 요소를 제거해 주는 메소드
unshift() : 배열 맨 앞에 요소를 추가하는 메소드
shift() : 배열 맨 앞에 요소를 제거하는 메소드
push와 unshift는 여러 요소를 한번에 추가할 수도 있다.
배열을 사용하는 이유 중 하나는 반복을 위해서이다.
length를 이용하여 배열의 길이를 알고 있으므로, for문을 사용할 수 있다.
for ... of문은 for문보다는 간단하지만 인덱스를 못 얻는다는 단점이 있다.
// for문
let days = ["월", "화", "수"];
for (let index = 0; index < days.length; index++) {
console.log(days[index]);
}
// for ... of
let days = ["월", "화", "수"];
// 배열 days를 돌면서 요소를 day라는 이름으로 접근할 수 있다.
for (let day of days) {
console.log(day);
}
var, let의 차이점
var는 한번 선언된 변수를 다시 선언할 수 있다.
var는 선언하기 전에 사용할 수 있다.
호이스팅 : 스코프 내부 어디서든 변수 선언은 최상위에 선언된 것 처럼 행동되는 것
var name; // 호이스팅 (hoisting)
console.log(name); // undefined (선언은 호이스팅되지만, 할당은 호이스팅되지 않기 때문이다)
name = "Mike";
// let과 const도 호이스팅이 된다
console.log(name); // ReferenceError
let name = "Mike";
let과 const도 호이스팅되지만 var처럼 동작하지 않는 이유?
TDZ 때문이다. (let, const는 TDZ의 영향을 받는다)
TDZ 영역에 있는 변수들은 사용할 수 없기 때문이다.
할당을 하기 전에는 사용할 수 없다. 이는 코드를 예측 가능하게 하고 잠재적인 버그를 줄일 수 있다.
console.log(name); // TDZ
const name = "Mike"; // 함수 선언 및 할당
console.log(name); // 사용 가능
var (함수 스코프)
let (블록 스코프)
const (블록 스코프)
블록 스코프는 모든 코드 블록 내에서 선언된 변수는 코드 블록 내에서만 유효하며 외부에서는 접근할 수 없다. (즉, 지역 변수이다)
함수 스코프는 함수 내에서 선언된 변수만 지역 변수가 된다.
객체 리터럴 형식
let user = {
name: "Mike",
age: 30,
};
개발을 하다보면 비슷한 객체를 만들어야 하는 상황이 생긴다. (회원, 상품 등)
이럴때 사용하는 것이 생성자 함수이다.
// 첫 글자는 대문자로 시작하여 함수를 만든다.
// 이름과 나이를 인자로 받아서 this에 넣어주고 있다.
function User(name, age) {
this.name = name;
this.age = age;
}
// new 연산자를 사용하여 함수를 호출한다.
// 각기 다른 변수명으로 3번 연달아 호출하였다.
let user1 = new User("Mike", 30);
let user2 = new User("Jane", 22);
let user3 = new User("Tom", 17);
어떤 식으로 동작하는가?
function User(name, age) {
// this = {} : 2. 일단 빈 객체를 만들고 this에 할당한다.
// 3. 함수의 본문을 실행하면서 this에 프로퍼티들을 추가한다.
this.name = name;
this.age = age;
// return this; : 4. 마지막으로 this를 반환한다.
// 실제로 2, 4 번은 코드상에 존재하지 않는다.
// new를 붙여 실행하는 순간 이런 식으로 알고리즘이 동작한다.
}
// 1. new 함수명() 실행.
new 함수명();
어떠한 함수라도 new를 붙여 실행하는 순간 저 알고리즘으로 동작하게 된다.
메소드 추가
function User(name, age) {
this.name = name;
this.age = age;
this.sayName = function () {
// console.log의 this는 user5를 뜻한다.
console.log(this.name);
};
}
let user5 = new User("Han", 40);
user5.sayName(); // 'Han'
let a = "age";
const user = {
name: "Mike",
[a]: 30, // age :30
};
Object.assign() : 객체 복제
// 이 user 변수에는 객체 자체가 들어가 있는 것이 아니라
// 객체가 저장되어있는 메모리 주소인 객체에 대한 참조값이 저장된다.
const user = {
name: "Mike",
age: 30,
};
// 이런 식으로 복사하게 되면 참조값만 들어가게 된다.
// 이렇게 되면 cloneUser에서 이름을 수정하면 user에서도 이름이 같이 수정된다. (하나의 객체를 두 변수가 접근하기 때문!)
const cloneUser = user; // XXXXXX : 이 방법으론 복제되지 않는다.
// 첫 번째 빈 객체는 초기값이다.
// 두 번째 매개변수부터 들어온 객체들이 초기값에 병합된다.
const newUser = Object.assign({}, user);
// 총 3개의 프로퍼티를 가지게 된다.
const newUserGender = Object.assign({ gender: "male" }, user);
// 키가 같다면 덮어씌우게 된다.
const newUserRename = Object.assign({ name: "Tom" }, user);
const user = {
name: "Mike",
};
const info1 = {
age: 30,
};
const info2 = {
gender: "male",
};
// info1, 2가 user에 병합된다.
Object.assign(user, info1, info2);
Object.keys() : 객체 프로퍼티의 키를 배열로 반환한다.
const user = {
name: "Mike",
age: 30,
gender: "male",
};
Object.keys(user); // ['name', 'age', 'gender']
Object.values() : 객체 프로퍼티의 값을 배열로 반환한다.
const user = {
name: "Mike",
age: 30,
gender: "male",
};
Object.values(user); // ['Mike', '30', 'male']
Object.entries() : 키와 값을 모두 배열로 반환
const user = {
name: "Mike",
age: 30,
gender: "male",
};
Object.entries(user);
// 키와 값을 쌍으로 묶어서 배열로 반환해준다.
<!-- [
["name", "Mike"],
["age", 30],
["gender", "male"],
] -->
Object.fromEntries() : 키와 값 배열을 객체로 반환
const arr = [
["name", "Mike"],
["age", 30],
["gender", "male"],
];
Object.fromEntries(arr);
// 객체로 반환됨
<!-- {
name: "Mike",
age: 30,
gender: "male",
}; -->
// 프로퍼티의 키가 숫자와 불린형으로 작성되어도
const obj = {
1: "1입니다.",
false: "거짓",
};
// 모두 문자형으로 변환되어 반환된다.
Object.keys(obj); // ["1", "false"]
// 실제 접근할 때에도 문자형으로 접근이 가능하다.
obj["1"]; // "1입니다."
obj["false"]; // "거짓"
// Symbol은 유일한 식별자이다.
const a = Symbol();
const b = Symbol();
// 자료형은 달라도 내용만 일치하면 되는 동등 연산자로 확인
a == b; // false
// 일치 연산자로 확인
a === b; // false
console.log(a); // Symbol()
console.log(b); // Symbol()
// Symbol을 만들 때 설명을 붙일 수 있다.
// 문자열을 전달해 줄 수 있는데, 이 문자열은 심볼 생성에 어떠한 영향도 미치지 않는다.
const id = Symbol("id");
const id2 = Symbol("id");
id == id2; // false
id === id2; // false
console.log(id); // Symbol(id)
console.log(id2); // Symbol(id)
// Symbol을 객체의 키로 사용
const id = Symbol("id");
const user = {
name: "Mike",
age: 30,
[id]: "myid", // 계산된 프로퍼티 키로 넣음
};
console.log(user); // {name: "Mike", age: 30, Symbol(id): "myid"}
console.log(user[id]); // "myid"
Object.keys(user); // ["name", "age"]
Object.keys, values, entries, for ... in 문은 키가 Symbol형인 프로퍼티를 건너뛴다.
그럼 이걸 어디에 쓸 수 있나?
특정 위치에 원본 데이터는 건드리지 않고 속성을 추가할 수 있다.
다른 사람이 만들어 놓은 객체에 자신만의 속성을 추가해서 덮어 씌워버리면 안되고, 그렇다고 엄청 길거나 이상한 네이밍을 하는 것도 좋지 못하다.
Symbol.for() : 전역 심볼 (코드 어디서든 사용할 수 있다.)
전역 변수처럼 이름이 같으면 같은 객체를 가리켜야 할 때 사용한다.
하나의 심볼만 보장받을 수 있다.
없으면 만들고, 있으면 가져오기 때문이다.
Symbol 함수는 매번 다른 Symbol 값을 생성하지만, Symbol.for 메소드는 하나의 Symbol을 생성해서 여러 모듈이 키를 통해 같은 Symbol을 공유할 수 있다.
const id1 = Symbol.for("id");
const id2 = Symbol.for("id");
// for없이 생성했던 것과는 다르게 true가 출력된다.
id1 === id2; // true
// 이름을 얻고 싶다면 keyFor()
Symbol.keyFor(id1); // id
const id = Symbol("id 입니다.");
id.description; // "'id' 입니다."
전역 심볼이 아니라면 keyFor를 사용할 수 없다. 대신 description으로 이름을 알 수 있다.
숨겨진 Symbol key 보는 법
const id = Symbol("id");
const user = {
name: "Mike",
age: 30,
[id]: "myid",
};
// 심볼만 골라서 확인
Object.getOwnPropertySymbols(user); // [Symbol(id)]
// 심볼형 키를 포함한 객체의 모든 키를 보여준다.
Reflect.ownKeys(user); // ["name", "age", Symbol(id)]
toString() : 숫자를 문자열로 바꾼다. 괄호 안에 숫자를 넣으면, 그 숫자의 진법으로 변경된다.
let num = 10;
let num2 = 255;
num.toString(); // "10"
num.toString(2); // "1010"
num2.toString(16); // "ff"
Math.PI : 원주율
Math.ceil() : 올림
let num1 = 5.1;
let num2 = 5.7;
Math.ceil(num1); // 6
Math.ceil(num2); // 6
Math.floor() : 내림
let num1 = 5.1;
let num2 = 5.7;
Math.floor(num1); // 5
Math.floor(num2); // 5
Math.round() : 반올림
let num1 = 5.1;
let num2 = 5.7;
Math.round(num1); // 5
Math.round(num2); // 6
toFixed() : 소숫점 자릿수
// 요구사항 : 소수점 둘째 자리까지 표현 (셋째 자리에서 반올림)
let userRate = 30.1234;
// 숫자를 인수로 받아 그 숫자만큼 소수점 이하 갯수에 반영한다.
userRate.toFixed(2); // "30.12" : 2번째 자리까지 보여준다
userRate.toFixed(0); // "30" : 0은 정수만 보여준다
userRate.toFixed(6); // "30.123400" : 나머지는 0으로 채운다
// toFixed는 문자열을 반환하므로 Number를 이용하여 숫자로 변경
Number(userRate.toFixed(2)); // 30.12
isNaN() : NaN을 판단한다
let x = Number("x"); // NaN
// x가 NaN인지 검사하는 방법은 isNaN이 유일하다.
x == NaN; // false
x === NaN; // false
NaN == NaN; // false
isNaN(x); // true
isNaN(3); // false
parseInt() : 문자열을 숫자로 변경한다. Number와 다른 점은 문자가 혼용되어 있어도 동작한다는 점이다. 소수점은 무시하고 정수만 반환한다.
let margin = "10px";
parseInt(margin); // 10
Number(margin); // NaN
let redColor = "f3";
// parseInt는 숫자까지만 읽고 반환하기 때문에 앞이 문자라면 NaN을 반환한다.
parseInt(redColor); // NaN
// 두 번째 인수에 16을 전달해서 16진수로 변환
parseInt(redColor, 16); // 243
// 문자열 "11"을 2진수로 변환하여 10진수로 변환 : 3
parseInt("11", 2); // 3
parseFloat() : parseInt와 동일하게 동작하지만 부동소숫점을 반환한다.
let padding = "18.5%";
parseInt(padding); // 18
parseFloat(padding); // 18.5
Math.random() : 0 ~ 1 사이의 무작위 숫자를 생성한다.
// 1 ~ 100 사이의 임의의 숫자를 뽑고 싶다면?
Math.floor(Math.random() * 100) + 1;
// 100까지의 숫자이므로 *100, 5까지라면 *5
// 최소값이 1이기 때문에 +1
Math.max() / Math.min() : 괄호 안의 인수들 중 최대값 / 최소값을 구한다.
Math.abs() : 절대값을 구한다. (abs는 absolute의 약자이다)
Math.pow(n, m) : n의 m승 값, 즉 거듭제곱값을 구한다. (pow는 power의 약자이다)
Math.sqrt() : 제곱근을 구한다. (sqrt는 square root의 약자이다)
Math.max(0, 1, 2, 3); // 3
Math.min(0, 1, 2, 3); // 0
Math.abs(-1); // 1
Math.pow(2, 10); // 1024 : 2의 10승
Math.sqrt(16); // 4
length : 문자열 길이 (회원가입 시 아이디 길이 제한에 사용됨)
toUpperCase() / toLowerCase() : 모든 글자를 대문자 / 소문자로 변경
str.indexOf(text) : 문자를 인수로 받아 몇 번째에 위치하는지 알려준다.
let desc = "안녕하세요.";
desc.length; //6
// 특정 위치에 접근
desc[2]; // '하'
desc[4] = "용"; // 배열과 다르게 한 글자만 바꾸는 것은 허용되지 않는다.
// 아무 변화 없음!
let desc = "Hi guys. Nice to meet you.";
desc.toUpperCase(); // "HI GUYS. NICE TO MEET YOU."
desc.toLowerCase(); // "hi guys. nice to meet you."
desc.indexOf("to"); // 14
desc.indexOf("man"); // -1 : 찾는 문자가 없다면 -1이 반환됨
// 포함된 문자가 여러개라도 첫번째 위치만 반환된다.
if (desc.indexOf("Hi") > -1) {
// indexOf는 0을 반환하고 if문에서 0은 false
// 그러므로 이 문장은 출력되지 않는다.
// 그래서 항상 -1보다 큰가 로 비교해야 한다.
console.log("Hi가 포함된 문장입니다.");
}
str.slice(n, m) : n부터 m까지 문자열을 반환한다. n은 시작점이고 m은 없으면 문자열 끝까지, 양수면 그 숫자까지(포함하지 않음), 음수면 끝에서부터 센다.
str.substring(n, m) : n과 m 사이 문자열을 반환한다. n과 m을 바꿔도 동작하므로, 그냥 두 숫자 사이의 문자열을 반환한다고 생각하면 된다. 음수를 허용하지 않는다. (음수는 0으로 인식한다)
str.substr(n, m) : n부터 시작해서 m개의 문자를 반환한다.
str.trim() : 앞,뒤의 공백을 제거한다. (사용자로부터 입력받을 때 사용됨)
str.repeat(n) : 문자열을 n번 반복한다.
let desc = "abcdefg";
desc.slice(2); // "cdefg"
desc.slice(0, 5); // "abcde"
desc.slice(2, -2); // "cde"
desc.substring(2, 5); // "cde"
desc.substring(5, 2); // "cde"
desc.substr(2, 4); // "cdef"
desc.substr(-4, 2); // "de"
let desc = " coding ";
desc.trim(); // "coding"
let hello = "hello!";
hello.repeat(3); // "hello!hello!hello!"
문자열 비교
1 < 3; // true
// 아스키 코드에 의해서 결정
"a" < "c"; // true
// 아스키 코드 반환
"a".codePointAt(0); // 97
// 반대로 숫자 코드를 안다면 문자를 얻을 수 있다.
String.fromCodePoint(97); // "a"
arr.splice(n, m) : n부터 시작하여 m개를 지우는 메소드
arr.splice(n, m, x) : 지운 뒤에 x의 자리에 있는 요소를 추가하는 메소드
arr.splice() : 삭제된 요소를 반환할수도 있다. (메소드를 사용할 때 값을 반환하는데, 그 값이 삭제된 요소의 배열이다)
// n 시작 m 개 삭제
let arr = [1, 2, 3, 4, 5];
arr.splice(1, 2);
console.log(arr); // [1,4,5]
// 지운 뒤 x의 자리에 있는 요소 추가
let arr = [1, 2, 3, 4, 5];
arr.splice(1, 3, 100, 200);
console.log(arr); // [1,100,200,5]
let arr = ["나는", "철수", "입니다"];
arr.splice(1, 0, "대한민국", "소방관");
// 0과 1 사이에 삽입된다.
// ["나는", "대한민국", "소방관", "철수", "입니다"]
// 삭제된 요소 반환
let arr = [1, 2, 3, 4, 5];
let result = arr.splice(1, 2);
console.log(arr); // [1,4,5]
console.log(result); // [2,3]
arr.slice(n, m) : n부터 m까지 반환 (m은 포함하지 않고 바로 앞자리를 의미한다. 작성하지 않으면 배열 끝까지를 의미한다.)
arr.concat(arr2, arr3 ...) : 인자로 주어진 배열이나 값들을 기존 배열에 합쳐서 새로운 배열을 반환한다.
// slice
let arr = [1, 2, 3, 4, 5];
arr.slice(1, 4); // [2,3,4]
// 괄호 안이 비어있다면 배열이 복사된다.
let arr2 = arr.slice();
console.log(arr2); // [1,2,3,4,5]
// -------------------------------------
// concat
let arr = [1, 2];
arr.concat([3, 4]); // [1,2,3,4]
arr.concat([3, 4], [5, 6]); // [1,2,3,4,5,6]
arr.concat([3, 4], 5, 6); // [1,2,3,4,5,6]
arr.forEach(fn) : 배열의 반복을 for 문이나 for of 문을 사용했는데, forEach로도 반복할 수 있다.
let users = ["Mike", "Tom", "Jane"];
users.forEach((item, index, arr) => {
// 1. Mike, Tom, Jane / 2. 0, 1, 2 / 3. users
});
arr.indexOf / arr.lastIndexOf : 문자열의 indexOf와 사용법이 같다. 발견하면 해당 요소의 인덱스를 반환하고, 없으면 -1을 반환한다.
arr.includes() : 인덱스를 확인할 필요 없이 포함하는지 확인한다.
let arr = [1, 2, 3, 4, 5, 1, 2, 3];
arr.indexOf(3); // 2
// 인수가 2개인 경우, 두번째 인수는 시작 위치를 의미한다.
arr.indexOf(3, 3); // 7
// 끝에서부터 탐색
arr.lastIndexOf(3); // 7
// -------------------------------------
let arr = [1, 2, 3];
arr.includes(2); // true
arr.includes(8); // false
arr.find(fn) / arr.findIndex(fn) : indexOf처럼 찾는다는 의미는 동일하지만 복잡한 연산이 가능하도록 함수를 전달할 수 있다.
(짝수 찾기, 성인 찾기 등)
첫 번째 true값만 반환하고 끝난다. 만약 없으면 undefined를 반환한다.
findIndex는 해당 인덱스를 반환한다. 없으면 -1을 반환한다.
arr.filter(fn) : find는 하나만 찾았지만 filter는 만족하는 모든 요소를 배열로 반환한다. find와 사용법은 동일하다.
arr.reverse() : 배열 역순으로 재정렬 (최근 가입된 유저부터 보여준다거나 게시판에서 가장 최근에 작성된 글 순서로 정렬할 때 자주 사용된다.)
// forEach
let arr = ["Mike", "Tom", "Jane"];
arr.forEach((name, index) => {
console.log(`${index + 1}. ${name}`);
// 1. Mike
// 2. Tom
// 3. Jane
});
// find
let arr2 = [1, 2, 3, 4, 5, 6];
const result = arr2.find((item) => {
// 짝수 찾기, return값이 true일 때 멈추므로 2만 반환된다.
return item % 2 === 0; // 2
});
console.log(result);
// findIndex
// 객체가 들어있는 배열의 경우는 indexOf로는 찾기 힘들다.
let userList = [
{ name: "Mike", age: 30 },
{ name: "Jane", age: 27 },
{ name: "Tom", age: 10 },
];
// 미성년자 찾기
const result2 = userList.findIndex((user) => {
if (user.age < 19) {
return true;
}
return false;
});
console.log(result2); // 2
// filter
let arr3 = [1, 2, 3, 4, 5, 6];
const result3 = arr2.filter((item) => {
// 짝수 찾기, filter는 모든 요소를 반환한다.
return item % 2 === 0; // 2
});
console.log(result3); // [2, 4, 6]
let arr = [1, 2, 3, 4, 5];
arr.reverse(); // [5,4,3,2,1]
let userList = [
{ name: "Mike", age: 30 },
{ name: "Jane", age: 27 },
{ name: "Tom", age: 10 },
];
// 매번 나이를 확인하는 것이 아닌 isAdult 라는 프로퍼티를 추가한 새로운 배열을 만들기로 함
let newUserList = userList.map((user, index) => {
return Object.assign({}, user, {
id: index + 1,
isAdult: user.age > 19,
});
});
console.log(newUserList);
let arr = ["안녕", "나는", "철수야"];
let result = arr.join(" ");
console.log(result); // 안녕 나는 철수야
const users = "Mike,Jane,Tom,Tony";
const result = users.split(",");
console.log(result); // ["Mike", "Jane", "Tom", "Tony"];
let user = {
name: "Mike",
age: 30,
};
let userList = ["Mike", "Tom", "Jane"];
console.log(typeof user); // object
console.log(typeof userList); // object
console.log(Array.isArray(user)); // false
console.log(Array.isArray(userList)); // true
arr.sort(fn) : 배열을 재정렬함 (배열 자체가 변경되니 주의)
let arr = [27, 8, 5, 13];
arr.sort((a, b) => {
// 결과가 음수면(a가 더 작으면) a를 앞으로 보낸다.
// 0을 반환하면 제자리
// 결과가 양수면(b가 더 작으면) b를 앞으로 보낸다.
return a - b;
});
console.log(arr); // [5, 8, 13, 27]
보통 이런 함수를 만들어놓고 사용하기 보다는 Lodash같은 라이브러리를 많이 사용한다. 숫자, 문자, 객체 전부 원하는 기준으로 정렬해준다.
_.sortBy(arr);
arr.reduce(fn) : (누적 계산값, 현재값) => { return 계산값 };
arr.reduceRight() : reduce와 동일하나 배열 우측부터 실행한다는 차이점이 있다.
// 배열의 모든 수 합치기
let arr = [1, 2, 3, 4, 5];
// for, for of, forEach
let result = 0;
arr.forEach((num) => {
result += num;
});
console.log(result); // 15
// arr.reduce()
const result2 = arr.reduce((prev, cur) => {
return prev + cur;
// 초기값 설정 : 0 / 작성하지 않으면 배열의 첫 번째가 들어가게 된다.
}, 0);
console.log(result2); // 15
// 성인만 골라서 새로운 배열을 생성
let userList = [
{ name: "Mike", age: 30 },
{ name: "Tom", age: 10 },
{ name: "Jane", age: 27 },
{ name: "Sue", age: 26 },
{ name: "Harry", age: 42 },
{ name: "Steve", age: 60 },
];
let result = userList.reduce((prev, cur) => {
if (cur.age > 19) {
// 19살보다 나이가 크면 기존 배열에 push 해주고 return / 이대로 반복
prev.push(cur.name);
}
return prev;
// 초기값은 빈 배열
}, []);
참고자료 :
https://www.youtube.com/watch?v=KF6t61yuPCY&t=2359s
https://www.youtube.com/watch?v=4_WLS9Lj6n4&t=4s