2021-12-29 T.I.L

정종훈·2022년 2월 28일
0

T.I.L

목록 보기
1/20

원시자료형 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 : 값이 변하지 않는 상주정의할때 씀. 블록스코프 따름.

변수선언시 유의할점

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

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

  • 선언없는 변수 할당 금지
    선언 없으면 var로 취급된다!
  • html 맨 위에 'use strict'라고 쓰면 선언없는 변수 할당 같은것도 에러로 판정!

클로저( 한 걸음 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가 서로 영향 안 줌!

profile
괴발개발자에서 개발자로 향해보자

0개의 댓글