[부트캠프 js/Node] 210726 Primitive & Reference 개념 체크 및 스코프 체크포인트 복습

📌 원시자료형 & 참조자료형?

원시자료형

자바스크립트에서 원시 타입의 데이터(primitive data types; 원시 자료형)는 객체가 아니면서 method를 가지지 않는 6 가지의 타입

string, number,bigint, boolean, undefined, symbol, (null)

원시 자료형은 모두 "하나"의 정보, 즉, 데이터를 담고 있음.

참조자료형

원시 자료형이 아닌 모든 것은 참조 자료형입니다. 배열([])과 객체({}), 함수(function(){})가 대표적.

❗ 주의

원시 자료형이 할당될 때에는 변수에 값(value) 자체가 담기고, 참조 자료형이 할당될 때는 보관함의 주소(reference)가 담깁니다.


📌 원시자료형 & 참조자료형 체크포인트

1번문제

코드가 실행된 후, x의 값은 무엇일까요?
let x = 2;
let y = x;
y = 3;

x는 원시자료형이다. 원시자료형은 하나의 값만 가질 수 있다. 그러므로 변수 x의 값은 원시 자료형이기 때문에 x의 값이였던 2를 y에 복사하여 할당.
y=3 이라는 코드가 x의 값에 영향을 주지 않으므로 x는 2가 됨.

2번문제

코드가 실행된 후, x.foo의 값은 무엇일까요?
let x = { foo: 3 };
let y = x;
y.foo = 2;

원시 자료형이 아닌 모든 것은 Object. 배열([])과 객체({}), 함수(function(){}) 이 해당됨. 이런걸 참조자료형. 참조자료형은 1번문제와는 달리 주소값을 복사함. x에 객체를 할당하였음. y에 x를 담았음. 그런데 y.foo 가 2로 변경됨. 그렇다면 x.foo 도 똑같이 변경. x = {foo: 2} 가 되는 것

3번문제

코드가 실행된 후, 콘솔에 찍히는 값은 각각 무엇일까요?
console.log('codestates' === 'codestates');
console.log(3.14 === 3.14);
console.log([1,2,3] === [1,2,3]);
console.log({ foo: 'bar' } === { foo: 'bar' });

첫번째는 원시자료형, 두번째도 원시자료형, 세번째는 배열이므로 두개의 주소값다름. 네번째는 객체이므로 두개의 주소값 다름
그럼 true true false false

4번문제

코드가 실행된 후, x.foo의 값은 무엇일까요?
let x = { foo: 3 };
let y = x;
y = 2;

두번째 라인에서 변수 y는 x의 주소값을 할당 받은 것.

y -> { foo:3 } x -> { foo:3 } //두개가 같지 않음

그래서 y에 2는 x에 아무런 영향을 받지 않음. 그러므로 x.foo 의 원래 값 3이 출력되는 것

5번문제

코드가 실행된 후, myArray의 값은 무엇일까요?
let myArray = [2, 3, 4, 5];
let ourArray = myArray;
ourArray[2] = 25;
ourArray = undefined;

ourArray 주소값에 위치한 배열의 의 2번째 요소를 25로 변경. ourArray와 myArray의 주소값은 같음으로 현재 myArray는 [2, 3, 25, 5]
그러나 ourArray = undefined 는 원시자료형이므로 myArray에 접근할 수 없음. ourArray는 undefined 가 되고 myArray는 [2, 3, 25, 5] 가 됨.

6번 문제

코드가 실행된 후, player.score의 값은 무엇일까요?
let player = { score: 3 };
function doStuff(obj) {
obj.score = 2;
}
doStuff(player);

doStuff(player);
함수 doStuff에 변수 player를 인자로 전달하여 호출.

function doStuff(obj) { 
  obj.score = 2;
}

코드가 실행되는 순서는 변수가 선언 또는 함수의 실행을 기준으로 함.
함수가 호출되면 (실행되면) 매개변수 obj에 변수 player의 값이 할당되므로. { score: 3 }의 주소값이 됨. obj.score에 2를 할당하면, obj와 player는 같은 주소값을 가지고 있기 때문에, player.score도 2가 되게 됨.

7번 문제

코드가 실행된 후, score 의 값은 무엇일까요?
let score = 80;
function doStuff(value) {
value = 90;
}
doStuff(score)

코드가 실행되는 순서는 변수가 선언 또는 함수의 실행을 기준으로 함.

doStuff(score)

함수 doStuff에 score의 값을 인자로 전달하여 실행.

function doStuff(value) {
  value = 90;
}

매개변수 value에 score의 값 80이 전달되고,
value = 90에서 value에 90이 할당. 그러나 변수 score의 값 80은, 참조 자료형이 아니기 때문에 주소값을 전달하지 않고, 값 자체를 복사하여 전달 그래서 함수에서 어떤 일이 발생했던가와 관련이 없이 score는 초기에 할당된 값 80이 그대로 유지


📌 스코프 주요규칙

변수에 접근할 수 있는 범위가 존재한다. 그 범위를 스코프라고 한다.

  • 안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 반대는 불가능하다.
    (바깥쪽 스코프에서 선언한 변수는 안쪽스코프에서 사용가능 / 안쪽 스코프에서 선언한 변수는 바깥쪽에서 사용불가능)

  • 스코프는 중첩이 가능

📌 스코프 체크포인트

  1. 다음의 코드를 실행시킨 후에 result 의 값은 무엇이 될까요?
    let x = 30;
    function get () {
    return x;
    }
    let result = get(20);

함수 get은 x를 반환하는데, 이때 x는 전역 스코프의 x. get 함수 스코프 내에는 x라는 변수가 별도로 선언되어 있지 않기 때문. 따라서 변수 result에는 30이 할당

  1. 다음의 코드를 실행시킨 후에 result 의 값은 무엇이 될까요?
    let x = 30;
    function get (x) {
    return x;
    }
    let result = get(20);

1번 문제와 달리, get함수에 매개변수 x가 선언되어 있음. 즉 get함수가 반환하는 x는 전역 스코프의 x가 아니라, get함수 스코프에 선언된 별도의 매개변수 x. 따라서 이번 문제에서 result의 값은 전역 변수 x에 할당된 30이 아닌 get함수의 전달인자 20

3. 다음의 코드를 실행시킨 후에 result 의 값은 무엇이 될까요?
let x = 30;
function get () { return x; }
function set (value) { let x = value; }
set(10);
let result = get(20);

result 값은 30
(왜지...?😂😂)

  1. 다음의 코드를 실행시킨 후에 result 의 값은 무엇이 될까요?
    let x = 30;
    function get () { return x; }
    function set (value) { x = value; }
    set(10);
    let result = get(20);

📌 클로저 함수

☑ 클로저 함수 특징/활용

  • 함수를 리턴하는 함수.
  • 외부함수와 내부함수로 나눠짐. 내부 함수는 외부 함수에 선언된 변수에 접근 가능하다. 외부함수의 변수에 접근가능한 내부함수.
  • 데이터를 보존하는 함수
  • 정보의 접근제한
  • 모듈화 가능

1번문제

아래 코드에서, 어떤 function이 클로저로 간주됩니까?

let seenYet = function() {
  let archive = {};
  return function(val) {
    if (archive[val]) {
      return true;
    } 
    archive[val] = true;
    return false;
  }
}

2번문제

total의 값은 무엇일까요?

let add = function(x) {
  let sum = function(y) {
    return x + y;
  }
  return sum;
}
let foo = add(1);
foo(3);
let total = foo(6);

함수 add는 x를 매개변수로 하며, 함수 sum을 반환. add는 매개변수 x를 통해 전달받은 값을 내부함수 sum에게 내려줌. 여기서 sum은 외부함수인 add의 변수 x에 접근할 수 있으므로 클로저.

3번문제

다음 함수(multiplyByX, multiplyByFive)중 클로저 사용을 보여주는 함수는 무엇입니까?

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);

리턴 함수가 x에 접근할 수 있기 때문에 multiplyByX가 클로저를 사용하고 있다고 볼 수 있다. 함수 내에서 다른 함수(내부 함수)가 리턴이 되면, 이 함수를 클로져 함수라고 부르고, 외부 함수에 있는 변수에 접근 가능!

4번문제

JavaScript에서 클로저를 정의해보세요.

클로져는 "함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성 된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다." 라고 합니다. 여기서의 키워드는 "함수가 선언"된 "어휘적(lexical) 환경"입니다. 특이하게도 자바스크립트는 함수가 호출되는 환경와 별개로, 기존에 선언되어 있던 환경 - 어휘적 환경 - 을 기준으로 변수를 조회하려고 합니다. 유어클레스 영상에서 언급되는 "외부함수의 변수에 접근할 수 있는 내부함수"를 클로져 함수로 부르는 이유도 그렇습니다. 클로저 함수: 클로저는 외부함수의 컨텍스트에 접근할 수 있는 내부함수를 뜻합니다. 외부함수의 실행이 종료된 후에도, 클로저 함수는 외부함수의 스코프, 즉, 함수가 선언된 어휘적 환경에 접근할 수 있습니다. 클로저 사용 예시: 클로저를 통해 커링(currying, 함수 하나가 n개의 인자를 받는 대신 n개의 함수를 만들어 각각 인자를 받게 하는 방법), 클로저 모듈(변수를 외부 함수 스코프 안쪽에 감추어, 변수가 함수 밖에서 노출되는 것을 막는 방법) 등의 패턴을 구현할 수 있습니다. 클로저의 단점: 일반 함수였다면 함수 실행 종료 후 가비지 컬렉션(참고 자료: MDN '자바스크립트의 메모리 관리') 대상이 되었을 객체가, 클로저 패턴에서는 메모리 상에 남아 있게 됩니다. 외부 함수 스코프가 내부함수에 의해 언제든지 참조될 수 있기 때문입니다. 따라서 클로저를 남발할 경우 퍼포먼스 저하가 발생할 수도 있습니다. 자바스크립트는 가비지 컬렉션을 통해 메모리 관리를 합니다. 객체가 참조 대상이 아닐 때, 가비지 컬렉션에 의해 자동으로 메모리 할당이 해제됩니다.


📌 Spread/Rest 문법

☑ Spread 문법
주로 배열을 풀어서 인자로 전달하거나, 배열을 풀어서 각각의 요소로 넣을 때에 사용.

ex) function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];
sum(...numbers) // 1 + 2 +3 = 6

☑ Rest 문법
파라미터를 배열의 형태로 받아서 사용. 파라미터 개수가 가변적일 때 유용.

function sum(...theArgs) {
  return theArgs.reduce((previous, current) => {
    return previous + current;
  });
}
sum(1,2,3) // 1 + 2 + 3 = 6 , 6을 리턴한다
sum(1,2,3,4) // 10

📌 Spread/Rest 오답 체크포인트

3번문제

코드가 실행된 후, value값은 무엇일까요?
let arr = [10, 30, 40, 20]
let value = Math.max(arr)

답은 NAN. max메서드는 인자들 중 가장 큰 값을 반환하는 메서드임. 근데 여기선 배열 자체를 값으로 받았기 때문에 40을 반환하는게 아니다.

4번 문제

코드가 실행된 후, value값은 무엇일까요?
let arr = [10, 30, 40, 20]
let value = Math.max(...arr)

arr의 모든 인자들을 펼쳐서 값을 받음. 그럼 max메서드가 구동하여 가장 큰 요소를 반환하여 40을 반환.

좋은 웹페이지 즐겨찾기