Codestates/06.15 - 07.10

2020.06.25 [TIL] Scope

Hello, Big stranger 2020. 6. 20. 12:17

이제 프로그래밍의 아주 기초적인 부분들을 벗어나 JavaScript의 기초 문법이 어느정도 익숙해지셨을 것으로 기대합니다. 앞으로의 목표는 단순히 잘 작동되도록 구현하는 것을 넘어, 기본적인 작동 원리와 규칙을 이해하고 이를 통해 좀 더 나은 코드를 작성할 수 있도록 하는 것입니다.

그러기 위해서는 JavaScript의 scope, closure, callback과 같은 개념을 익혀야 합니다. 이는 JavaScript 뿐만 아니라, 함수형 프로그래밍을 할 수 있는 기타 다른 언어들에서도 발견할 수 있는 특징입니다.

이를 잘 이해하면 여러분은 Underbar 과제를 풀 수 있게 될 것입니다. 이 파트를 꼼꼼히 학습하세요. closure와 scope에 대해 구체적으로 이해하는 것이 JavaScript 초보자와 숙련자를 가르는 기준들 중 하나입니다.

Achievement Goals

Scope

  • JavaScript의 Scope의 의미와 적용 범위를 이해할 수 있다
  • JavaScript의 Scope 주요 규칙을 이해할 수 있다
    • 중첩 규칙
    • block level vs. function level
    • let, const, var의 차이
    • 전역 변수와 전역 객체의 의미

Closure

  • Closure의 의미와 Closure가 가지는 Scope Chain을 이해할 수 있다
  • Closure의 유용하게 쓰이는 몇 가지 코딩 패턴을 이해할 수 있다

매개변수

  • Parameter의 갯수가 유동적인 함수를 만들 수 있다
  • ES6에서 사용하는 Rest parameter 및 ES5의 방법인 arguments 키워드를 이용할 수 있다
  • Default parameter를 사용할 수 있다

객체 지향 JavaScript

  • 객체 지향 프로그래밍의 기본적인 컨셉을 이해할 수 있다
    • class, instance 등의 용어를 이해할 수 있다
    • new키워드를 사용해 instance를 생성할 수 있다
    • ES6 class 키워드를 사용할 수 있다
  • prototype을 이용해 클래스의 원형을 만드는 방법을 이해할 수 있다

범위라는 뜻을 가진 Scope

범위라는 개념이 있어야 잘작동하는 코드를 알기 위해 있어야한다.

 

Q1 : greetSomeone() 과 firstName 실행의 결과는?

 

let greeting = 'Hello'

function greetSomeone() {

let firstName = 'Josh';

return greeting + ' ' + firstName;

}     ----------------------------------------------> Local Scope

 

greetSomeone(); // => ???

firstName ; // = > ??? ----------------------------------------> Global Scope

 

greetSomeone(); // => ' Hello Josh'

firstName; // => ReferenceError

 

why? 참조할수가없다? 

firstName is not defined - 정의된 적이 없다라고 나온다. 안쪽에 접근을 할 수없다.? 즉 안보이는 바운더리가 있음을 알수 있다.

그게바로 Scope가 되어있다.

 

변수 firstName에 접근할 수 있는 범위가 존재합니다.

 

Local Scope 안쪽에서 선언된 변수는 밖에서 사용할 수 없습니다. 

 

Scope : 변수 접근 규칙에 따른 유효 범위

 

변수는 어떠한 환경 내에서만 사용 가능하며, 프로그래밍 언어는 각각의 변수 접근 규칙을 갖고 있습니다.

변수와 그 값이, 어디서부터 어디까지 유효한지를 판단하는 범위

JavaScript는 기본적으로, 함수가 선언되는(lexical) 동시에 자신만의 Scope를 가집니다.

 

Rule 1 : Local Scope vs. Global Scope

 

안쪽 Scope에서 바깥 변수/함수를 접근하는 것은 가능

바깥쪽 Scope에서 안쪽 변수/함수를 접근하는 것은 불가능

 

Scope는 중첩이 가능합니다. - 함수 안에 함수를 넣을 수 있습니다.

 

Global Scope는 최상단의 Scope로, 전역 변수는 어디서든 접근이 가능합니다.

 

지역 변수는 함수 내에서 전역 변수보다 더 높은 우선순위를 가집니다.

 

Q2. 순서대로 콘솔에 출력되는 결과는?

 

let name = "Richard"

 

function showName() {

 let name = "Jack"; // 지역 변수   - let 키워드를 이용해 새로 선언하였습니다. 전역에 선언한 name과는 다른 변수입니다.

// showName 함수 안에서만 접근 가능

console.log(name); // ??? 2번째 Jack

}

 

console.log(name); // ??? 1번째 Richard

showName();

console.log(name); // ??? 3번째 Richard

 

지역변수는 항상 전역 변수보다 우선순위가 높다. - 그래서 잭을 참조하게된다.

 

let name = "Richard"

 

function showName() {

 name = "Jack"; // let 키워드가 없습니다. 

// 선언(let)이 없기 때문에, 바깥 scope에 있는 name이라는 변수를 가져옵니다.

console.log(name); // ??? Jack

}

 

console.log(name); // ??? Richard

showName();

console.log(name); // ??? Jack

 

Rule 2 : Fuction Scope vs. Block Scope

 

Block : 중괄호로 시작하고 ,끝나는 단위 컬리 브라켓이라고 한다.

 

if (true){

console.log('i am in the block');

}

 

for ( let i =0; i<10; i++){

console.log(i);

}

 

{

console.log('it works');

}

 

Q4. 콘솔에 출력되는 결과는?

 

for( let i = 0; i<5; i++){

 console.log(i); // 다섯번 iteration

} --------------> 여기까지만 변수를 사용할수있다.

 console.log('final i :', i); // ? - ReferenceError 

 

why? block 범위를 벗어나는 즉시 변수를 사용할 수 없습니다.

 

var 키워드 vs. let 키워드

 

변수를 정의하는 또다른 키워드 var

 

JavaScript는 기본적으로, 함수 단위로 자신만의 Scope를 가집니다. -> var 키워드 ( old way)

 

그러나, Block 단위로 Scope를 구분했을 때에 예측하기 쉬운 코드를 작성할 수 있다. -> let 키워드

 

Q5. 콘솔에 출력되는 결과는?

 

for( var i = 0; i<5; i++){   ----------------------> var 키워드를 사용해서 변수를 선언합니다.

 console.log(i); // 다섯번 iteration

}

 console.log('final i :', i); // ? - 5  block 범위를 벗어나도(같은 function scope 에서는) 사용이 가능합니다.

0,1,2,3,4,증감문 i++까지하기때문에 5가 나온다.

 

보시는것과같이 var이 편하게 보일수 있으나  한정된 블락안쪽에 있어야만 유효범위가 눈에 확들어오고 이 경우는 예상못하게 i를 뒤에서 쓰거나 재사용하는 경우가 있을 수있으니 var 보다 let를 쓰는게 좋다.

 

개발자 콘솔로 확인하는 var 키워드와 let 키워드

변수를 정의하는 또다른 키워드 var의 작동원리를 통해 Fuction Scope와 Block Scope가 무엇인지 알아봅시다.

 

A-1

function greetSomeone( firstName){

var time = 'night';

if(time === 'night'){

var greeting = 'Good Night';

}

return greeting + ' ' + firstName;

}

 

greetSomeone('Steve');

 

 

Local

firstName : "Steve"

greeting: " Good Night"

time : "night"

Global

 

Local Scope에는(this 값을 제외하고) 세 개의 변수가 담겨있습니다 ( firstName, greeting, time) 함수 안에 정의된 모든 변수를 Local Scope에서 사용가능합니다.

 

A-2

function greetSomeone(firstName){

let time = 'night';

if( time === 'night'){

let greeting = 'Hello';

}

return greeting + ' ' + firstName;

}   ---------------------------------> greeting 변수가 없으므로,ReferenceError가 발생합니다.

greetSomeone('Steve');

 

Local

firstName : "Steve"

this : window

time : "night"

Global

 

block 안쪽에 있는 greeting이라는 것에 주목을 해봐야 할 것이다.

 

function greetSomeone( firstName){

var time = 'night';

if(time === 'night'){

var greeting = 'Good Night';

}

return greeting + ' ' + firstName;

debugger; ---- 멈춘다면,

}

-------------------------------->Scope 에서는다음과 같이 나온다.

 

Block

greeting : "Good Night"

Local

firstName : "Steve"

this : window

time : "night

Global

 

greetSomeone('Steve');

 

const 키워드

 

값이 변하지 않는 변수, 즉 상수를 정의할 때 사용하는 키워드 const

let 키워드와 동일하게 Block Scope를 따릅니다.

값을 재정의하려고 하면 TypeError를 냅니다.

 

변수선언에 표를 작성한다면 다음과 같다.

  let const var(old way)
유효 범위  Block Scope Block Scope  Function Scope
값 재정의 가능 불가능 가능
재선언 불가능 불가능 가능

 

- 나는 시작부터 let를 사용해서 그런지 var이 낯설고 안쓴다. 가능한 한 재선언을 하지않는게 중요하니까!

 

Rule3. 전역 변수와 window객체

 

전역 범위를 대표하는 객체 window

 

Global Scope에서 선언된 함수, 그리고 var 키워드를 이용해 선언된 변수는 window 객체와 연결

 

var myName = "Paul";
console.log(window.myName); // paul

function foo(){
console.log('bar');
}

console.log(foo === window.foo); // true

 전역 범위에 너무 많은 변수를 선언하지 않도록 주의하세요.

 

전역 영역은 최상위 스코프이기 때문에 어떤 라이브러리가 어떤 변수를 사용할지 모르기 때문이다.

나는 a 라는 변수를 만들고있는데 i라는 이름이 겹칠수 있기 때문이다.

잘못 작동할 수 있기 때문이다.

그래서 하나의 스코프를 만들어 변수를 만드는 것이 좋다.

 

Rule 4 : 선언 없이 초기화된 전역 변수

 

🙅‍♂️절대로, 선언 키워드 ( var, let, const)없이 변수를 초기화하지 마세요!

 

function showAge(){
// age는 전역 변수로 취급됩니다.
age : 90;
console.log(age);
}
showAge(); // 90
console.log(age); // 90

age === window.age 보실 수 있는데 좋은게 아니다.

 

이런 실수를 방지하고자 한다면 Strict Mode를 사용하세요!

 

'use strict'; - 가장 상단에 넣어주고 코드 작성하면 변수선언을 키워드없이 했을 경우에 에러를 내준다. 그래서 의도하지않게 나이가 전역변수로 들어가지 않게 도와준다. 항상 파일을 저장한 상태에서만 스트릭트 모드가 사용가능하다.

 

function showAge(){

age = 90; // 여기서 에러가 발생합니다!

console.log(age);

}

showAge(); // 90

console.log(age); // 90

 

Rule 1 : Local Scope vs. Global Scope.

Rule 2 : Function Scope vs.

Rule 3 : 전역 변수와 window객체

Rule 4 : 선언 없이 초기화된 전역 변수