이전 포스트에서는 변수/상수/자료형/연산자에 대해 알아보았다. 이번에는 블록/스코프, 일급 객체에 대해 다룰 것이다. 함수나 if/else문, switch,for,while 문들의 사용법은 타 프로그래밍 언어와 크게 다를것이 없기 때문에 여기서 다루지는 않을 것이다.
어디까지나 이 블로그의 JS 포스트는 JS를 이용하여 추후 React.js와 Next.js를 하기위한 기초 개념을 정리한 포스트이다.
만약 함수나 if/else문, switch,for,while 문들의 사용방법을 알고 싶다면 모질라 재단의 공식문서를 확인하자.
JavaScript | MDN
JavaScript (JS)는 가벼운, 인터프리터 혹은 just-in-time 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 웹 페이지를 위한 스크립트 언어로 잘 알려져 있지만, Node.js, Apache CouchDB, Adobe Acrobat처럼
developer.mozilla.org
1) 블록 / 스코프
1.1)블록문
{
console.log('블록문');
}
JS에서는 {}안에 위와 같이 코드를 작성한다. 이렇게 {}로 묶여있는 코드문을 블록문이라고 이해하자.
블록문을 간단하게 정리하면 아래와 같다.
- 0개 이상의 statement들을 묶은 단위
- 제어문, 함수 등세 일반적으로 사용됨.
- 새로운 스코프를 생성함.
1.2)스코프
스코프를 간단하게 설명하면 '변수나 상수, 식별자들이 유효하게 사용될 수 있는 범위' 정도로 이해하면 될듯하다.
{
const x = 'Hello';
let y = 'world!';
console.log(x, y);
}
console.log(x);
console.log(y);
F12를 눌러 개발자도구의 콘솔탭에서 실행해보자.(처음 실행 시 붙여넣기가 안됨. 안내 내용을 따라해 붙여넣기 허용.)
실행 결과는 4번줄의 console.log(x,y)부분 실행 결과인 Hello world!가 나오고 7번줄 console.log(x)부분 부터 에러가 발생할것이다.
이유는 위에서 말했듯, 스코프는 유효하게 사용될 수 있는 범위이다. 따라서 블록 안에 선언된 변수와 상수를 해당 블록 밖에서 사용할 수 없다는 것이다. 따라서 블록 밖에 위치한 console.log(x)부터 에러가 발생하는 것이다.
let x = 1;
{
let y = 2;
console.log(x, y);
}
console.log(x);
console.log(y);
다만 블록 안쪽에서는 바깥에 선언된 변수나 상수를 사용할 수 있다.
따라서 위 코드를 실행시켜 보면 1 2 <br> 1 <br> 에러가 출력되는것을 볼 수 있다.
블록 안쪽의 console.log(x,y)는 블록 밖 변수 x와 블록 안 변수 y를 사용한다. 이것은 가능하다. 그리고 블록 밖의 console.log(x)는 같은 영역의 변수 x를 사용하기에 출력 되나, console.log(y)는 블록 안 변수 y를 사용하기에 에러가 발생하는 것 이다.
const xx = 0;
let yy = 'Hello!';
console.log(xx, yy);
{
const xx = 1; // 💡 블록 안에서는 바깥의 const 재선언 가능
let yy = '안녕하세요~';
console.log(xx, yy);
// ⚠️ const, let을 빼먹으면 재선언이 아니라 바깥것의 값을(변수면) 바꿈!
}
console.log(xx, yy);
블록 안쪽 변수나 상수를 재선언 할 수도 있다. 그 이유는 블록 밖 영역과 블록 안 영역에서 선언된 변수나 상수는 이름이 같아도 다른 것으로 보기 때문이다.
중요한것은 재선언시 const 나 let을 빼먹으면 재선언이 아닌 블록 밖에있는 해당 변수의 값을 바꿔버린다.(상수는 불변값이기 때문에 안바뀐다.)
만약 JAVA를 배웠던 사람이라면 오버로딩/오버라이딩 같은 느낌이 날 것이다.
1.3)스코프 체인
let a = 0;
let b = 1;
let c = 2;
console.log('시점 1:', a, b, c);
{
let a = 'A';
let b = 'B'
console.log('시점 2:', a, b, c);
{
let a = '가'
console.log('시점 3:', a, b, c);
}
console.log('시점 4:', a, b, c);
}
console.log('시점 5:', a, b, c);
위 코드의 실행결과를 보면 각 시점의 코드에서 필요한 값이 상위 스코프에 없다면 더 상위 스코프로 가서 찾는 행위를 한다. 이러한 행위를 스코프 체이닝이라고 한다.
이런 형태가 마지 스택(stack)처럼 보인다고 한다. 아마 후입선출(Last In First Out : LIFO)구조와 비슷해 보여 그런것 같다.
해당 코드를 그림으로 그려보면 스택처럼 보이기는 한다. 한번 각 시점별로 그림으로 그려 생각해 보면 이해하기 편할듯하다. (전역 / 스택 메모리 영역)
*전역 / 지역 변수/상수
전역(global) | 지역(local) |
데이터(data) 영역에 위치 | 스택(stack) 영역에 위치 |
코드 어느 곳에서든 접근 가능 | 해당 블록 안에서만 접근 가능 |
프로그램 종료시 소멸 | 블록 실행 종료시 소멸 |
전역변수 사용은 최소화 권장 (메모리 절약을 위함) |
변수나 상수는 사용할 블록 내에서 선언 권장 (메모리 절약을 위함) |
2) 일급 객체
함수를 변수와 같이 다루는 언어에 있는 개념이다. 자바스크립트의 함수도 기본적으론 객체이다.
일급 객체는 다음과 같이 3개의 특성을 갖는다.
- 상수 또는 변수에 할당 가능하다.
- 다른 함수에 인자로 전달 가능하다.
- 다른 함수의 결과값으로서 반환 가능하다.
2.1) 할당
function isOddNum (number) {
console.log(
(number % 2 ? '홀' : '짝')
+ '수입니다.'
);
return number % 2 ? true : false;
};
const checkIfOdd = isOddNum; // 뒤에 괄호 없음 유의
console.log(checkIfOdd(23));
isOddNum은 주어진 수가 홀수인지 아닌지를 참 거짓으로 출력하는 함수이다. 중요하게 볼 부분은 밑에서 두번 째 코드인 const checkIfOdd = isOddNum이다.
해당 코드는 checkIfOdd라는 상수를 만들고, 해당 상수의 값으로 isOddNum을 넣어준것이다. 중요한것은 괄호가 없다는 것이다.
만일 isOddNum에 괄호가 붙었다면, 그 함수를 실행해서 그 값을 리턴하는 것을 의미하지만, 여기서는 그냥 isOddNum이라는 함수 그 자체를 상수에 값으로 할당해준 것이다.
let person = {
name: '홍길동',
age: 30,
married: true,
introduce: function (formal) {
return formal
? '안녕하십니까. 홍길동 대리라고 합니다.'
: '안녕하세요, 홍길동이라고 해요.';
}
};
console.log(person.introduce(true));
console.log(person.introduce(false));
위 코드 처럼 객체의 값으로도 할당할 수 있다. introduce: function (formal) {...} 부분에서 function다음 함수 이름이 없는데, 이때 introduce라는 프로퍼티가 그 역할을 수행한다. 해당 함수는 한번 읽어보면 대부분 알것이라 생각한다.
(함수 내 구조는 타 프로그래밍 언어와 차이 없음)
let arithmetics = [
(a, b) => a + b,
(a, b) => a - b,
(a, b) => a * b,
(a, b) => a / b
];
for (arm of arithmetics) {
console.log(arm(5, 3));
}
이것은 배열의 값으로 활용했을 때의 예제이다. for문만 보면 알 수 있다. arm이라는 이름에 arithmetics 변수를 넣어 for문을 만든것이다. 때문에 이후 console.log로 출력할때는 arithmetics에 있는 a,b인자에 맞춰 값을 넣어 출력하면 모든 계산식에 값을 넣어 출력해줄것이다.
let person = {
name: '홍길동',
age: 30,
married: true,
introduce: function () {
return `저는 ${this.name}, ${this.age}살이고 `
+ `${this.married ? '기혼' : '미혼'}입니다.`;
}
}
console.log(person.introduce());
위 코드는 객체에 함수 프로퍼티를 포함할 때의 예제이다. 타 프로그래밍 언어와 별반 다른것은 없고, 그냥 객체의 다른 프로퍼티에 접근할 때는 this를 사용한다라는것만 기억하자.
introduce: function () {...}에서 {}안의 내용을 지우고 return this;를 입력하면, person객체가 그대로 나온다.
참고로 객체 리터럴의 프로퍼티로는 this 사용하는 화살표 함수를 권장하지 않는다.
2.2) 인자로 전달
함수가 다른 함수를 인자로 받는것이다. 전달받는 함수를 고차함수라고 하며, 전달되는 함수를 콜백함수라고 한다.
자바스크립트를 하다보면 자주볼것이 콜백함수이다. 해당 개념에 대한 포스트는 Node.js쪽에 포스팅 해 놓았다.
[Node.js] : Node.js 입문하기 _ 기본 개념
1) Node.js Node.js는 JavaScript를 어느 곳에서든 실행할 수 있게 해주는 JavaScript 실행환경이다. ( JavaScript's Runtime이라고 한다.) Chrome V8 엔진으로 빌드되어 있다. 이벤트 기반, Non-Blocking I/O 모델을 사용
homeless-programmer.tistory.com
*4번 섹터를 확인하자. 참고로 ES6 화살표 함수 형식의 콜백함수를 예시로 넣었다. 그점 유의해서 참고하라.
let list = [1, 2, 3, 4, 5];
function doInArray (array, func) {
for (item of array) {
func(item);
}
}
// console.log - console이란 객체에서 log란 키에 할당된 함수
doInArray(list, console.log);
간단한 코드이다. function doInArray (array, func) {...}부분을 보면 된다. 해당 부분은 한 배열과 어떤 함수 2개를 인자로 받는다. 그 후 for문을 보면 한 배열 array인자에 배열의 요소들을 하나씩 받아오고 그것을 func라는 함수에 인자로 넣어 실행한다는 것이다.
그 후 마지막 doInArray(list, console.log); 부분을 보면 list와 console.log를 인자로 받아 실행한다.
// calculate
const add = (a, b) => a + b;
const subtract = (a, b) => a - b;
const multiply = (a, b) => a * b;
// evaluate
const isOdd = (number) => !!(number % 2);
const isPositive = (number) => number > 0;
function calcAndEval (calc, eval, x, y) {
return eval(calc(x, y));
}
console.log(
calcAndEval(add, isOdd, 5, 7),
calcAndEval(subtract, isPositive, 5, 7),
calcAndEval(multiply, isOdd, 5, 7)
);
위 코드를 실행해 보며 나름대로 이해해 보자. 어려운건 아니니 이해될 것이다.
2.3) 결과값 반환
function getIntroFunc (name, formal) {
return formal
? function () {
console.log(`안녕하십니까, ${name}입니다.`);
} : function () {
console.log(`안녕하세요~ ${name}이라고 해요.`);
}
}
const hongIntro = getIntroFunc('홍길동', true);
const jeonIntro = getIntroFunc('전우치', false);
hongIntro();
jeonIntro();
별다른 설명은 필요 없을 것 같다.
const add = (a, b) => a + b;
const sub = (a, b) => a - b;
const mul = (a, b) => a * b;
const div = (a, b) => a / b;
function comb3ArmFuncs(armFunc1, armFunc2, armFunc3) {
return (x, y) => armFunc3(armFunc2(armFunc1(x, y), y), y);
}
const add_mul_sub = comb3ArmFuncs(add, mul, sub);
const mul_add_div = comb3ArmFuncs(mul, add, div);
const div_add_mul = comb3ArmFuncs(div, add, mul);
console.log(
add_mul_sub(10, 4),
mul_add_div(10, 4),
div_add_mul(10, 4)
);
이거까지 보면 될듯하다.
*본 포스팅은 '얄코'의 '제대로 파는 자바스크립트' 강의를 보고 정리한 내용임을 알림*
*해당 강의는 https://www.yalco.kr/ 에서 확인 가능함*
'JavaScript' 카테고리의 다른 글
[React.js] 리액트 입문하기 _ 리액트(React.js)란? (0) | 2024.07.04 |
---|---|
[JavaScript] 자바스크립트 입문하기 _ JS 변수/상수/자료형/연산자 (2) | 2024.04.07 |