원시자료형 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 |