일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 통영예쁜카페
- 한남동맛집
- ELK
- 스페인여행
- react
- gradle
- tomcat7
- 성북구맛집
- 방이편백육분삼십
- 성신여대맛집
- 통영
- ubuntu자바설치
- 통영에어비앤비
- 파이썬
- JavaScript
- 퇴사후공무원
- springboot
- 국가직
- 돈암동맛집
- 방이편백육분삼십성신여대
- 자바스크립트에러처리
- npm
- 꼴뚜기회
- 뚝섬역맛집
- 통영여행
- 영화추천
- 서울숲누룽지통닭구이
- 공무원
- 성신여대편백집
- 한성대맛집
- Today
- Total
코린이의 기록
[ES6] 스코프 본문
전역 스코프
전역변수를 사용하는 방식
let name = "Irena";
let age = 25;
function greet() {
console.log(`Hello, ${name}!`);
}
function getBirthYear() {
return new Date().getFullYear() - age;
}
greet();
console.log(getBirthYear());
Result
Hello, Irena! 1994 |
=> name 값을 외부에서 의도적으로 바꿀 수 있다는 문제가 있음.
let user = {
name : "Irena",
age : 25
};
function greet() {
console.log(`Hello, ${user.name}!`);
}
function getBirthYear() {
return new Date().getFullYear() - user.age;
}
greet();
console.log(getBirthYear());
단일 객체로 정의하는것이 낫다.
name과 age를 없애고 user를 써서 전역 식별자를 하나 줄였지만 greet(), getBirthYear()은 여전히 전역 user에 의존한다. 이 객체 역시 어디서든 수정할 수 있다.
대안으로 전역 스코프에 의존하지 않게 만드는 방법인데... 위와 차이점을 잘 모르겠다.
function greet(name) {
console.log(`Hello, ${user.name}!`);
}
function getBirthYear(name) {
return new Date().getFullYear() - user.age;
}
greet();
console.log(getBirthYear());
블록 스코프
중괄호로 묶은 것. 블록의 스코프에서만 보이는 식별자를 의미한다.
코드 블록({…})내에서 유효한 스코프
단, ES6에서 도입한 let과 const를 사용해야 가능한 스코프이다. Javascript는 기본적으로 비블록레벨스코프를 가진다. 그게 무슨말이냐면, C언어 같은 경우는 블록안에 있는 지역 변수는 외부에서 사용할 수 없었는데 Javascript는 그렇지 않다.
c언어
int main(void) {
// block-level scope
if (1) {
int x = 5;
printf("x = %d\n", x);
}
printf("x = %d\n", x); // use of undeclared identifier 'x'
return 0;
}
7번째 줄에서 x는 선언되지 않은 식별자 에러가 발생한다.
javascript
console.log('before block');
{
console.log('inside block');
var x = 3;
console.log(x);
}
console.log(`outside block; x=${x}`);
javascript에서는 정상적으로 outside block; x=3 이 출력된다.이를 ES6에서 새로 도입한 let, const를 사용해서 블록레벨스코프로 만들어보자.
console.log('before block');
{
console.log('inside block');
const x = 3;
console.log(x);
}
//console.log(`outside block; x=${x}`);
Result
before block 3 |
7번째 줄에서 x를 찍으려고 해보지만 x는 블록안에서 정의된 값이므로 ReferenceError가 발생한다. 왜냐하면 x는 블록 내에서만 접근 가능한 객체이기 때문이다.
클로저
함수가 특정 스코프에 접근할 수 있도록 의도적으로 함수를 그 스코프에서 정의하는 것. 쉽게말해서 함수내부에서 함수를 선언하면 클로저를 생성한것이다.
아래 예시를 보면서 이해해보자
클로저 Example 1
let globalFunc;
{
let blockVar = 'a';
globalFunc = function() {
console.log(blockVar);
}
}
globalFunc();
Result
a |
globalFun이 블록 안에서 정의되었다. 이 함수 밖에 있는 blockVar를 사용하고 있는데, 내부 함수에서 자신을 포함하고 있는 외부함수(or 블록)에서 정의한 변수에 접근할 수 있다. 가장 상위에 있는 스코프의 전역변수는 globalFunc이지만, globalFunc 함수의 전역변수는 그 상위에 있는 blockVar이 전역변수가 된다.
클로저 Example 2
function outerFunc() {
var x = 10;
var innerFunc = function () { console.log(x); };
innerFunc();
}
outerFunc();
Result
10 |
innerFunc에서 x 변수 접근이 가능하다.
결론은, 스코프 안에서 함수를 정의하면 해당 스코프는 메모리에서 조금 더 오래 유지된다.
클로저를 Javascript에서 사용하는 예제
1씩 증가하는 카운터 만들기
Case 1. 전역 변수를 썼을때.
var counter = 0;
function increase() {
return ++counter;
}
increase();
이 경우, counter 전역변수를 외부에서 변경할 수 있기 때문에 상당히 위험한 코드이다.
Case 2. 지역 변수를 썼을 때
function increase() {
var counter = 0;
return ++counter;
}
increase();
이 방식은 increase 함수가 호출될 때마다 변수를 0으로 초기화시키기 때문에 counter라고 할 수 없다. 계속 값이 1이기 때문.
Case 3. 클로저를 이용할때
var increase = (function () {
var counter = 0;
// 클로저를 반환
return function () {
return ++counter;
};
}());
increase 함수에서 내부함수를 만들어서 counter를 증가시키고 있다. 이는 counter변수를 외부에서 변경할 수 없으므로 안전한 코드라고 할 수 있다.
클로저의 대한 이해 : https://poiemaweb.com/js-closure
Reference : Learning JavaScrpit 이선 브라운 지음
'javascript,HTML,CSS' 카테고리의 다른 글
[javascript] Set onclick on the <tbody tr> except for specific <td> (0) | 2019.07.05 |
---|---|
[ES6] 객체와 객체지향 프로그래밍 (0) | 2019.06.30 |
[ES6] 표현식 & 연산자 (0) | 2019.06.17 |
[HTML] 한자 넣기 (0) | 2019.06.14 |
[ES6] 객체 (0) | 2019.06.14 |