Unit9 - [JavaScript] 핵심 개념과 주요 문법

강성일·2023년 4월 27일
0
post-thumbnail

📝 참조 자료형


1-1. 원시 자료형과 참조 자료형


JavaScript에서 자료형(type)이란 값(value)의 종류이다.

자료형은 크게 두 가지 자료형(primitive type)참조 자료형(reference type)로 구분할 수 있다.

JS에서는 6개의 자료형(number, string, boolean, undefined, null, symbol)을 원시 자료형으로 구분한다.
이중 symbol 타입은 잘 사용되지 않는 타입이다.


// 원시 자료형(primitive type) - number, string, boolean, undefined, null

42, 'string', true, undefined, null

원시 자료형이 아닌 모든 자료형은 참조 자료형이다.

배열, 객체가 대표적인 참조 자료형이며, 함수도 포함된다.


// 참조 자료형(reference type)

[0, 1, 2] // 배열
{name: 'kimcoding', age: 45} // 객체
function sum (x, y) { return x + y } // 함수



1-2. 얕은 복사와 깊은 복사


⚙️ 얕은 복사 (배열)


⚙️ 얕은 복사 (객체)


⚙️ 깊은 복사



1-3. 정리





📝 스코프


JavaScript에서의 스코프는 "변수의 유효범위"로 사용됩니다.


2-1. 스코프와 쥬요 규칙


Q. 콘솔에 순서대로 출력되는 결과는 무엇일까?


let greeting = 'Hello';
function greetSomeone() {
  let firstName = 'Josh';
  return greeting + ' ' + firstName;
}
console.log(greetSomeone()); // ?
console.log(firstName); // ?

// A.
'Hello Josh'
ReferenceError

greeting 변수는 바깥 스코프에 정의되어 있으므로, 함수 안쪽에서 사용할 수 있다.
따라서 greeting 변수와 firstName 변수의 조합에 의해 'Hello Josh' 문자열이 출력된다.

반면에, firstName 변수는 안쪽 스코프에 정의되어 있으므로 바깥쪽에서는 접근이 불가능하다.
따라서 ReferenceError를 내게 된다.



2-2. 변수 선언과 스코프


현재 var는 완벽하게 대체되었다고 볼 수 있다.

그 이유는 var를 사용하는 것은 살짝 위험하다고 할 수 있기 때문이다.

var 키워드는 재선언을 해도 에러가 나지 않는다.
반면에, let const은 그렇기 않기에 let const이 더 안전하다고 할 수 있다.




📝 클로저


클로저는 함수와 그 함수 주변의 상태의 주소 조합이다.

조금 더 쉽게는, 클로저는 함수와 그 함수가 접근할 수 있는 변수의 조합을 뜻한다.


3-1. 클로저 기초



Q. 아래 코드에서 message의 값은 무엇일까?


function outerFn() {
  const innerFn = function() { 
    const message = 'outerFn은 message에 접근할 수 있습니다.';
  }
	return message;
}
const message = outerFn();


A. 'outerFn은 message에 접근할 수 있습니다.'
B. 알 수 없음


// A.

답은 B번이다.

outerFn을 호출할 때, message를 리턴하려고 시도하지만 message는 innerFn의 스코프
즉, 내부 함수의 스코프에 있기 때문에 접근이 불가하여 ReferenceError가 난다.

→ 만약 `outerFn``message` 를 리턴하지 않고, `innerFn` 을 리턴했다면 결과는 바뀐다.

최종적으로 message 값은 outerFn() 이었을 것이다.


3-2. 클로저 활용


⚙️ 데이터 보존


⚙️ 커링


⚙️ 모듈 패턴




🔥 문제 풀면서 정리


result 값은?

let x = 10;

function outer () {
  x = 20;

  function inner () {
    let x
    x = x + 20;
    return x;
  }
  inner();
}

outer();
let result = x;

답은 20이다.

outer 함수는 전역 변수 x에 20을 재할당합니다. 따라서 result의 값은 20이 됩니다.

outer 내부에서 inner 함수가 호출되고 있긴 하지만, inner 함수는 바깥 스코프에 아무런 영향을 미치지 않는다.




다음 중 틀린 것은?

const Subject = function () {
  const observers = [];

  return {
    subscribeObserver: function (observer) { observers.push(observer); },
    unsubscribeObserver: function (observer) {
      const index = observers.indexOf(observer);
      if (index > -1) { observers.splice(index, 1); }
    },
    notifyObserver: function (observer) {
      const index = observers.indexOf(observer);
      if (index > -1) { observers[index].notify(); }
    },
    notifyAllObservers: function () {
			for (let i = 0; i < observers.length; i += 1){
				observers[i].notify()
			}
		},
  };
};

const Observer = function (observerName) {
  let name = observerName;
  return {
    getName: function (name) { console.log("Observer Name:" + name); },
    notify: function () { console.log("Observer " + name + " is notified!"); },
  };
};

const subject = Subject();
const kimcoding = Observer('kimcoding');
const parkhacker = Observer('parkhacker');

subject.subscribeObserver(kimcoding);
subject.subscribeObserver(parkhacker);

subject.unsubscribeObserver(kimcoding);
subject.notifyAllObservers();


-----------------------------------------------------------------------------------------------

A. 콘솔 출력 결과는 `Observer parkhacker is notified!`이다.

B. 코드 실행이 모두 끝나면 `parkhacker``observers` 배열의 요소다.

C. 코드 실행이 모두 끝나면 `kimcoding``parkhacker``observers` 배열을 조회할 수 있다.

D. 코드 실행이 모두 끝나면 `kimcoding``parkhacker`는 다른 주솟값을 가진다.
  

답은 C이다.

이번 문제의 코드는 Observer 디자인 패턴이 적용되었다.

subject 객체의 subscribeObserver 함수를 사용하여 observer(kimcoding, parkhacker)를 등록하면,
향후 notifyAllObservers 함수를 통해 자동으로 kimcoding 과 parkhacker 의 notify 를 호출할 수 있다.

가장 쉬운 Observer 패턴의 예는 이벤트 핸들러이다.

이벤트 핸들러를 특정 이벤트가 특정 요소에서 발생할 때 작동하도록
“구독(addEventListener)”해두면 브라우저는 이벤트 발생 시 이벤트 핸들러를 호출한다.

구독을 취소(removeEventListener)하면 해당 이벤트는 발생하지 않는다.
이렇게 Observer 패턴은 한 동작을 구독한 여러 부분에 작동시킬 때 유용하다.

kimcoding 과 parkhacker 는 observers 배열의 요소로 포함되지만,
서로 다른 스코프에 위치하기 때문에 observers 배열을 직접 조회할 수 없다.

Observer 함수를 똑같이 이용했지만, 완전히 새로운 객체의 주솟값이 각각 담기기 때문에
kimcoding 과 parkhacker 는 서로 다른 주솟값을 갖는다.

만약 같은 주솟값을 가지면, observers 가 [kimcoding, parkhacker] 인 경우
subject.unsubscribeObserver(parkhacker); 를 실행해도 같은 주솟값을 가진 kimcoding 이 배열에서 삭제된다.
profile
아이디어가 넘치는 프론트엔드를 꿈꿉니다 🔥

0개의 댓글