S1. (원시/참조)자료형, 블로깅, 스코프, 클로저

Haizel·2022년 11월 16일
0

Front-End Developer 되기

목록 보기
13/70
post-thumbnail

노션으로 보기

원시자료형과 참조자료형


원시자료형(primitive data type) : 고정된 저장공간을 차지하는 데이터로, Method를 가지지 않는다.

  • 하나의 변수에 = 하나의 원시 자료형 데이터만 담을 수 있다.
  • number, string, boolean , undefined, symbol, bigint(길이의 제약 없이 정수를 다룰 수 있게 해주는 숫자형), (null)
  • 기존 데이터의 값(value)을 복사/변경 → 기존 데이터가 변경되지 않음
    • but, 변수에 다른 데이터 할당은 가능

참조자료형(reference data type) : 동적인 저장공간을 차지하는 데이터로 → 대량에 데이터를 다루기에 적합

  • 하나의 변수에 = 여러 데이터가 담긴다. → 동적인 데이터 보관함을 heap이라고 부른다.
  • array(배열)[], object(객체){}, funcion(함수)(){}
  • 데이터의 주소(reference)를 복사/변경 → 기존데이터가 변경된다.
💡 `**let`과 `const`의 차이점**
  • let : 키워드 선언 후 → 재할당 가능
  • const : 키워드 선언 후 → 재할당 불가능
let word = "hello world!"
word = "hello codestates!"
// let :  키워드 선언 후 → **재할당 가능**

const num1 = 123;
num1 = 123456789; // 에러 발생
// const : 키워드 선언 후 → **재할당 불가능**

스코프


: 변수에 접근할 수 있는 범위(변수의 유효범위)

스코프를 나누는 유형

  1. 중괄호
  • 중괄호 안쪽(안쪽 스코프)에 변수가 선언 or 중괄호 바깥(바깥쪽 스코프)에 변수가 선언되었는가
  1. 함수
  • 변수가 함수 안쪽 or 바깥쪽에 선언되었는가

스코프의 규칙

1️⃣ **변수 접근 규칙에 따른 유효범위**
  • 안쪽 스코프에서 선언한 변수는 : 안쪽 스코프에서만 사용 가능
  • 바깥쪽 스코프에서 선언한 변수는 : 안쪽, 바깥쪽 스코프 모두 사용 가능
2️⃣ **스코프는 중첩이 가능하다.**
  • 가장 바깥쪽의 스코프 : 전역 스코프(global Scope) → 전역스코프에서 선언한 변수 : 전역변수
  • 나머지 : 지역 스코프(local Scope) → 지역 스코프에서 선언한 변수 : 지역변수
  • 지역변수는 > 전역변수보다 더 높은 우선순위를 가진다.

Untitled

스코프의 종류

  1. 블록 스코프(block Scope) : **중괄호{}** 를 기준으로 범위가 구분된다.
  2. 함수스코프(function Scope) : **함수 function**키워드가 등장하는 함수선언식/함수표현식으로 범위 구분

❗️같은 함수여도, 화살표함수를 사용하면 ⇒ 블록 스코프로 취급

let getAge = user => {  //화살표 함수 -> 블록스코프
 return user.age;
}

변수 선언 키워드 let, const, var 차이점


for(___ i = 0 ; i < 5; i++) {
  console.log(i);  /i가 5번 반복
 }
console.log('final i:', i); //결과는 ??

1️⃣ __이 let일 경우

  • 블록 스코프안에 정의된 변수 i가 블록 범위를 벗어남.
  • 재선언 불가능하다.
for(**let** i = 0 ; i < 5; i++) {
  console.log(i);  /i가 5번 반복
 }
console.log('final i:', i); //ReferenceError

2️⃣  __이 var일 경우

  • for문이 만들어낸 블록스코프를 무시하고, 함수스코프만 따른다.
    • 하지만 화살표함수의 블록 스코프는 따른다.
for(**var** i = 0 ; i < 5; i++) {
  console.log(i);  /i가 5번 반복
 }
console.log('final i:', i); //5
  • var선언은 함수 스코프의 최상단에 선언된다.
    • 선언 키워드가 없는 선언은 최고 스코프에 선언된다.

그렇다면letvar중 무엇이 더 권장될까?

👉 **답은 `let` 이다.**
  1. 블록 단위로 스코프를 구분했을때 →**let키워드**가 훨씬 더 예측 가능하다.
  2. **let키워드**는 재선언을 방지 → 버그 실수를 막아준다.

3️⃣ const 키워드

: 갑이 변하지 않는 상수(Constant)를 정의할때 사용

  • 블록스코프를 따른다.(**let 키워드**와 동일)
  • 값의 변경을 최소화 하여 안전 → 값을 새롭게 할당할일이 없다면 **const 키워드** 사용 권장!
  • 재할당하는 경우 → TypeError 발생! : 의도하지 않은 값의 변경을 막는다.
👉 `**let`, `const`, `var` 변수 선언 키워드 비교**
letvarconst
유효범위블록스코프 함수스코프함수스코프블록스코프 함수스코프
값 재할당가능가능불가능
재선언불가능가능불가능

변수 선언에서 주의할 점


💡 “ **브라우저에만 존재하는 ‘window 객체’**

: 브라우저 창을 대표하는 객체이다. 그러나 브라우저 창과 관계없이 전역 항목도 담고 있다.

  • var로 선언된 전역 변수 및 전역 함수 → window객체에 속한다.
var myname = '김코딩';
console.log(window.myname); //김코딩

function foo() {
 console.log('bar'); 
}
console.log(foo === window.foo); //true
// -> var로 선언된 전역변수와 전역함수가 window 객체에 속한다.

1️⃣ 전역 변수를 최소화해라

  • 부수효과(side effect)이 발생 하기 때문이다 : 다른 함수, 로직에 의해 의도치않은 변경 발생 가능성

    2️⃣ **let, const를 주로 사용하자!**

    3️⃣ 선언 없는 변수 할당 금지!

  • 선언 없이 변수를 할당 → 해당 변수는 var로 선언한 전역 변수처럼 취급 된다!

💡 실수를 방지할 수 있는 **‘Strict Mode’**
  • js 파일 상단에 ‘Use Strict’; 이라고 입력(따옴표 포함)
  • 문접적으로 실수할 수 있는 부분들을 에러로 판단한다.
  • ‘선언 없는 변수 할당’ → 에러로 판단한다.

클로저(Closure)


: 외부 함수의 변수에 접근할 수 있는 내부함수

💡 **자바스트립트의 특이점**
  • JS는 함수가 호출되는 환경과 별개로 기존에 선언되어 있던 환경(= 어휘적 환경)을 기준으로 변수를 조회한다.
  • 따라서 ‘클로저’는 함수와 함수가 선언된 어휘적 환경의 조합을 말한다.
  • JS는 정적 스코프(Static Scope)를 채택
  • 정적 스코프(Static Scope)어휘적 스코프(lexical Scope)라고도 불린다.

클로저 함수의 특징

  1. 함수를 리턴하는 함수
const adder = x => y => x=y; // 함수 호출이 두번 발생하는 함수
add(5)(7);

//=위 코드와 동일하게 작동하는 코드
const adder = function(x) {      //function(x)는 또 다른 함수인 function (y)를 리턴
 return function (y) {           //즉 adder 함수는 클로저 함수이다.
   return x + y; 
   }
}
  • adder함수는 리턴 값으로 fucntion(x)를 가지는 클로저 함수이다.
  1. 외부함수의 변수에 접근가능한 내부 함수
  • 리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분된다.
const adder = function(x) {      
 return function (y) {          
   return x + y; 
   }
}
  • 외부함수 function(x) → 내부함수 function(y)에 접근 불가능❌

    ⇒ 바깥스코프 → 안쪽 스코프 접근 불가 ❌

  • 내부함수 function(y) → 외부함수 function(x) 에 접근 가능 ⭕️

    ⇒ 안쪽스코프 → 바깥스코프에서 선언한 변수에 접근 가능 ⭕️

클로저의 장점 및 활용

  1. 데이터를 보존하는 함수
  • 외부 함수(adder)의 실행이 끝나도 → 외부 함수 내 변수(x) 사용 가능
const adder = function(x) {
 return function(y) {
  return x + y ;
  }
}
const add5 = adder{5} ;
add5(7) //12
add5(10) //15
 
//일반적인 함수는 함수 실행이 끝나면 함수 내부의 변수 사용이 불가하다.
//하지만 클로저 함수인 adder 함수의 실행이 끝나도 x 변수에 5 값을 담은 채 남아있다.
//  => 이는 클로저가 어휘적 환경을 메모리에 저장하기 때문이다.
  1. HTML 문자열 생성기
  • 클로저는 특정 데이터를 스코프 안에 가둔 채 계속 사용할 수 있다.
const tagMaker = tag => content => `<${tag}>${content}</${tag}>`

const = divMaker = tagMaker('div);
//divMaker 함수는 'div'문자열을 'tag'라는 변수에 담아두고 있다.
divMaker('hello'); // '<div>hello</div>'
divMaker('code');; // '<div>code</div>'

const anchorMaker = tagMaker('a');
//anchorMaker 함수는 'a'라는 문자열을 tag라는 변수에 담아두고 있다.
anchorMaker('go'); // '<a>go</a>'
anchorMaker('you');// '<a>you</a>'
  1. 정보의 접근을 제한하는 : 클로저 모듈 패턴
  • 클로저를 이용 → 객체에 담아 여러 개의 내부 함수 리턴 가능
const makecounter = () => {
 let value = 0;

 return {                  //makercounter함수는 내부함수 여러개를 포함한 객체 값을 리턴한다.
  increase : () => {
   value = value + 1
   },
  decrease : () => {
   value = value - 1
   },
  getvalue : () => value
   }
 }

const counter1 = makecounter();
counster1 //  { increacs : f, decrease : f, getvalue :f }
💡 **클로저의 캡슐화 (정보의 접근 제한)**
  • 외부 스코프 → 내부 스코프의 변수에 접근 불가능
  • 따라서 let value 변수를 makecounter 함수가 보존하고 있기에 → 스코프 규칙에 의해 value 변수에 새로운 값 할당 불가능❌  ⇒ 따라서 리턴하는 객체가 제공하는 매소드를 통해서만 변경 가능
  • 클로저를 통해 불필요한 전역 변수 사용을 줄이고, 변수를 보다 안전하게 보호 가능하다
  1. 모듈화 : 재활용이 가능
  • 모듈화 : 함수의 재사용성을 극대화 - 함수 하나를 완전히 독립적인 부품형태로 분리하는 것
  • 클로저를 통해 데이터 + 메서드를 같이 묶어 다룰수 있다 → 클로저는 모듈화에 유리하다.
//counter1과 counter2의 value는 서로 영향 끼치지 X
// -> 함수를 완전히 독립적인 부품으로 분리하는 모듈화를 했기 때문에 !!!

const counter1 = makercounter();
counter1.increase(); //1
counter1.increase(); //2
counter1.decrease(); //1
counter1.getvalue(); //1

const counter2 = makercounter();
counter2.decrease(); //-1
counter2.decrease(); //-2
counter2.decrease(); //-2
counter2.getvalue(); //-3

//클로저 함수인 makercounter()함수를 캡슐화 -> 변수 value를 makercounter()함수로 보존 -> 전역 변수로 인한 side effect을 방지한다.

클로저 종합퀴즈 오답

  1. 아래 코드에서 클로저 함수는 → seeYet 함수가 리턴하고 있는 익명함수
  • seeYet 함수가 리턴하고 있는 익명함수 : 외부함수 seeYey의 스코프에 선언된 변수 archive에 접근 할 수 있는 클로저이다.
 let seenYet = function() {
  let archive = {};
  return function(val) {
    if (archive[val]) {
      return true;
    } 
    archive[val] = true;
    return false;
  }
}
  1. 다음코드를 실행 시, total의 값은? → 7
let add = function(x) {
  let sum = function(y) {
    return x + y;
  }
  return sum;
}

let foo = add(1);  
foo(3); // add(1)(3)으로 4가 반환되지만 어떤 변수에도 할당되지않아 total에 영향 X3.
let total = foo(6);  // = add(1)(6)과 같으므로 1+6 = 7이 정답
  1. 다음 함수(multiplyByX, multiplyByFive)중 클로저 사용을 보여주는 함수는 무엇인지 고르세요.

리턴 함수가 x에 접근할 수 있기 때문에 multiplyByX가 클로저를 사용

  • 클로저 함수는 “외부 함수의 변수(context)에 접근할 수 있는 내부함수”
let multiplyByX = function(x) {   
  return function(y) {
    return x * y;
  }
}

let multiplyBy5;
multiplyBy5 = multiplyByX(5);

multiplyBy5(4);

/////

let multiplyByFive = function() {
  return function(y) {
    return 5 * y;
  }
}

let multiplyBy5 
multiplyBy5 = multiplyByFive();
multiplyBy5(4);
  1. A, B, C, D 각각에 출력 될 내용은?
var a = 0;   //전역변수(글로벌변수)
function foo() {
    var b = 0;  //지역변수(로컬변수)
    return function() {
        console.log(++a, ++b);
    };
}

var f1 = foo();
var f2 = foo();

f1(); // --> A : 1 1
f1(); // --> B : 2 2
f2(); // --> C : 3 1
f2(); // --> D : 4 2

//해답 
//지역변수 b는 함수안에 선언 -> f1(), f2()실행할 때 각각 카운트가 올라감
//전역변수 a는 함수 밖에 선언 -> f1(), f2() 중 어떤것을 실행해도 카운트가 올라감
  1. (Advanced Challenge) 다음은 클로저가 유용하게 사용되는 상황인 버튼을 클릭하면 나타나고 사라지는 토글을 구현한 예제 코드이다. 클로저 개념을 활용해서 isShow 변수의 Javascript 를 작성하라.
  • 클로저가 가장 유용하게 사용되는 상황은 현재 상태를 기억하고 변경된 최신 상태를 유지하는 것.
<!DOCTYPE html>
<html>
<body>
  <button class="toggle">toggle</button>
  <div class="box" style="width: 100px; height: 100px; background: red;"></div>

  <script>
    var box = document.querySelector('.box');
    var toggleBtn = document.querySelector('.toggle');

    var toggle = (function () {
      var isShow = false;

      // TODO: ① 클로저를 반환하는 함수를 작성
      return function () {
        // TODO: ③ isShow 변수의 상태를 변경하는 코드를 작성하세요.
      };
    })();
    // ② 이벤트 프로퍼티에 클로저를 할당

    toggleBtn.onclick = toggle;
  </script>
</body>
</html>

//1. 클로저를 반환하는 함수
   return function() {
    box.style.display = isShow ? 'block' : 'none' ;
 //3. 변수 상태 변경
    isShow = !isShow;
 };
  1. 의 함수는 자신이 생성됐을 때 → 렉시컬 환경에 속한 변수 isShow를 기억하는 클로저이다.
  • 변수 isShow는 box 요소의 표시상태를 boolean 값으로 나타낸다.
  1. 버튼을 클릭하면 이벤트 프로퍼티에 할당한 이벤트 핸들러인 클로저가 호출된다.
  • 함수가 호출될 때 상황에 따라 isShow의 값이 변경
  • 변수 isShow는 클로저에 의해 참조됨으로 유효 → 자신의 변경된 최신 상태를 계속해 유지 가능하다.
profile
한입 크기로 베어먹는 개발지식 🍰

0개의 댓글