코딩공부/T.I.L

2021-12-29 T.I.L

지구야 사랑해 2021. 12. 29. 13:22

원시자료형 VS 참조자료형

 

원시자료형

 

- 객체가 아니면서 메소드가 없는 string, number, boolean, symbol, bigint, null, undefined 7가지 데이터 타입

  (단, typeof null === 'object')

 

-cf) symbol 유형 : 병결불가능한 원시 타입의 값 -> 이름이 충돌할 위험이 없는 객체의 유일한 프로퍼티키를 만들기 위해 사용!

 

- 원시보관함의 보관함인 변수에는 하나의 원시자료형만 담을수있음! -> 그 공간이 바로 stack! (사물함 한 칸)

 

참조자료형

 

- 원시가 아니면 모두 참조

 

- 옛날에는 배열을 구현하기 어려워 배열과 비슷한 형태를 만듬 like csv -> ex) 10, 20, 30 같이 컴마로 구분!

 

참조자료형이 저장되는 특별한 데이터 보관함

 

- 참조자료형의 데이터 -> 데이터가 위치한곳을 가리키는 주소에 저장 -> 특) 동적임, heap라고도 부름, 참조(reference) 타입임.

 

Example 1) 참조자료형의 비교

[] === [] // false
{} === {} // false
왜 false가 뜰까? 참조자료형에서 비교가 되는것은 배열의 내용이 아니라 개체 참조이기 때문! ->
동일한 개체 인트던스 아님!

 

 

Example 2) 참조자료형을 원시자료형의 형태를 써서 바꿀 수 있을까?

 

let x = [1, 2, 3, 4];

let y = x;
y = 2 // 

console.log(x) // 고대로 [1, 2, 3, 4]
원시자료형으로 접근해봤자 영향 XXXX

스코프

 

def) 식별자가 유효한 유효범위(우효~) 

 

- 지역변수가 전역변수보다 우선순위가 높음!  -> 동일한 변수이름으로 인해 바깥쪽변수가 안쪽변수에 의해 가져리는 현상 : 쉐도잉

 

Example 3) let이 있고 없고의 차이가 이렇게 큽니다!

 

let name = 'a';

function() {
    let name = 'b';
    console.log(name);
    }
console.log(name)  // 'a'
function() // 'b' 바꿨네
console.log(name) // 'a' 안쪽 지역변수가 바깥쪽에 영향 x



let name = 'a';

function() {
     name = 'b'; // ***
    console.log(name);
    }
console.log(name)  // 'a'
function() // 'b' 바꿨네
console.log(name) // 'b' 계속 바뀌네? 밑에는 ***식에 let이 없음. 즉 전역변수를 계속 사용,수정할거
let이 없으면 전역변수를 그대로 가져다 쓴다!

스코프의 종류

 

- { }  : 블록스코프  & ( ) : 함수스코프

 

cf) 화살표함수블록스코프임

 

Example 4) user에서 세번째 줄 } 까지 블록 스코프!

let getAge = user => {
    return user.age;
    }

 

  • var : 블록스코프를 무시하고 함수스코프만 따름. 단, 화살표함수의 블록스코프는 무시하지 않음. 함수스코프의 최상단에 선언

 

  •  const : 값이 변하지 않는 상주정의할때 씀. 블록스코프 따름.

 

  var let const
유효범위 () () & {} () & {}
재선언 ok no no
재할당 ok ok no

 

변수선언시 유의할점

  • window객체(브라우저 only)

var 로 선언된 전역 변수 및 전역 함수는 window객체에 속하게 됨 -> window 기능을 덮어씌워 문제 발생 가능

ex) var console; 이렇게 함으로써 console.log 작동 오류

 

  • 선언없는 변수 할당 금지

선언 없으면 var로 취급된다!

 

  • html 맨 위에 'use strict'라고 쓰면 선언없는 변수 할당 같은것도 에러로 판정!

 

let foo = 1; // 전역 변수

{
  console.log(foo); // ReferenceError: foo is not defined
  let foo = 2; // 지역 변수
}

 

클로저( 한 걸음 closer 내 맘~)

 

intro) JS에는 클로저라는 개념이 있음!

 

def) by mdn ... 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다. 뭔 개소리? 우선 렉시컬이 뭔지 보자

 

렉시컬 스코프

Example 5) 렉시컬 스코프(정적 스코프)와 동적 스코프의 차이

 

var x = 1;

function foo() {
	var x = 10;
	bar();
}

function bar() {
	console.log(x);
}

foo(); // ?
bar(); // ?
위의 결과는 놀랍게도 1을 두 번 호출하는데 이는 JS가 렉시컬 스코프를 따르기 때문이다

- 함수를 어디서 호출했는지에 따라 함수의 상위 스코프를 결정하는방식은 동적 스코프이다.

 

- 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정하는 방식은 렉시컬스코프(정적 스코프)이다.

 

bar함수는 어쨋든 전역에서 정의된 함수이므로 전역 스코프를 기억함. 

함수가 호출될 때마다 함수의 상위 스코프를 참조할 필요가 있기 때문.  -> 즉 상위 스코프를 기억

 

클로저와 렉시컬 환경

Example 6)  클로저 그게 뭔데 

const x = 1;

// 1.

function outer() {
    const x  = 10;
    const inner = function () { console.log(x); }; //2.
    return inner;
}

//outer 함수를 호출하면 중첩 함수 inner를 반환한다.
//그리고 outer 함수의 실행 컨텍스트는 실행 컨테스트 스택에서 팝되어 제거된다.

const innerFunc = outer(); // 3.
innerFunc(); // 4.  10 not a 1
외부 함수(outer)보다 중첩 함수(inner)가 더 오래 유지되는 경우
이러한 중첩 함수를 클로저라고 부른다.

Q. 아니근데 왜 이런현상이 일어날까요??

 

A. 그냥 함수안에 함수가 있다고 클로저가 아님! 상위 스코프의 식별자를 참조(const x = 10)해야 그대는 진정한 클로저!

 

Example 7) 클로저 특

 

const adder = function (x) {
    return function (y) {
        return x + y;
    }
}

console.log(adder(5)(7)); //12
외부함수는 y에 접근 불가하지만 내부함수는 선언된 변수x에 접근 가능!

클로저의 활용

  • 함수내부의 변수를 재 사용!.

 

일반적인 함수는 실행이 끝나면 함수내부의 변수사용이 불가하다.

 

Example 8-1) 내부변수 사용 ㄴㄴ

function whereIsX() {
    let x = 3;
    return x;
}

console.log(x); // x is not defined

 

Example 8-2) 클로저는 다릅니다!

 

const adder = function (x) {
    return function (y) {
        return x + y;
    }
}

const add5 = adder(5); // 5라는 값을 x에 계속 담은채로 있음!

 

 

  • 상태를 안전하게 변경하기!

카운트상태 변수를 만들고 하나씩 늘린다고 해보자 !

 

Example 9-1) 이건 좀 아니지 않나요?

 

let num = 0;

const increase = function () {
    return ++num;
};

console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3

 

저렇게 해도 되지만 오류가 발생할 수 있음. 왜냐?

1. 카운트 상태(num 변수 값) 는 increase 함수가 호출되기 전까지 변경되지 않고 유지되어야 한다.

2. 이를 위해 카운트 상태는 increase 함수만이 변경할 수 있어야함!

 

Q. num을 조금 더 안전하게 보관할 수 있으면 좋겠다!

 

Example 9-2)  클로저를 이용해 조금 더 세이프티하게 저장!

const increase = (
    function () {
        let num = 0;
        return function () { //요게 클로저
            return ++ num; // 상위 스코프의 식별자 num 사용!
        };
    }
());
console.log(increase()); // 1
console.log(increase()); // 2
console.log(increase()); // 3

 

Example 10) HTML 문자열 생성기

 

const tagMaker = tag => content => `<${tag}>${content}</${tag}>`

const divMaker = tagMaker('div'); // tag 변수에 div 저장함!
console.log(divMaker('hello')); // <div>hello</div>

 

응용해보셈!

  • 정보의 접근제한(캡슐 모듈화!)

Example 11-1) 클로저 모듈 패턴

const makeCounter = () => {
    let value = 0;

    return {
        increase: () => {
            value += 1;
        },
        decrease: () => {
            value -= 1;
        },
        getValue: () => value
    }
}

const counter1 = makeCounter();
counter1 // {increase:f, decrease:f, getValue:f} 함수여러개를 포함한 객체가 됨.

Example 11-2) 클로저 모듈 패턴의 활용(11-1 예제에 이어서 작성)

counter1.increase();
counter1.increase();
counter1.increase();
console.log(counter1.getValue()); // 3이 됨

const counter2 = makeCounter();
counter2.decrease();
counter2.getValue(); // -1이 됨
counter1의 value와 counter2의 value가 서로 영향 안 줌!

'코딩공부 > T.I.L' 카테고리의 다른 글

2022-01-07 T.I.L  (0) 2022.01.07
2022-01-05 T.I.L  (0) 2022.01.06
2022년 1월 6일 T.I.L  (0) 2022.01.06
2022-01-04 T.I.L  (0) 2022.01.04
2021-12-31 T.I.L  (0) 2022.01.03