자료형(원시 vs 참조), scope, closure, spread, rest

호키키·2021년 12월 30일
0

TIL

목록 보기
1/2

TIL


📌 자료형

원시 자료형과 참조 자료형의 차이를 이해하고, 각자 맞는 상황에서 사용할 수 있다.
원시 자료형이 할당될 때에는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담긴다는 개념을 코드로 설명할 수 있다.
참조 자료형은 기존에 고정된 크기의 보관함이 아니라, 동적으로 크기가 변하는 특별한 보관함을 사용한다는 것을 이해할 수 있다.

  • 원시형
    자바스크립트에서 원시자료형은 객체가 아니면서 method를 가지지 않는 아래 6가지 데이터
    string, number, bigint, boolean, undefined, symbol, (null)
    원시 자료형은 값 자체에 대한 변경이 불가능(immutable), 새로운 값으로 재할당은 가능
    원시 자료형이 할당될 때에는 변수에 값 자체가 담김
	let value = 'hokiki'
    	value = 'nhpunch' // 재할당
  • 참조형
    자바스크립트에서 원시 자료형이 아닌 모든 것은 참조 자료형: 배열[], 객체{}, 함수(function)
	const pi = 3.14 // 원시 자료형에 값 할당
	const arr = ['hello', 'world'] // 참조 자료형의 주소가 할당

 	자바스크립참조 자료형의 데이터는 동적으로 변한다

	const arr = [1, 2, 3];
	arr.push(4, 5, 6); 
	arr // [1, 2, 3, 4, 5, 6]
 
 	참조 자료형을 변수에 할당할 경우, 데이터의 주소가 저장된다
 
 	const ages = [21, 25, 27]
 	ageCopy = ages;
 	ageCopy === ages // true
 
 	const num1 = [1, 2, 3]
 	const num2 = [1, 2, 3] 
 	num === num2 // false: 같은 데이터가 heap에 저장 되지만 주소가 다르기 때문,,

📌 scope

스코프의 의미와 적용 범위를 이해할 수 있다
스코프의 주요 규칙을 이해할 수 있다

중첩 규칙
block scope와 function scope
전역 스코프와 지역 스코프
전역 변수와 지역 변수간의 우선 순위
let, const, var 의 차이
전역 객체(window)의 이해

  • 스코프
    변수에 값을 찾을 때 확인하는 곳으로
    1) 블록 스코프: 중괄호{} 기준으로 범위가 구분
    2) 함수 스코프: fucntion 키워드가 등장하는 함수 선언식 및 표현식 !
    ➡️ 화살표 함수는 블록 스코프로 취급
    let message = 'Outer'; // 전역 변수: 내부에서 접근 가능

    function getMessage() {
      return message; /// 'Outer'
    }

    function shadowGlobal() {
      let message = 'Inner'; // 지역 변수: 바깥에서 접근 못함
      return message; // 'Inner'
    }

    function shadowGlobal2(message) {
      return message; 
    }
	shadowGlobal2('Parameter') // 'Parameter'
  
    function shadowParameter(message) {
      message = 'Do not use parameters like this!';
      return message;
    }
  	shadowParameter('Parameter') // 'Do not use parameters like this!'
  • var
    블록 스코프를 무시함, 함수 스코프만 따름. but 화살표 함수의 블록 스코프는 무시하지 않음
    함수 스코프는 함수의 실행부터 종료까지이고, var 선언은 최상단에 선언됨
    var 키워드는 재선언해도 에러를 내지 않음, let 키워드는 재선언을 방지

  • const
    값이 변하지 않는 상수를 정의할 때 쓰는 변수 선언 키워드
    let 키워드와 동일하게 블록 스코프를 따름
    값의 변경을 최소화하여 보다 안전한 프로그램을 만들 수 있음
    값을 새롭게 할당할 일이 없다면, const 키워드의 사용이 권장
    값을 재할당하는 경우, TypeError!!

  • let
    재할당이 필요한 경우에 한정해 사용하는것이 좋고 기본적으로는 const 사용

  • letconstvar
    유효 범위블록, 함수 스코프블록, 함수 스코프함수 스코프
    값 재할당가능불가능가능
    재선언불가능불가능가능
  • 변수 선언에서 주의할 점
    전역 변수는 최소화
    편리한 대신, 다른 함수 혹은 로직에 의해 의도되지 않은 변경이 발생할 수 있음(side effect)
    선언 없는 변수 할당 금지
    선언 없이 변수를 할당하면, 해당 변수는 var로 선언한 전역 변수처럼 취급 -> 'use strict'

  • window 객체(브라우저only)
    var로 선언된 전역 변수 및 전역 함수는 window 객체에 속함

    var myName = 'hokiki';
    console.log(window.myName); // hokiki 

    let message = 'Outer'; // 전역 변수: 내부에서 접근 가능

📌 closure

클로저 함수의 정의와 특징에 대해서 이해할 수 있다
클로저가 갖는 스코프 범위를 이해할 수 있다
클로저를 이용해 유용하게 쓰이는 몇 가지 코딩 패턴을 이해할 수 있다

  • 정의 및 특징
    함수를 리턴하는 함수가 클로저의 형태를 만들고, 외부 함수의 변수를 기억하고 이 외부 변수에 접근할 수 있는 함수를 의미
    외부함수의 실행이 종료된 후에도, 클로저 함수는 외부함수의 스코프. 즉, 함수가 선언된 어휘적 환경에 접근할 수 있다
    클로저가 가장 유용하게 사용되는 상황은 현재 상태를 기억하고 변경된 최신 상태를 유지하는 것
	// 리턴하는 함수에 의해 스코프(변수 접근 범위)가 구분됨
	// 클로저의 핵심은 스코프를 이용해서, 변수의 접근 범위를 닫는데에 있음
	// 따라서, 함수를 리턴하는 것만큼이나, 변수가 선언된 곳이 중요!!

	// 외부 함수 adder의 실행이 끝나더라도, 외부 함수 내 변수 x를 사용할 수 있음(장점)
	const adder = function (x) { // 변수 x가 선언된 함수는 바깥에 있으니 '외부 함수'
	  return function (y) {  // 변수 y가 선언된 함수는 보다 안쪽에 있으니 '내부 함수'
	    return x + y 
	  } // 외부 함수는 y에 접근 X
	}   // 내부 함수는 x에 접근 O
	const add5 = adder(5) // 변수 add5 에는 클로저를 통해 리턴한 함수가 담겨 있다
	// adder 함수에서 인자로 넘긴 5라는 값을 x 변수에 계속 담은 채로 남아있다
	add5(7) // 12
	add5(10) // 15 
  • 클로저의 실용적인 예제
	const tagMaker = tag => content => `<${tag}>${content}</${tag}>`
	// 클로저는 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있게 해줌!

	const divMaker = tagMaker('div');
	divMaker('hi') // '<div>hi</div>'
	divMaker('hokiki') // '<div>hokiki</div>'
	
	const anchorMaker = tagMaker('a');
	anchorMaker('pizza') // '<a>pizza</a>'
	anchorMaker('beer') // '<a>beer</a>'
  • 모듈화
	// 모듈화
	// 재활용 가능한 makeCounter 함수
	// 여러개의 counter를 만드는 것이 가능
	const makeCounter = () => {
        let value = 0; // counter1과 counter2의 value는 서로에게 영향을 끼치지 않음.
  
	  return {
	    increase: () => { 
	      value += 1;
	    },
	    decrease: () => { 
	      value -= 1;
	    },
	    getValue: () => value 
	  }
	}
	// makeCounter를 실행할 때에 선언되는 value 값을 각자 독립적으로 가지게 됨
	// 따라서 counter1에서의 value와 counter2에서의 value는 서로에게 영향을 끼치지 않고, 
	// 각각의 값을 보존할 수 있음
	const counter1 = makeCounter();
	counter1.increase();
	counter1.increase();
	counter1.decrease();
	counter1.getValue(); // 1

	const counter2 = makeCounter();
	counter2.decrease(); 
	counter2.decrease();
	counter2.decrease();
	counter2.getValue(); // -3

	// 이와 같이 함수 재사용성을 극대화하여, 함수 하나를 완전히 독립적인 부품 형태로 분리하는 것을 모듈화
	// 클로저를 통해 데이터와 메소드를 같이 묶어서 다룰 수 있다. 즉, 클로저는 모듈화에 유리하다!!

📌 Spread/Rest

Spread/Rest 문법, 구조 분해 할당을 사용할 수 있다.

  • Spread(...)
    배열을 풀어서 인자로 전달하거나, 배열을 풀어서 각각의 요소로 넣을 때 사용
    spread 문법은 기존 배열을 변경하지 않으므로, 새롭게 할당해야 함
  • rest
    파라미터를 배열의 형태로 받아서 사용할 수 있음
    파라미터 개수가 가변적일 때 유용
	// array
	let parts = ['shoulders', 'knees'];
	let lyric = ['head', ...parts, 'and', 'toes'];
	
	console.log(lyric); // ['head', 'shoulders', 'knees', 'and', 'toes']
	
	// object
	let obj1 = { ho: 'kiki', won: 100 };
	let obj2 = { ho: 'bbang', price: 200 };
	
	let clonedObj = { ...obj1 }; 
	let mergedObj = { ...obj1, ...obj2 };

	console.log(clonedObj); // { ho: 'kiki', price: 100 }
	console.log(mergedObj); // { ho: 'bbang', won: 100, price: 200 }
	
	//function
	function myFun(a, b, ...manyMoreArgs) {
	  console.log("a", a); // a one
	  console.log("b", b); // b two
	  console.log("manyMoreArgs", manyMoreArgs); // manyMoreArgs [ 'three', 'four', 'five', 'six']
	}
	
	myFun("one", "two", "three", "four", "five", "six");
	
	console.log(myFun); 
  • 구조 분해 (Destructing)
    구조 분해 할당은 spread 문법을 이용하여 값을 해제한 후, 개별 값을 변수에 새로 할당하는 과정

  • 배열의 구조 분해

	const [a, b, ...rest] = [10, 20, 30, 40, 50];
	a // [10]
	b // [20]
	...rest // [30, 40, 50]
  • 객체의 구조 분해
	const {a, b, ...rest} = { a: 10, b: 20, c: 30, d: 40}
	a // {a: 10}
	b // {b: 20}
	...rest // {c: 30, d: 40}
	객체에서 구조 분해 할당을 사용하는 경우, 선언(const, let, var)과 함께 사용하지 않으면 에러!
	선언없이 할당하는 경우, {} 블록 스코프로 인식함
	{title, width, height} = {title: "Menu", width: 200, height: 100};
	({title, width, height} = {title: "Menu", width: 200, height: 100});
	() 로 감싸주어 코드 블록이 아닌 표현식으로 해석하면 에러 해결
  • 함수에서 객체 분해
	function whois({displayName: displayName, fullName: {firstName: name}}) {
	  console.log(displayName + " is " + name); // hokiki is namhyun
	}
	
	let user = {
	  id: 28,
	  displayName: "hokiki",
	  fullName: {
	    firstName: "namhyun",
	    lastName: "kim"
	  }
	};

	whois(user) // 함수에 객체 전달

0개의 댓글