function add(num1, num2) {
console.log("함수 호출");
return num1 + num2;
}
console.log(`두 숫자를 더한 결과는 ${add(10, 15)} 입니다.`); //25
if/else 대신에 if/return 구조를 사용하여 들여쓰기를 최소한으로 줄이는 패턴이다.
유의점은 조건문의 범위 및 순서를 잘 고려하면서 배치하지 않으면 망한다.
//--------기존에 자주 쓰던 패턴-----------
function func(num) {
if (num > 0) {
if (num >= 10) {
console.log("num의 값이 10보다 크거나 같습니다.");
} else {
console.log("num의 값이 0보다 크고 10보다 작습니다.");
}
} else if (num === 0) {
console.log("num의 값 0");
} else {
console.log("num의 값이 0보다 작습니다.");
}
}
func(15);
//-----------[Early Return]-----------
function func(num) {
if (num === 0) return "num의 값이 0입니다.";
if (num < 0) return "num의 값이 0보다 작습니다.";
if (num >= 10) return "num의 값이 10보다 크거나 같습니다.";
return "num의 값이 0보다 크고 10보다 작습니다. ";
}
console.log(func(15));
//num의 값이 10보다 크거나 같습니다.
즉시 실행 함수는 동시에 즉시 실행되는 함수를 의미한다.
함수 리터럴을 () 로 감싼 뒤
바로 실행하는 형태가 일반적.
(function () {
console.log('Hello World');
})();
// Hello World
함수 리터럴
자바스크립트에서 함수를 정의하는 표현식을 "함수 리터럴" 이라고 한다.
함수 리터럴은 아래 4개의 요소로 구성된다.
명칭은 거창하지만, 실제로는 일반적으로 다들 알고 있는 자바스크립트의 함수 선언을 위한 문법을 의미한다.
function add(a, b) {
return a + b
}
아래처럼 이름 없는 함수로 작성하면... 에러 발생.
function (a, b) { return a + b } // Uncaught SyntaxError: Unexpected token
함수 이름은 선택사항이라고 했지만, 함수 이름이 없이 정의하는 경우에는 아래 조건이 충족되어야 한다.
그러니까, 결국 다음과 같이 되어야 한다
const add = function (a, b) { return a + b };
(function(a, b) { return a + b })(1, 2); // 3
위와 같은 함수 리터럴 표현식을 통해 즉시 실행 함수를 정의할 수 있다.
그리고 즉시 실행 함수라는건 위의 예제코드들처럼
즉시 실행되어 값으로 평가되는 함수를 의미한다.
함수는 어디에서 호출되는지에 따라 순서가 달라진다.
범위, 변수 혹은 함수가 갖게 되는 유효범위
const num = 10; //전역 스코프
function print() {
const num = 100; //지역 스코프
console.log(`지역스코프 : ${num}`); //지역스코프 : 100
}
print();
console.log(`전역스코프 : ${num}`); //전역스코프 : 10
같은 블록에서만 접근 가능한 범위.
여기서 블록이란, 중괄호{} 내부를 가리킨다.
function print() {
for (let i = 0; i < 10; i++) {
console.log(`블록스코프 : ${i}`);
}
console.log(i); //ERROR
}
print();
let
과 var
차이점
let
은 같은 이름의 변수를 재선언하면 에러
var
는 오류 없이 가장 마지막에 작성된 값으로 변수의 값이 변경된다.
var
로 선언된 변수는 기존에 선언했던 변수는 무시되면서 같은 이름의 변수를 여러번 선언할 수 있기 때문에 더 유연하다.
그러나 자바스크립트 특성 상 특정 변수가 이미 선언되어 있는지 여부를 파악하기 어렵고, 어디서 어떻게 사용되었는지 파악이 힘들어지면서 에러 발생 확률이 높아진다는 치명적인 단점이 존재한다.
고로 중복 선언이 불가능 한 let
선호
let num1 = 10;
var num2 = 20;
num1 = 100;
num2 = 200;
console.log(num1); //100
console.log(num2); //200
//--[case 01: let]----
let num1 = 10;
let num1 = 100;
console.log(num1); //ERROR: SyntaxError
//--[case 02: var]----
var num2 = 20;
var num2 = 200;
console.log(num2); //200
포괄하는 범위가 다른 걸 느낄 수 있다.
function print() {
for (var i = 0; i < 10; i++) {
console.log(`블록스코프 : ${i}`);
}
console.log(i); //10
}
print();
그러나 for문 안에 선언된 변수가 var일 경우,
해당 for문이 종료되더라도 같은 함수 내부에서 계속 접근 가능하기 때문에 여러오류 발생 시킬 수 있다.
인터프리터가 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것을 의미한다.
이로 인해 변수선언/함수선언이 해당 스코프의 최상단으로 끌어 올려진 것 같은 현상.
var
로 선언한 변수의 경우 호이스팅 시 undefined로 변수를 초기화한다.
반면, let
과 const
로 선언한 변수의 경우 호이스팅 시 변수를 초기화하지 않는다.
console.log(num); //undefined
var num = 10;
// js 엔진이 위의 2줄 코드를 다음과 같이 해석함.
var num; //변수의 선언문만 해당 스코프의 최상단으로 올려 해석하는 방식
console.log(num); //indefined
num = 10;
/* let, const */
console.log(num); //ERROR
let num = 10;
console.log(num); //ERROR
const num = 10;
TDZ(Temporal Dead Zone, 일시적인 사각지대) : 변수 사용하는 것을 허용하지 않는 공간
호이스팅이 발생하지 않는 것이 아니라, 변수스코프 맨 위에서 변수의 초기화가 완료될 때까지 TDZ라는 공간에 있기 때문에 호이스팅이 발생하지 않는 것처럼 보인다.
var
는 변수 생성한 후 바로 메모리에 변수의 공간을 미리 할당을 한다. 그러나 let
과 const
는 그렇지 않기 때문에 초기화될 때까지, 메모리 공간이 확보되지 않은 상태가 되어서 해당 키워드로 생성된 변수들은 변수를 사용할 수 없는 공간(TDZ)에 들어가게 된다.
다시말해 "변수의 선언과 초기화를 분리한 후, 선언만 코드의 최상단으로 옮기는" 것.
따라서 변수를 정의하는 코드보다 사용하는 코드가 앞서 등장할 수 있다. 다만 ⚠ 선언과 초기화를 함께 수행하는 경우, 선언 코드까지 실행해야 변수가 초기화된 상태가 됨을 주의
참고 글 01) [JavaScript] 호이스팅(Hoisting)이란?
참고 글 02) JavaScript 변수와 함수 호이스팅(Hoisting)에 대해 알아보자
화살표형 함수란?
자바스크립트에서 함수는 객체다. 함수의 파라미터로서 객체를 전달할 수 있다는 말이다.
그렇듯이 다른 함수에 파라미터로 넘겨준(=전달하는) 함수를 콜백함수라 칭한다.
객체 중괄호 안에 있는 값은 '객체 프로퍼티' 또는 '객체 속성' 이라고 부른다.
let person = new Object();
console.log(person); //{}
객체 프로퍼티는 왼쪽은 key 값, 오른쪽은 value 값으로 구성됨.
key 값을 통해 객체를 찾기 때문에 객체 프로퍼티의 key 값은 고유해야 한다.
그러나 객체 프로퍼티의 value 값은 어떠한 자료형으로 작성되어도 상관없다.
let person = {
name: "홍길동"
};
console.log(person); //{}
. 이용해 객체의 값을 꺼냄
객체 이름 뒤에 .을 찍고 객체의 프로퍼티에 key 값을 작성하면 key값에 해당하는 value의 값을 가져온다.
let person = {
name: "mac",
age: 20,
pet: "cat"
};
console.log(person.name); //mac
console.log(person.age); //20
console.log(person.pet); //cat
객체 이름 뒤에 대괄호([]) 안에 key 값을 작성한다.
대괄호 안에 큰 따옴표("")로 문자열임을 명시해 줘야 함.
let person = {
name: "mac",
age: 20,
pet: "cat"
};
console.log(person["name"]); //mac
console.log(person["age"]); //20
console.log(person["pet"]); //cat
보통 객체 프로퍼티 값을 꺼낼 때는 점 표기법을 많이 사용한다.
그러나 다음과 같은 겨웅는 괄호 표기법을 이용한다.
다음은 객체의 key 값을 매개변수가 결정하는 경우의 예제다.
let person = {
name: "mac",
age: 20,
pet: "cat"
};
const getValue = (key) => { //매개변수에 key 값 받기
console.log(person[key]); //key 값에 해당하는 person 객체의 프로퍼티 value 값을 출력하는 함수
};
//호이스팅 방지를 위해 제일 마지막에 호출문 작성.
getValue("name"); //person 객체의 프로퍼티 key 값 중 name을 인수로 넘김.
//mac
점 표기법, 괄호 표기법 둘 다 사용 가능하다.
let person = {
name: "mac",
age: 20,
pet: "cat"
};
person.phone = "010-123-123"; //점 표기법으로 phone 프로퍼티 추가
person["height"] = 180; // 괄호 표기법으로 key에 대한 정보 생성
console.log(person);
/*
[output]
{name: "mac", age: 20, pet: "cat", phone: "010-123-123", height: 180}
name: "mac"
age: 20
pet: "cat"
phone: "010-123-123"
height: 180
*/
해당 프로퍼티에 원하는 값 입력.
person.age = 25;
person["pet"] = "dog";
/*
[output]
{name: "mac", age: 25, pet: "dog"}
name: "mac"
age: 25
pet: "dog"
*/
앞에서 const
로 선언된 상수는 수정이 불가능 하다고 했지만,
객체의 프로퍼티 값 수정할 때는 상수로 선언된 객체의 프로퍼티도 변경 가능.
why?
: 객체 프로퍼티 값 수정이 해당 객체 자체를 수정하는 행위가 아니기 때문에 가능하다.
객체는 생성될 때 고유한 id를 갖게 되는데 프로퍼티 갑 수정은 id 값에 영향을 미치지 않으므로 const든, let이든 상관없다.
const person = {
name: "mac",
age: 20,
pet: "cat"
};
person.age = 22;
person["pet"] = "rabbit";
console.log(person);
/*
[output]
{name: "mac", age: 22, pet: "rabbit"}
name: "mac"
age: 22
pet: "rabbit"
*/
person객체 자체에 새로운 프로퍼티를 저장하려 하면 객체의 고유한 id를 변경하는 것이므로 read-only 라는 에러 발생
const person = {
name: "mac",
age: 20,
pet: "cat"
};
person = {
pet: "dog"
};
console.log(person);
delete
키워드 사용
const person = {
name: "mac",
age: 20,
pet: "cat"
};
delete person.pet; //{name: "mac", age: 20}
delete person["age"]; //{name: "mac"} name: "mac"
console.log(person);
key값 = print, value값 = "hello world"를 출력하는 함수인 프로퍼티 작성하는 예시
const person = {
name: "mac",
age: 20,
pet: "cat",
print: function () {
console.log("hello world");
}
};
person.print(); //print의 value 값으로 저장된 함수 호출(점 표기법)
person["print"](); // " (괄호 표기법)
console.log(person);
/*
[output]
> hello world
> {name: "mac", age: 20, pet: "cat", print: ƒ print()}
name: "mac"
age: 20
pet: "cat"
print: ƒ print() {}
<constructor>: "Function"
name: "Function"
*/
위와 같이 객체 프로퍼티 값이 함수일 경우 이를 '메서드' 라고 부름.
메서드는 객체 내부 프로퍼티에 접근할 수 있다.
다음은 person객체의 print 매서드에서 key 값이 name인 프로퍼티의 value 값 출력하는 예시다.
const person = {
name: "mac",
age: 20,
pet: "cat",
print: function () {
console.log(`제 이름은 ${this.name} 입니다`); //제 이름은 mac 입니다
}
};
person.print();
person["print"]();
console.log(person);
this
키워드 이용해 자신이 속해있는 객체를 가리킬 수 있다.
메서드 생성 시 주의할 점
화살표형 함수가 아닌function
키워드를 통해 함수를 선언해야한다.
또한, this 키워드를 통해 객체 프로퍼티 값을 꺼내올 수 있다.
단,화살표형 함수는 자신이 속한 객체를 가리키기 못하기 때문에 this 키워드와 맞지 않음.
객체 생성 방법과 마찬가지로, new 키워드 사용.
let arr = new Array();
let arr1 = new Array(1, 2, 3);
let arr2 = new Array(3);
console.log(arr); //[]
console.log(arr1); //[1, 2, 3]
console.log(arr2); //[undefined, undefined, undefined]
대괄호('[ ]') 이용
let arr = [];
let arr1 = [1, 2, 3];
let arr2 = [3];
console.log(arr); //[]
console.log(arr1); //[1,2,3]
console.log(arr2); //[3]
배열 리터럴을 통해 배열 생성 후 값을 넣게 되면, 배열요소로 순서대로 저장된다.
객체 프로퍼티와 같이 타입 상관없이 모든 요소를 넣을 수 있다.
let arr = [
{ name: "MAC" },
1,
"array",
function () {
console.log("hello,world");
},
null,
undefined
];
console.log(arr);
//[Object, 1, "array", ƒ (), null, undefined]
배열은 순서 있는 요소들의 집합으로, 객체와 달리 데이터를 구분하는 key 값이 존재하지 않는다.
대신 데이터가 위치하는 순서인 index를 통해 배열 요소에 접근 가능.
let arr = [1, "hello", null];
console.log(arr[0]); //1
console.log(arr[1]); //hello
console.log(arr[2]); //null
내장함수 push
메서드 사용한다.
해당 배열의 맨 마지막 요소로 추가한다.
그리고, unshift
메서드는 해당 배열의 맨 앞 요소로 추가한다.
/* push */
arr.push(4);
console.log(arr);
//[1, "hello", null, 4]
/* unshift */
arr.unshift(0);
console.log(arr);
//[0, 1, "hello", null, 4]
index으로 배열에 직접 접근해서 수정 가능하다.
배열은 객체로 분류되는 자료형에 속하므로, 객체와 동일한 이유로 const
로 배열 선언해도 수정 가능하다.
arr[0] = 5;
arr[2] = undefined;
console.log(arr);
//[5, "hello", undefined]
pop 배열의 맨 마지막 요소 삭제 가능하다.
shift 배열의 맨 앞 요소 삭제 가능하다.
/* pop */
arr.pop();
console.log(arr); // [1, "hello"]
/* shift */
arr.shift();
console.log(arr); //["hello", null]
for문은 특정 변수의 초기값과 조건문을 비교하고 해당 조건문이 참이라면 변수의 값을 증감 시키는 반복문.
while문은 단순하게 괄호 안의 조건문만 확인하여 반복한다.
다음은 while문 사용 예시이다.
let i = 1;
while(i < 6) {
console.log(i);
i++;
}
다음은 for문을 이용해 배열의 모든 요소에 접근하는 반복문의 예시다.
let arr = [1, 2, 3, 4, 5];
for (let i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
반복문을 통해 배열뿐만 아니라 객체 프로퍼티도 접근 가능하다.
다만, 객체 프로퍼티를 순회하기 위해서는 해당 객체를 배열 형태로 변경해줘야 한다.
자바스크립트의 Object 객체 매서드로, 매개변수로 받은 객체의 key를 모두 찾아 배열 형태로 반환한다.
let person = {
name: "mac",
age: 20,
height: 100
};
//01)
let newArr = Object.keys(person);
//02)
for (let i = 0; i < newArr.length; i++) {
let nowKey = newArr[i];
console.log(`key: ${nowKey}, value: ${person[nowKey]}`);
}
console.log(Object.keys(person));
/*
[OUTPUT]
> key: name, value: mac
> key: age, value: 20
> key: height, value: 100
> ["name", "age", "height"] //Object.keys
*/
01) 객체를 key 값으로만 이루어진 객체로 변경.
02) for문 사용한 객체 프로퍼티 순환.
: person 객체프로퍼티의 key 값을 nowKey라는 변수를 통해 얻어올 수 있고, 괄호표기법을 통해 대괄호 안에 nowKey 변수를 작성하여 해당 key 값에 해당하는 value 값을 얻었다.
또한, newArr 라는 요소가 person 객체의 key 값을 알고 있기 때문에 객체의 프로퍼티를 모두 출력할 수 있었다.
매개변수로 객체 넘기면 해당 객체의 value를 모두 찾아 배열로 반환한다.
let person = {
name: "mac",
age: 20,
height: 100
};
let newArr = Object.values(person);
for(let i = 0; i < newArr.length; i++){
console.log(`value: ${newArr[i]}`);
}
console.log(Object.values(person));
/*
[OUTPUT]
> value: mac
> value: 20
> value: 100
> ["mac", 20, 100] //Object.values
*/
key값 없이 바로 객체프로퍼티의 value 값 확인 가능하다 .
객체 받으면 key와 value 쌍의 배열을 반환한다.
key와 value 값을 배열에 담아 새로운 배열로 반환해주는 메서드다.
let person = {
name: "mac",
age: 20,
height: 100
};
let newArr = Object.entries(person);
for (let i = 0; i < newArr.length; i++) {
console.log(`key: ${newArr[i][0]}, value: ${newArr[i][1]}`);
}
console.log(Object.entries(person));
/*
[OUTPUT]
> key: name, value: mac
> key: age, value: 20
> key: height, value: 100
> [Array(2), Array(2), Array(2)] //Object.entries
*/
만약 value: ${newArr[i][0]} 일 경우,
key: name, value: name
key: age, value: age
key: height, value: height
만약 value: ${newArr[i][2]} 일 경우,
key: name, value: undefined
key: age, value: undefined
key: height, value: undefined
더 자세한 건 '이차원배열' 을 찾아보자
주로 배열의 모든 요소에 접근해야할 때 사용된다.
let arr = [1, 2, 3, 4, 5];
for (let i of arr) {
console.log(i);
}
주로 객체에서 사용된다.
객체를 배열로 변환하는 과정없이 한번에 객체의 모든 프로퍼티에 접근 가능하다.
let person = {
name: "mac",
age: 20,
height: 200
};
for (let key in person) {
console.log(`key: ${key}, value: ${person[key]} `);
}
/*
[OUTPUT]
key: name, value: mac
key: age, value: 20
key: height, value: 200
*/