해당 포스트는 JavaScript의 기초 문법을 정리한 알쓸신잡 포스트입니다.
1. 포스팅 작성 이유
우선 저는 Git Blog를 만들면서 JavaScript 언어를 처음 사용해봤습니다.
블로그를 만들면서도 JS에 대한 공부가 필요하다고 느꼈지만, 정확한 JS 문법과 동작 과정을 공부하는 것보다 실제로 코드를 작성하면서 기능을 구현하는 것이 저에게 더욱 매력적으로 다가왔습니다.
이제는 어느정도 구현도 마쳤으니, JS 문법과 동작과정을 공부하면서 파편화된 지식을 조금 더 정립하고자 해당 포스트를 작성하게 되었습니다.
2. JavaScript 알쓸신잡 목차
이제부터는 공부한 내용을 하나씩 정리하면서 포스트를 작성해보고자 합니다.
1. 호이스팅
2. 표현식
3. JS는 숫자를 어떻게 인식할까?
4. 백틱
5. Null 병합 연산자
6. 중첩 함수
7. 화살표 함수
8. 콜백 함수
9. 객체
10. 형변환
11. Truthy & Falsy 그리고 단락 평가
3. JavaScript 알쓸신잡
3-1. 호이스팅
JavaScript가 제공하는 호이스팅이란 JavaScript 파일 내에서 함수나 표현식이 하단부에 선언되어있음에도 상단에 선언되어있는 것처럼 동작하도록 도와주는 기능입니다. 이러한 기능은 JS 엔진의 구동 방식에 기초하여 제공됩니다.
우선 JS 엔진은 모든 범위의 스코프를 탐색하여 유효한 함수나 표현식에 대한 정보를 미리 수집합니다. 이로인해 특정 함수가 실행되는 시점에 JS 엔진은 다른 함수나 표현식에 대한 정보를 알고 있기 때문에 정상적으로 동작할 수 있습니다.
우리가 기억해야하는 부분은 let, const, var의 변수 생성 과정입니다.
간단히 정리해보면 아래와 같습니다.
1. var은 선언과 초기화가 거의 동시에 진행되지만 let과 const는 선언과 초기화가 분리되어 진행된다.
2. let과 const는 실질적인 값을 만나기 전까지는 메모리 할당이 되지 않는다. - TDZ (Temporal Dead Zone) 구간에 놓여있다.
즉, 메모리 할당이 되지 않는 let과 const로 선언된 변수는 사용자가 기대하는 호이스팅 기능이 정상적으로 동작하지 않음을 알 수 있습니다.
위 그림을 통해 알 수 있는 점은 score는 정상적으로 50이라는 변수를 출력하지만 (호이스팅 O),
level은 TDZ에 존재하기 때문에 에러가 발생함을 확인할 수 있습니다. (호이스팅 X)
[Feat. 함수 표현식]
위 그림을 통해 알 수 있는 점은 fun이라는 변수에 funcA()라는 함수가 표현식으로써 할당되어 있습니다.
하지만, 실제로 funcA()를 호출해보면 에러가 발생합니다. 그 이유는 funcA()가 함수 선언식이 아니라 표현식이기 때문에 단독으로 사용할 수 없기 때문입니다.
3-2. 표현식
위에서 호이스팅 관련 내용을 정리하는 부분에서 표현식이라는 내용에 대해서 잠깐 언급한 바 있습니다.
JavaScript에서 표현식이란 변수에 저장할 수 있는 값을 의미합니다.
이 부분에서 우리가 알아야할 부분은 아래와 같습니다.
1. 조건문과 반복문은 표현식이 아니다. (값으로써 변수에 저장될 수 없다.)
2. 함수 선언문은 표현식이다.
3. 조건문은 표현식이 아니지만, 삼항연산자는 표현식에 해당한다.
간단한 예시는 아래와 같습니다.
var level = function () {}; // 표현식
const temp = 1; // 표현식
var test = temp === 1 ? true : false; // 표현식
3-3. JS는 숫자를 어떻게 인식할까?
JavaScript는 모든 숫자를 실수로 인식합니다.
즉, 아래와 같은 코드가 성립합니다.
const test1 = 1;
const test2 = 1.0;
const value = test1 === test2 ? true : false;
console.log(value); // true 출력
즉, 1과 1.0을 동일한 수로 인식합니다.
3-4. 백틱
백틱이란 `를 이용하여 변수를 저장하는 방법을 의미합니다. 예시는 아래와 같습니다.
const name = "정성엽";
const value = `aaa
bbb ${name}
ccc
`;
console.log(value);
위 코드의 결과는 아래 사진과 같습니다.
즉, 백틱을 사용하여 변수를 저장하면 (1) 줄바꿈을 인식시킬 수 있고 (2) 템플릿 리터럴 문법을 이용하여 동적으로 변수를 지정할 수 있다는 특징이 있습니다.
3-5. Null 병합 연산자
존재하지 않는 값 (undefined, null)이 아닌 값을 추려내는 연산자로 ‘??’의 형태를 가집니다.
코드 사용 예시는 아래와 같습니다.
const value1;
const value2 = 10;
const test = value1 ?? value2; // value1은 undefined이므로 value2 값인 10이 할당됨
3-6. 중첩 함수
JS에서는 함수안에 함수를 정의할 수 있습니다. 당연히 함수 내부에서 정의된 함수는 지역 스코프를 가지기 때문에 외부에서는 참조할 수 없습니다.
코드 사용 예시는 아래와 같습니다.
function funcA() {
console.log("funcA");
function funcB() {
console.log("funcB");
}
funcB();
}
funcA(); // funcA funcB 출력
funcB(); // 오류 발생 - 내부 스코프 참조
3-7. 화살표 함수
함수를 선언하는 방법으로 ‘function’ 키워드를 사용하는 대신 ‘=>’라는 화살표로 대신 함수를 선언하는 방식을 의미합니다.
코드 사용 예시는 아래와 같습니다.
let fun1 = function () {
return 1;
};
let fun2 = () => {
return 1;
};
let fun3 = () => 1;
위에서 예시로 보여드린 세 변수 (fun1, fun2, fun3)은 모두 동일한 기능을 처리하는 함수입니다.
이처럼 화살표 함수를 사용하면 함수를 더욱 간결하게 선언할 수 있습니다.
여기서 살펴볼 부분은 fun3인데 함수에서 내부적으로 로직처리가 필요없고 바로 반환으로 넘어간다면 중괄호를 생략할 수 있습니다.
이를 응용하면 아래와 같습니다.
let fun3 = (value) => value * 3;
fun3(4); // 12출력
3-8. 콜백 함수
다른 함수의 매개변수로써 전달되는 함수를 콜백 함수라고 합니다. 아래의 예제를 살펴보도록 합시다.
function main(value) {
value();
}
function sub() {
console.log("sub");
}
main(sub); // sub()가 아닌 sub 함수 자체를 매개변수로 넘겨준다.
위 예제를 살펴보면 main 함수의 매개변수로써 sub라는 함수가 전달되고 있습니다.
main 함수에서는 sub 함수를 호출하고 있으니 결과적으로는 ‘sub’이 콘솔에 출력됩니다.
이를 조금 더 응용해보면 아래와 같습니다.
var current = 0;
const onClickButton = (value) => {
current = current + value;
};
function click(fun) {
fun(1);
console.log(current);
}
click(onClickButton);
click(onClickButton);
click(onClickButton);
위 코드를 실행하면 console에 1, 2, 3이 출력됩니다.
click 함수가 실행될 때마다 전달받은 콜백함수(onClickButton)를 동작시키도록 구현되어있기 때문입니다.
콜백 함수는 앞으로도 유용하게 사용되기 때문에 응용하는 방법을 잘 숙지해야할 필요가 있습니다.
3-9. 객체
객체를 생성하는 방식은 아래의 두 가지 방식이 존재합니다.
let obj1 = new Object(); // 객체 생성자 사용
let obj2 = {}; // 객체 리터럴 사용
주로 객체 리터럴 방식을 사용하니 해당 방법을 사용해서 코드 예제를 살펴보도록 하겠습니다.
let person = {
name: "정성엽",
age: 26,
"like cat": true,
};
// 새로운 프로퍼티 추가
person.major = "computer science";
// 프로퍼티 수정
person.age = 27;
// 프로퍼티 삭제
delete person.age;
// 프로퍼티의 존재 유무 확인
let isAge = "age" in person; // True or False로 반환됨
위 코드를 살펴보면 객체 리터럴 방식을 사용하여 person이라는 객체 변수를 선언했습니다.
person이라는 객체 변수에서 살펴봐야할 부분은 Key : Value 형식으로 객체가 구성된다는 것입니다.
key에서 띄어쓰기를 사용하고 싶다면 ““를 사용하여 이를 구현할 수 있으며, value에는 모든 타입이 올 수 있다는 특징이 존재합니다.
key를 프로퍼티라고도 부르며, 새로운 프로퍼티를 추가하고 싶다면 객체 변수에 . 연산자로 새로운 프로퍼티를 할당해주면 됩니다.
만약, 프로퍼티를 수정하고 싶다면 기존에 존재하는 객체 프로퍼티에 접근하여 값을 수정해주면 됩니다.
프로퍼티의 삭제의 경우 ‘delete’ 키워드를 사용하여 진행할 수 있습니다.
마지막으로, 객체에서 프로퍼티의 존재 유무를 확인하는 키워드로 ‘in’을 사용할 수 있으며 반환값은 Boolean이라는 부분을 생각해야 합니다.
3-10. 형변환
JS에서 형변환하는 방법에 대해서 알아보고자 합니다. 형변환 방법에는 명시적 형변환 방법과 암묵적 형변환 방법이 존재합니다.
명시적 형변환은 JS의 내장함수를 사용해서 직접적으로 변환하는 방법입니다. 코드 예시는 아래와 같습니다.
const value1 = "1";
const value2 = "1개";
const strToNum1 = Number(value1);
const strToNum2 = Number(value2);
console.log(strToNum1); // 1 출력
console.log(strToNum2); // NaN 출력
위처럼 ‘Number()’라는 함수를 사용해서 명시적으로 형변환을 시켜주는 방식을 명시적 형변환이라고 합니다.
여기서 주의해야할 부분은 value2의 숫자 + 문자의 조합으로 되어있기 때문에 ‘Number()’함수를 이용해서 숫자로 변환이 불가합니다. (NaN 출력)
다음으로는 암묵적 형변환입니다. 코드 예시는 아래와 같습니다.
const value1 = 1;
const value2 = "2";
const text = value1 + value2;
console.log(text); // 12 출력
const value3 = "123";
const value4 = "456";
const num1 = +value3 + +value4;
const num2 = -value3 + -value4;
console.log(num1); // 579 출력
console.log(num2); // -579 출력
우선 text 변수는 + 라는 연산자를 이용하여 value1과 value2를 합치고 있습니다.
변수 중 하나라도 문자열이 존재한다면 + 연산자에 의해 다른 변수들이 모두 문자열 취급되어 결과적으로 12를 출력하게 됩니다.
그렇다면 문자열 변수를 숫자형 변수로 취급하기 위해서는 어떻게 해야할까요?
바로 문자열 변수 앞에 연산자를 붙여주면 숫자로 취급이 됩니다.
num1의 경우 각 변수 앞에 + 연산자를 추가하여 value3, value4를 양수로 취급하고 있습니다. 당연히 이에 대한 결과로 num1은 579가 출력됩니다.
num2의 경우 각 변수 앞에 - 연산자를 추가하여 value3, value4를 음수로 취급하고 있습니다. 마찬가지로 이에 대한 결과는 당연히 -579가 됩니다.
3-11. Truthy & Falsy 그리고 단락 평가
JS의 모든 값들은 Truthy 혹은 Falsy 입니다.
JS 엔진에서는 Falsy 값들이 개별적으로 저장되어있기 때문에 조건문을 길게 작성할 필요없이 에러체킹이 가능합니다.
Falsy한 값은 아래와 같습니다.
undefined
null
NaN
0
-0
""
0n
Truty한 값은 위 Falsy한 값을 제외한 나머지 모든 값들을 의미합니다.
JS 엔진은 논리연산자를 이용한 상황에서 첫번째 연산자만으로도 판별이 가능하다면 두번째 연산자에는 접근하지 않습니다.
이를 단락 평가라고 합니다. 예제 코드는 아래와 같습니다.
const trueFunc = () => {
console.log("true");
return 10; // Truthy
};
const falseFunc = () => {
console.log("false");
return NaN; // Falsy
};
console.log(trueFunc() || falseFunc()); // true, 10을 반환
위 코드를 실행해보면 콘솔에 ‘false’가 실행되지 않는 모습을 볼 수 있습니다.
즉, trueFunc()만으로 논리연산자 판별이 가능하므로 뒤에 있는 함수에 대해서는 판별을 진행하지 않습니다.
단락평가를 활용한 예제는 아래와 같습니다.
const person = {
age: 26,
};
const name = person && person.name;
console.log(name || "이름이 없습니다.");
person이라는 객체에 이름을 할당해주지 않은 상황이기 때문에 name이라는 변수에는 어떠한 값도 할당되지 않습니다.
콘솔에 출력하는 부분에서 || 논리연산자를 활용하여 단락평가를 진행합니다.
결과적으로 name이 Falsy이므로 뒤에있는 Truthy 값인 ‘이름이 없습니다.’가 콘솔에 출력됩니다.
4. 마무리
제 경험상 화살표 함수, 콜백 함수는 자주 사용되니 정확한 개념과 다양한 응용을 숙지한다면 코드를 더욱 효율적으로 작성할 수 있을 것 같습니다.
생각보다 내용이 길어져서 ‘JavaScript 알쓸신잡 - 2’로 돌아오겠습니다!