js/node - 자료형, 스코프, 클로저

2021. 9. 8. 18:21·SE Bootcamp 내용 정리

원시 자료형과 참조 자료형

원시 자료형: 고정된 저장 공간 사용
참조 자료형: 동적으로 변하는 저장 공간 사용(함수, 배열, 객체 등)

학습 목표

* 원시 자료형과 참조 자료형의 구분이 필요한 이유?
* 원시 자료형과 참조 자료형의 차이?
* 원시 자료형은 변수에 값이 할당되고 참조 자료형은 “주소”가 할당된다
* 참조 자료형은 동적으로 크기가 변하는 특별한 보관함을 사용한다

원시, 참조 자료형 쉽게 이해하기

원시 자료형: 값(value)가 stack에 직접적으로 저장되어 있다. 값을 stack 보관함에서 바로 꺼내오는 구조

참조 자료형: 보관함에 값이 저장이 된 것이 아니라 어디를 참조 해라는 “주소”가 저장되어 있다.
그 주소에 해당하는 값은 heap에 저장이 되어 있어서 보관함에서 주소를 보고 heap에서 꺼내 오는 구조(간접적인 저장)

원시 자료형과 참조 자료형의 큰 차이?

원시 자료형은 그 값을 다른 변수가 가져와서 복사하고 수정하더라도 “원본에는 영향을 미치지 않는다”

let a = 60;
let b = a;
b=b+20;    //b=80
console.log(a);    // a=60;

반면, 참조 자료형은 그 값을 다른 변수가 가져와서 복사하고 수정하면 “원본도 변한다”
→ 원본도 “주소의 위치”를 가지고 있는 것이기 때문에 결국 heap의 찐 데이터 값을 수정한 것이기 때문

let a =[1,2,3,5,6];
let b=a;
b.pop();    //b=[1,2,3,5]
console.log(a);    // a=[1,2,3,5]

원시 자료형에 대한 심화 이해

원시 자료형: string, number, boolean, undefined, (null), bigint, symbol
→ 변수에 “하나”의 데이터 만을 담고 있다.
→ 데이터 보관함 한 칸에 하나의 데이터만 담을 수 있는 “원시적인” 방식
→ 원시 자료형은 값(value) 자체에 대한 변경이 불가능(immutable)하다.

다만, 변수에 다른 값을 할당해서(재할당) 변수에 담긴 내용을 변경할 수는 있다.

"hello world!"
"hello code!"
// "hello world!" 와 "hello code!"는 모두 변경할 수 없는 고정된 값

let word = "hello world!" 
word = "hello code!" 
// 하지만, word라는 변수에 재할당을 하여 변수에 담긴 내용을 변경은 가능

const num1 = 123;
num1 = 123456789; // 에러 발생
// const 키워드로 선언하면, 재할당은 불가

참조 자료형에 대한 심화 이해

참조 자료형에는 하나의 데이터가 아닌 “여러 데이터”가 담기게 된다
→ 여러 데이터 자체는 특별한 보관함인 heap에 저장된다
→ 참조 자료형의 변수에는 해당 heap을 찾아갈 수 있는 주소(reference)가 저장되는 개념

참고1)

let x = { foo: 3 };
let y = x;    // y에 객체의 주소를 할당했다 y={foo:3};
y = 2        // y에 원시 자료형의 값인 2를 재할당 y=2;
x.foo?    // y는 원시 자료형의 값을 할당했으므로 x에는 영향x    → x.foo=3;

참고2)

let score = 80;    // 변수에 number(원시 자료형) 값 할당;
function doStuff(value) {    // 함수(참조 자료형)
  value = 90;
}

doStuff(score)    // 해당 함수가 돌아가면 score가 원시 자료형이기 때문에 value에 score의 주소가 아닌 값을 가져옴
            // value=90; 이 되고 score에는 초기값인 80이 유지됨
            // score=80;

스코프(scope)

스코프란 영어 단어로는 “범위”라는 의미
→ js에서는 “변수의 유효범위” 로 사용

학습 목표

* 스코프의 의미와 적용범위?
* 스코프의 주요 규칙
- 중첩 규칙
- block scope와 functioin scope
- 전역 스코프와 지역 스코프
- 전역 변수와 지역 변수 간의 우선 순위?
- 선언 키워드 let, const, var의 차이
- 전역 객체(window)의 이해

스코프의 정의와 주요 규칙

정의: 변수 접근 규칙에 따른 유효 범위

주요 규칙

1. 안쪽 스코프에서 바깥쪽 스코프로는 접근할 수 있지만 그 반대는 불가능
2. 스코프는 중첩이 가능
3. 가장 바깥의 스코프: 전역 스코프(Global Scope) ↔ 지역 스코프(Local Scope): 그 외
4. 지역 변수가 전역 변수보다 높은 우선순위
ex1)
let name='kim';    // 전역 변수 선언 및 할당

function showName(){
    let name='lee';    // 지역 변수 선언 및 할당
// 동일한 변수 이름으로 인해 바깥쪽 변수가 안쪽 변수에 의해 가려지는(shadow) 이러한 현상을 “쉐도잉”(variable shadowing)이라 함

https://share.getliner.com/JX9kSC
    console.log(name);
}

console.log(name);    // kim        ← 아직 함수를 타기 전    
showName();        // lee
console.log(name);    // kim        ← 지역 변수가 아닌 전역 변수 꺼를 타므로

ex2)
let name='kim';    // 전역 변수 선언 및 할당

function showName(){
    name='lee';    // 값을 재할당
    console.log(name);
}

console.log(name);    // kim        ← 아직 함수를 타기 전    
showName();        // lee
console.log(name);    // lee        ← 함수로 인해 변수 name의 값이 변경됨

스코프의 종류와 선언 키워드 let, const, var

1.블록 스코프(block scope)
중괄호 `{}`를 기준으로 범위가 구분됨: 중괄호로 둘러싼 범위

2.함수 스코프(function scope)
function 키워드가 등장하는 함수 선언식(함수 표현식)은 함수 스코프를 생성: 함수로 둘러싼 범위

**cf. 화살표 함수는 블록 스코프로 취급(함수 스코프x)**

블록 스코프의 규칙

ex) 변수 선언 키워드로 let 사용
for(let i=0; i<5;i++){
console.log(i)    //5번 반복 
}
console.log(‘final i =’, i); //RefereceError
// i는 지역변수 이므로 출력 불가

ex) 변수 선언 키워드로 var 사용
for(var i=0; i<5;i++){
console.log(i)    //5번 반복 
}
console.log(‘final i =’, i);    // ?
// 5;    var 키워드는 블록 스코프를 무시

var 키워드

var 키워드는 블록 스코프를 무시하고 함수 스코프만 따른다
→ block 범위를 벗어나도(같은 function scope 에서는) 사용이 가능!
→ 단, “화살표 함수”의 블록 스코프는 무시하지 않는다

블록 단위로 스코프를 구분했을 때(들여쓰기 하므로), 훨씬 더 가독성 있고 예측 가능한 코드 작성이 가능하므로 let 키워드의 사용을 권장!

또한, var 키워드는 재선언을 해도 아무런 에러를 내지 않지만(정상), let 키워드는 재선언을 방지(에러)
→ 실제 코딩을 할 때 변수를 재선언하는 경우가 있는가? 대부분 버그이기 때문에 let은 버그 방지!

const 키워드

값이 변하지 않는 ‘상수’를 정의할 때 쓰는 const(constant)
값의 재할당이 불가능

let 키워드와 동일하게 “블록 스코프”를 따름

값의 변경을 최소화하여 보다 안전한 프로그램 제작 가능. 값을 새롭게 할당할 일이 없다면 const 키워드의 사용을 권장

값을 재할당하는 경우 TypeError!
→ 의도치 않은 값의 변경을 방지!

let, var, const 키워드 비교

            let                const                var
============================================================
유효범위 블록/함수scope    블록/함수 scope        함수 scope
------------------------------------------------------------
값 재할당    가능                X                가능
------------------------------------------------------------
재선언        X                    X                가능

개발자 콘솔을 통한 연습

breakpoint 사용 해보기, var 키워드 let 키워드 사용 해보기

function greetSomeone(firstName){
    let time='night';
    if(time==='night'){
        let greeting ='Good Night';
        debugger;    // debugger; 명령어로 디버깅 가능
    }

    return  greeting+' '+firstName;    //    greeting이 if 구문의 블록 스코프 안에서만 유효하므로 ReferenceError!
}

greetSomeone('Steve');

변수 선언에서 주의할 점

window 객체(브라우저 only)

브라우저에만 존재하는 window 객체
→ 브라우저 창을 대표하는 객체
→ 그러나, 브라우저 창과 관계없이 전역 항목도 담고 있음

”var”로 선언된 전역 변수와 함수 선언식(표현식)으로 선언된 전역 함수가 window 객체에 속함

전역 변수는 최소화할 것

전역 변수에 너무 많은 변수를 선언하지 마라!
→ 편리한 대신, 다른 함수 또는 로직에 의한 의도치 않은 변경이 발생 가능(부수효과: side effect)
→ 전역 변수 최소화는 side effect를 줄이는 좋은 방법!

let, const를 주로 사용하기

var가 가진 특징(재선언 가능, 블록 스코프 무시)때문에 버그 유발 가능
var로 선언한 전역 변수가 window 기능을 덮어 씌워서 내장 기능을 못 쓰게 만든다

선언 없는 변수 할당 금지

선언 키워드(let, var, const) 없이 변수 할당하지 말기

ex)
function showAge(){
age=90;    // 선언 키워드 없이 값을 할당하면 마치 var로 선언된 전역 변수처럼 작동
console.log(age);    //    90
}
showAge();
console.log(age);    //    90
console.log(window.age);        //    90

→ 선언 없이 사용하는 실수 방지를 위해 strict mode 사용 가능
strict mode는 브라우저가 엄격하게 작동하도록 만들어 줌

ex)
‘use strict’;        // js 파일 상단에 ‘use strict’ → strict mode 사용

function showAge(){
age=90;    // 선언 키워드 없이 넣었으므로 캐치하여 ReferenceError!
console.log(age);    
}
showAge();
console.log(age);    
console.log(window.age);        

클로저(closure)

자바스크립트만이 가지는 특이한 특성

"함수와 함수가 선언된 어휘적(lexical) 환경의 조합을 말한다. 이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다."

→ 자바스크립트(js)는 함수가 호출되는 환경과 별개로, 기존에 선언되어 있던 환경-어휘적 환경-을 기준으로 변수를 조회하려고 함

학습 목표

* 클로저 함수의 정의와 특징: 외부 함수의 변수에 접근할 수 있는 “내부 함수”; 클로저
* 클로저가 갖는 스코프 범위
* 클로저를 이용한 유용한 코딩 패턴

클로저(closure) 함수의 특징

1.함수를 리턴하는 함수의 형태

리턴값이 함수
→ 즉, 함수와 함수가 선언된 형태

ex)
const adder = x =>y =>x+y        //화살표 함수로 표현한 함수

// 위와 동일한 코드의 함수 표현식
const adder=function(x){
    return function(y){    // 리턴값이 함수의 형태이다!
        return x+y;
    }
}

2.외부 함수의 변수에 접근 가능한 “내부 함수”

→ 그 “내부함수”를 클로저라 한다!

리턴하는 함수에 의해 스코프(변수의 접근 범위)가 구분됨

클로저의 핵심은 스코프를 이용해서 변수의 접근 범위를 닫는(closure; 폐쇄) 것에 있다
→ 변수를 선언하는 곳이 중요!

ex) 외부 함수와 내부 함수

const adder = function(x){    // 외부 함수의 변수x
    return function(y){    // 내부 함수의 변수y    
        return x+y;        // 내부 함수
    }
}        // 외부 함수

→ 외부 함수는 y에 접근이 가능? 접근이 불가(바깥 스코프에서는 안쪽 스코프 접근x)
→ 내부 함수는 x에 접근이 가능? 접근이 가능(안쪽 스코프에서는 바깥 스코프의 변수에 접근가능)

클로저의 활용

“데이터를 보존하는 함수”

일반적인 함수는 함수 실행이 끝나면 함수 내부의 변수를 사용이 불가
→ 반면에 클로저는 외부 함수의 실행이 끝나더라도 외부 함수 내 변수가 메모리 상에 저장됨(어휘적 환경을 메모리에 저장하기 때문)

ex) 외부 함수(adder)의 실행이 끝나도, 외부 함수 내 변수인 x를 사용 가능

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

const a5=adder(5);    // adder(외부 함수)의 실행이 끝나도 5라는 값은 사용 가능
                // a5는 adder 함수에서 인자로 넘긴 5라는 값을 x 변수에 계속 담은 채로 있음

// 따라서 다음과 같이 활용 가능
a5(7);    //    12    → a5=adder(5) 이므로 adder(5)(7) → 7은 변수y에 대응됨
a5(10);    //    15    → adder(5)(10)    → 10은 변수y에 대

보다 실용적인 활용도 가능

ex) HTML 문자열 생성기

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

const divMaker = tagMaker(‘div’);    // divMaker 함수는 ‘div’ 문자열을 tag변수에 담아두고 있는 상태
divMaker(‘hello’)        //    <div>hello</div>
divMaker(‘code’)        //    <div>code</div>

const anchorMaker = tagMaker(‘a’);    // anchorMaker 함수는 ‘a’ 문자열을 tag 변수에 담아두고 있는 상태
anchorMaker(‘go’)    //    <a>go</a>
anchorMaker(‘to’)    //    <a>to</a>

→ 이처럼 클로저를 활용하면 특정 데이터를 스코프 안에 가두어 둔 채로 계속 사용할 수 있다

정보의 접근 제한(캡슐화)

클로저 모듈 패턴

ex) 클로저 모듈 패턴의 예

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

    return {
        increase: ()    => {        // 내부 함수를 객체({a: 2} 형태)에 담아 여러 개 만듦
            value=value+1
        },
        decrease: () => {    // 객체 안에 여러 개의 내부 함수가 들어간 구조
            value=value-1
        },
        getValue: () => value
    }
}

const counter1=makeCounter();
counter1    // 객체(Object) // {increase: 함수1, decrease: 함수2, getValue: 함수3}

위에서 makeCounter 함수를 바꾸지 않고 value 변수에 값을 재할당 가능?
→ 스코프 규칙에 의해 불가능. 대신, 리턴하는 객체가 제공하는 메소드를 통한 간접적 조작은 가능
(counter1.increase(); 이런 식으로 조작은 가능할 듯?)

→ 이것이 정보의 접근 제한(캡슐화)

캡슐화를 하는 이유?

캡슐화하지 않았으면 value 변수가 전역변수여야 함. 전역 변수는 side effect 발생 가능성을 높임
→ 불필요한 전역 변수를 줄여서 side effect 방지

모듈화(재활용이 가능)

앞선 예제에서 여러 개의 counter 생성이 가능

const counter1=makerCounter();
counter1.increase();    // 1증가
counter1.increase();    // 1증가
counter1.decrease();    // 1 감소
counter1.getValue();    // value = 0+1+1-1= 1;

const counter2=makeCounter();
counter2.decrease();    // 1감소
counter2.decrease();    // 1감소
counter2.decrease();    // 1 감소
counter2.getValue();    // value = 0-1-1-1=-3;

// 주의할 점이 counter1와 상관없이 counter2가 makerCounter를 할당 받았을 때 value는 0임
// makeCounter에 의해 리턴된 객체는 makeCounter를 실행할 때 선언되는 value 값을 각각 독립적으로 가짐.
// counter1과 counter2의 value는 서로에게 영향을 끼치지 않음(서로 독립적)

→ 함수 하나를 독립적인 부품 형태(모듈)로 분리하여 재사용성을 극대화 하는 게 모듈화
→ 클로저를 통해 데이터와 메소드를 같이 묶어서 활용 가능하므로 클로저는 모듈화에 유리

클로저의 단점

일반 함수였다면 함수 실행 종료 후 가비지 컬렉션(참고 자료: MDN '자바스크립트의 메모리 관리') 대상이 되었을 객체가, 클로저 패턴에서는 메모리 상에 남아 있게 됨
→ 클로저를 남발하면 퍼포먼스 저하


심화 학습: 스코프 고급

자바스크립트의 작동 원리에 대한 이해(기술 면접)

* Strict Mode
* 즉시 실행 함수 표현식(IIFE)
* 변수 호이스팅과 TDZ(Temporal Dead Zone)

Strict Mode: 엄격 모드(스크립트 최상단에 입력)

자바스크립트는 기존 기능을 변경하지 않으면서 새로운 기능이 추가되며 발전되어 옴

ECMAScript5(ES5) 가 등장하면서 새로운 기능이 추가되고 기존 기능 중 일부가 변경됨
→ 기존 기능이 변경되면서 하위 호환성 이슈가 발생
→ 그래서 변경 사항 대부분은 ES5 기본 모드에서는 비활성화 되도록 설계
→ 대신 ‘use strict’로 엄격 모드 활성화 시에만 변경 사항이 활성화 됨

cf. 보통 스크립트 최상단 위치가 국룰이나, 함수 본문 맨 앞에 쓸 수도 있다(이 때는 그 함수만 엄격 모드 적용)

* ‘use strict’ 는 반드시 최상단에 위치    // 오로지 주석만 그 위에 가능
* ‘use strict’는 취소 불가        // 한번 엄격 모드가 적용되면 되돌릴 수 없다

’use strict’를 꼭 사용해야 하나?

→ 엄격 모드를 활성화 하면 스크립트 전체가 “모던한” 방식으로 실행된다. 진일보한 현대적인 방식으로 돌아간다는 뜻. 모던 js는 클래스와 모듈이라는 구조를 제공함

→ 클래스와 모듈을 사용하는 경우 자동으로 ‘use strict’ 가 적용됨. 즉 이 때는 명시하지 않아도 됨

선언 키워드 var와 변수 호이스팅

선언 키워드 var는 구식 스크립트의 잔재이다.
var는 블록 스코프를 뛰어 넘는다는 것을 인지해야 함
var 선언은 함수가 시작될 때 처리되므로 var로 선언한 변수의 선언 위치가 어디든 상관없이 “함수가 시작되는 지점”에서 정의된다.

ex1)
function sayHi() { (*)
  phrase = "Hello";

  alert(phrase);

  var phrase;    // 뒤에서 선언했으나, 상관없이 함수 시작 지점(*)에서 정의
}
sayHi();

ex2)
function sayHi() {(*)
  var phrase;    // 함수 시작 지점(*)에서 정의

  phrase = "Hello";

  alert(phrase);
}
sayHi();

→ 위의 ex1)과 ex2)는 동일하게 동작.
이처럼 변수가 끌어올려지는 현상; 호이스팅(hoisting) 이라고 한다.
(Hoist;끌어올리다)

→ 단, 선언은 호이스팅되지만 할당은 호이스팅되지 않는다!
var phrase =”hello” 처럼 선언과 할당을 동시에 해도 선언만 호이스팅되고 할당은 그 할당 위치에서 처리됨

즉시 실행 함수 표현식(IIFE)

var도 블록 레벨 스코프를 가질 수 있도록 고안한 방식
요즘에는 쓰지 않는 방식이나 오래된 스크립트에서 발견할 수 있다

ex) 즉시 실행 함수 표현식(IIFE)의 예

(function() {

  let message = "Hello";

  alert(message); // Hello

})();

→ 함수 표현식을 괄호로 둘러쌓아 (function {…})와 같은 형태
함수를 괄호로 감싸면 js가 함수를 함수 선언문이 아닌 표현식으로 착각해서 인식함
함수 표현식은 이름이 없어도 되고, 즉시 호출도 가능

참고 // IIFE를 만드는 방법

(function() {
  alert("함수를 괄호로 둘러싸기");
})();

(function() {
  alert("전체를 괄호로 둘러싸기");
}());

!function() {
  alert("표현식 앞에 비트 NOT 연산자 붙이기");
}();

+function() {
  alert("표현식 앞에 단항 덧셈 연산자 붙이기");
}();

→ 모던 js에서는 굳이 쓸 필요 없으니깐 참고만 하면 됨(구식 스크립트의 잔재: var 때문)

호이스팅과 TDZ(Temporal Dead Zone; 일시적 사각지대)

호이스팅(Hoisting)이란, var 선언문이나 function 선언문 등을 해당 스코프의 선두로 옮긴 것처럼 동작하는 특성
→ 모든 선언;var, let, const, function, class 등이 호이스팅됨

그런데, let으로 선언된 변수를 선언문 이전에 참조하면 참조 에러가 발생
→ let으로 선언된 변수는 스코프의 시작에서 변수의 선언까지 일시적 사각지대(TDZ)에 빠지기 때문

ex) TDZ의 예

console.log(bar); // Error: Uncaught ReferenceError: bar is not defined
let bar;

TDZ를 이해하려면 변수의 생성 단계를 이해해야 함

<변수의 생성 3단계>
1. 선언 단계
변수를 실행 컨텍스트의 변수 객체에 등록. 이 객체는 스코프가 참조하는 대상이 됨

2. 초기화 단계
변수 객체에 등록된 변수를 위한 “공간”을 메모리에 확보. 이 단계에서 변수는 undefined로 초기화됨

3. 할당 단계
undefined로 초기화된 변수에 실제 값(value)을 할당함

→ var의 경우 선언 단계와 초기화 단계가 동시에 이루어짐
→ 반면, let으로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행

즉, 선언 단계와 초기화 단계의 사이가 일시적 사각지대(TDZ)가 되어서 초기화 전에 변수에 접근 시 참조 에러가 발생

// 스코프의 선두에서 선언 단계가 실행된다.
// 아직 변수가 초기화(메모리 공간 확보와 undefined로 초기화)되지 않았다.
// 따라서 변수 선언문 이전에 변수를 참조할 수 없다.
console.log(foo); // ReferenceError: foo is not defined

let foo; // 변수 선언문에서 초기화 단계가 실행된다.
console.log(foo); // undefined

foo = 1; // 할당문에서 할당 단계가 실행된다.
console.log(foo); // 1

checkpoint 추가 설명

js 에서는 함수의 전달 인자를 초과하는 인자를 전달했을 때
→ 에러가 나지 않고 무시한다    // 겉으로는 정상 작동

함수의 전달 인자가 필요한데 없이 호출한 경우
→ 에러가 나지 않고 undefined를 리턴

함수 내에서 매개변수는 그 안에서의 지역 변수로 취급된다

function(x) {    // 함수 내의 매개변수 x는 그 안에서의 지역변수로 취급됨!
return result=x;
}

클로저의 개념?

클로저 자체는 그 현상이라고 봐야 한다. 클로저 함수가 클로저는 아니다
클로저 함수가 구현되는 그 과정과 현상; 클로저
 

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

 
→ 외부 함수의 변수에 접근 가능한 내부 함수; 클로저 함수
클로저 함수와 같은 현상을 통칭하는게 클로저(즉 클로저는 함수 외에도 발견될 수 있다)
 
단순히 함수가 중첩되어 있다고 클로저 함수는 아니다
→ 외부 함수의 변수에 접근 가능한 내부 함수가 있어야 하고, 리턴 값으로 함수값을 사용해야 한다
 
클로저 정의에 대한 다양한 해석들; 명확한 정의가 없다
→ 그나마 이해될 정의? 함수의 실행 컨텍스트가 종료된 후에도 해당 변수가 사라지지 않는 현상;클로저

 
실제로 코딩할 때 비슷한데 디테일이 다른 함수가 계속 쓰이는 경우?
→ 이 부분을 클로저(closure)로 만들면 좋다!
→ 코드를 간략화 가능

'SE Bootcamp 내용 정리' 카테고리의 다른 글

얕은 복사, 깊은 복사 내용에 대한 정리?  (0) 2021.09.10
js/node - spread/rest 문법  (0) 2021.09.09
css - 레이아웃, selector  (0) 2021.09.07
js/node - 배열, 객체 checkpoint  (0) 2021.09.06
js/node - 배열, 객체  (0) 2021.09.03
'SE Bootcamp 내용 정리' 카테고리의 다른 글
  • 얕은 복사, 깊은 복사 내용에 대한 정리?
  • js/node - spread/rest 문법
  • css - 레이아웃, selector
  • js/node - 배열, 객체 checkpoint
레실이
레실이
  • 레실이
    레실이의 티스토리
    레실이
  • 전체
    오늘
    어제
    • 분류 전체보기 (91)
      • SE Bootcamp 내용 정리 (63)
      • 알고리즘 연습 (7)
      • Project 주저리 (4)
      • 기술 면접 source (3)
      • 개발 일상 (12)
      • 생성 AI 활용 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Ajax
    Python
    CORS
    Linux
    인증/보안
    ubuntu
    CSR
    IT
    JavaScript
    PickAndDrink
    자료구조
    react
    알고리즘
    useRef
    CSS
    객체
    문자열
    DOM
    JS
    fastapi
    promise
    node.js
    ORM
    state
    MVC
    useState
    비동기
    데이터베이스
    node
    mongoDB
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
레실이
js/node - 자료형, 스코프, 클로저
상단으로

티스토리툴바