⚡실행컨텍스트가 뭔가요?
실행컨텍스트는 소스코드를 실행하는데 필요한 환경을 제공하고
코드의 실행 결과를 실제로 관리합니다.
식별자를 등록하고 관리하는 스코프와 코드 실행 순서 관리를 구현한 내부 메커니즘이며
모든 코드는 실행 컨텍스트를 통해 실행되고 관리됩니다.
⚡렉시컬 환경이 뭔가요?
렉시컬 환경은 식별자와 식별자에 바인딩 된 값, 상위 스코프에 대한 참조를 기록하는 자료구조입니다.
실행 컨텍스트를 구성하는 컴포넌트라고 할 수 있습니다.
자바스크립트는 함수를 어디서 호출했는지가 아닌 함수를 정의한 위치에 따라
상위 스코프를 결정하는 정적 스코프를 채택합니다.
⚡일시적 사각지대(TDZ)가 뭔가요?
TDZ는 let,const 키워드로 선언한 변수는 런타임에 실행 흐름이 변수 선언문에 도달하기 전까지
일시적 사각지대 (Temporal Dead Zone)에 빠지게되어 참조할 수 없는 것을 말합니다.
⚡식별자 결정이 뭔가요?
동일한 이름의 식별자가 다른 스코프에 여러개 존재할 수 있습니다.
따라서 같은 이름의 식별자 중 어느 스코프의 식별자를 참조할지 결정할 필요가 있는데
이것을 식별자 결정이라고 부릅니다.
⚡클로저에 대해 설명해주세요
클로저는 함수를 일급 객체로 취급하는 함수형 프로그래밍 언어에서 사용되는 중요한 특성입니다.
MDN에서는 클로저를
"클로저는 함수와 그 함수가 선언된 렉시컬 환경과의 조합이다"라고 설명합니다.
⚡중첩함수에서 상위함수의 변수를 참조하면?
const x =1
function outerFunc() {
const x = 10
function innerfunc() {
console.log(x) ; // 10
}
innerfunc()
}
outerFunc()
위 예제에서 출력결과는 10입니다.
중첩함수 innerfunc은
전역에서 선언한 x를 참조하지않고 outerFunc에서 선언한 x를 참조하는걸 알 수있네요
중첩함수 innerfunc의 상위 스코프는 외부 함수 outerfunc의 스코프입니다.
따라서 innerfunc 내부에서 자신을 포함하고 있는 외부함수 outerfunc의 x 변수에 접근할수있습니다.
물론 innerfunc이 outerfunc의 내부에서 정의된 중첩함수가 아니라면
outerfunc의 변수에 접근할 수 없을 것입니다.
⚡함수 객체의 내부 슬롯 [[Environment]]
함수가 정의된 환경과 호출되는 환경은 다를 수 있습니다. 당연하죠?
그런데 렉시컬 스코프는 함수가 정의된 위치를 기억하고 있어야 사용할 수 있을 것입니다. 당연하죠?
왜냐면 함수가 정의된 위치를 기준으로 참조할 것을 결정하니까요!!!
이것을 위해 함수는 자신의 내부 슬롯
[[Environment]]에 자신이 정의된 환경을 기억합니다.
"함수 객체의 내부 슬롯 [[Environment]]에 저장된 현재 실행 중인 실행 컨텍스트의 렉시컬 환경의 참조"
너무 꾸며주는 말이 많아서 어지럽네요
줄여말해보자면..
[[Environment]] 엔 자기의 상위 스코프를 저장한다.로 요약할 수 있을듯
⚡클로저 예제
const x= 1
function outer () {
const x = 10
const inner = function () {console.log(x)} //10
return inner
}
const innerfunc = outer() (3)
innerfunc() (4)
위 예제의 3번을 보면 outer()함수를 호출합니다.
이 시점에서 outer함수는 중첩함수인 inner를 반환하고 생명주기를 마감합니다.
즉 outer함수의 실행이 종료되면 outer함수의 실행 컨텍스트는 스택에서 제거됩니다.
그렇다면 outer함수의 지역 변수 x와 변수 값 10을 저장하고 있던
outer함수의 실행 컨텍스트가 제거되었으므로 outer 함수의 지역 변수 x 또한 생명주기를 마감합니다.
따라서 outer함수가 종료되면 outer함수의 지역변수 x도 소멸하여 접근할 수 없어야 할 것 같습니다.
그렇게 생각하고 inner함수의 동작을 예상하면 outer의 변수 x는 소멸했으니
inner는 전역변수 x를 참조해서 4번의 실행결과에서 1이 반환되어야할 것 같기도합니다
하지만 반환 결과는 10입니다.
실행 컨텍스트 스택에서 제거된 outer 함수가 소멸하면서 지역변수도 없어져야하지만
outer함수의 지역변수 x는 outer 함수의 실행컨텍스트가 소멸한 이후에도 동작하고있습니다.
이와 같이
외부 함수보다 중첩 함수가 더 오래 유지되는 경우 중첩 함수는
이미 생명 주기가 종료된 외부 함수의 변수를 참조할 수 있다는 걸 알 수 있습니다.
바로 이런 중첩함수를 클로저라고 부릅니다.
⚡왜 위 예제가 저렇게 동작 할까요?
함수는 렉시컬 스코프를 사용하기 때문에 자신이 정의된 상위 스코프를 기억합니다.
상위 스코프는 실행컨텍스트의 렉시컬 환경을 말한다고 했습니다.
따라서 모든 함수는 자신이 기억하는 상위 스코프의 식별자를 언제나 참조할 수 있고
식별자에 바인딩된 값을 변경하는 것도 가능합니다.
따라서 위 예제에서 inner 함수는 자신이 평가 될 때 [[Environment]] 슬롯에
자신의 상위 스코프를 저장하며 이때 저장한 상위스코프는 함수가 존재하는 한 유지됩니다.
1. outer 함수를 호출하면 outer 함수의 렉시컬 환경이 생성됩니다.
2. outer함수의 [[Environment]]에 외부 렉시컬 환경에 대한 참조가 할당됩니다.
3. 중첩함수 inner가 평가됩니다.(inner는 함수 표현식으로 정의했으니까 런타임에 평가됨)
위 과정에서 중첩함수 inner는 자신의 내부슬롯에 outer 함수의 렉시컬 환경을 상위 스코프로 저장합니다.
4. outer 함수의 실행이 종료되면 inner함수를 반환하면서 outer함수 생명주기가 종료
5. outer 함수 생명주기가 종료되면 outer 함수의 실행컨텍스트도 스택에서 제거됨
하지만 이때 outer 함수의 렉시컬 환경까지 소멸하는 것은 아님
outer 함수의 렉시컬 환경은 inner 함수의 내부슬롯에 의해 참조되고 있고 inner 함수는
전역 변수 innerfunc에 의해 참조되고 있으므로 outer 함수의 렉시컬 환경은
가비지 컬렉션의 대상이 되지 않으며 이로 인해 렉시컬 환경은 유지됩니다.
이처럼 외부함수보다 더 오래 생존한 중첩 함수는 외부 함수의 생존 여부(실행컨텍스트의 생존 여부)와
관계 없이 자신이 정의된 위치에 의해 결정된 상위 스코프를 기억합니다.
중첩함수 inner의 내부에서는 상위 스코프를 참조할 수 있으므로
상위 스코프의 식별자를 참조할 수 있고 식별자의 값을 변경할 수도 있습니다.
이론상 자바스크립트의 모든 함수는 상위 스코프를 기억하므로 모든 함수는 클로저이지만
일반적으로 모든 함수를 클로저라고 부르지는 않습니다.
예컨대 상위 스코프의 어떤 식별자도 참조하지 않는 함수 혹은
외부함수보다 일찍 소멸하는 함수는 클로저라고 부르지 않습니다.
⚡클로저 예제
let x = 200
function foo() {
const x = 1
const y = 2
//중첩함수 bar는 외부함수보다 더 오래유지되며 상위 스코프 식별자를 참조함
function bar() {
console.log(x)
}
return bar
}
const bar = foo()
bar() // x = 1
위 예제를 보면
1. 중첩 함수 bar는 상위 스코프의 식별자를 참조하고 있음
2. 외부 함수의 외부로 반환되어 외부 함수보다 더 오래 살아남음
위 예제처럼 외부 함수보다 오래 유지되는 경우 중첩 함수는 외부 함수의 변수를 참조할 수 있습니다.
그런데 클로저는 x는 참조하지만 y는 참조하지 않는데 그럼 y는 어떻게 될까요?
⚡자유 변수가 뭔가요?
자유변수란 클로저에 의해 참조되는 상위 스코프의 변수입니다.
클로저란 함수가 자유변수에 대해 닫혀있다라는 의미라고 할 수 있습니다.
최적화를 통해서 대부분의 모던 브라우저는 상위 스코프의 식별자 중에서
클로저가 참조하고 있는 식별자 만을 기억합니다.
따라서 위 예제에서 클로저가 참조하지 않는 y는 기억하지않고 x만 기억합니다.
클로저의 메모리 점유는 위처럼 필요한 식별자를 기억하는 것이기 때문에
불필요한 메모리 낭비라고 보기는 힘들기 때문에 적극적으로 활용하는 것이 좋겠네요!
⚡클로저의 활용
클로저는 상태를 안전하게 변경하고 유지하기 위해 사용합니다.
상태가 의도치 않게 변경되는 것을 막고 상태를 안전하게 캡슐화하며
특정 함수에게만 상태 변경을 허용하기 위해서 사용합니다.
let num = 0;
const increase = function () {
return ++num
}
console.log(increase()) // 1
console.log(increase()) // 2
console.log(increase()) // 3
위 예제가 기대대로 동작하려면 두가지 전제조건이 필요합니다.
1. 카운트 상태(num 변수 값)은 increase 함수가 호출되기 전까지 변경되지 않고 유지되어야함
2. num 변수값은 increase 함수만이 변경할 수 있어야함
하지만 카운트 상태를 안전하게 유지하기 위해서는 num 변수값을 increase만이 변경할 수 있어야하는데
위 예제에서는 num이 전역변수라서 변경될 위험성이 높습니다.
const increase = function () {
let num = 0;
return ++num
}
console.log(increase()) // 1
console.log(increase()) // 1
console.log(increase()) // 1
그럼 이렇게 하면 어떨까요?
이러면.. 이전 상태를 유지하지 못합니다.
const increase = (function () {
let num = 0
return function() {
return ++num
}
}())
console.log(increase()) // 1
console.log(increase()) // 2
console.log(increase()) // 3
이렇게 클로저를 만들어서 사용하면
num은 클로저만 상태를 변경할 수 있으면서 이전 상태를 기억하네요
이처럼 클로저는 상태가 의도치 않게 변경되지 않도록 은닉 해주고
특정 함수에게만 상태 변경을 허용해주면서 상태를 기억해줍니다.
위 예제를 좀 더 발전 시켜서 카운트를 감소시킬수도있게 짜면 어떨까요
const counter = (function () {
let num = 0
//클로저인 메서드를 갖는 객체를 반환하기
//객체 리터럴은 스코프를 만들지 않습니다.
//따라서 아래 메서드들의 상위 스코프는 즉시 실행 함수의 렉시컬 환경입니다.
return {
increase() {
return ++num
},
decrease() {
return num>0?--num:0
}
}
}())
console.log(counter.increase()) 1
console.log(counter.increase()) 2
console.log(counter.decrease()) 1
console.log(counter.decrease()) 0
위 예제에서 즉시 실행 함수가 반환하는 객체 리터럴은
즉시 실행 함수의 실행 단계에서 평가되어서 객체가 됩니다.
이때 객체의 메서드도 함수 객체로 생성됩니다.
다만 객체 리터럴의 중괄호는 코드 블록이 아니므로 스코프를 생성하지 않고
따라서 위 예제에서 increase, decrease 메서드의 상위스코프는
메서드가 평가되는 시점에 실행 중인 실행 컨텍스트인
(즉시 실행 함수 실행 컨텍스트의 렉시컬 환경)입니다.
따라서 increase,decrease 함수는 즉시 실행 함수의 스코프의 식별자를 참조할 수 있습니다.
**한줄요약
객체리터럴은 스코프없어서 객체를 스코프로 하지 않고 즉시실행함수를 스코프로 합니다.
⚡위 예제를 생성자 함수로 표현하면?
const Counter = (function () {
let num = 0
function Counter() {
}
Counter.prototype.increase = function() {
return ++num
}
Counter.prototype.decrease = function() {
return num > 0 ? --num : 0
}
return Counter
}())
const counter = new Counter()
console.log(counter.increase()) //1
console.log(counter.increase()) //2
console.log(counter.decrease()) //1
위 예제에서 let num은 생성자 함수가 생성할 인스턴스의 프로퍼티가 아니라
즉시 실행 함수 내부에서 선언된 변수입니다.
만약 생인프라면 인스턴스를 통해 외부에서 접근이 자유롭지만
즉시실행함수 내부에서 선언된 num 변수는 은닉된 변수입니다.
생성자 함수 Counter는 프로토타입을 통해 메서드를 상속받는 인스턴스를 생성합니다.
이 메서드는 자신의 함수 정의가 평가되어 함수 객체가 될 때
실행 중인 실행 컨텍스트인 즉시 실행 함수 실행 컨텍스트의 렉시컬 환경을 기억하는 클로저입니다.
따라서 프로토타입을 통해 상속되는 프로토타입 메서드여도 num을 참조할 수 있습니다.
⚡함수형 프로그래밍에서의 예제
//함수를 인수로 전달받고 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환합니다.
function makeCounter(aux) {
//카운트 상태를 유지하기 위한 자유 변수
let counter = 0
//클로저를 반환
return function () {
//인수로 전달받은 보조 함수에 상태 변경을 위임한다.
counter = aux(counter)
return counter
}
}
//보조함수
function increase(n) {
return ++n
}
function decrease(n) {
return --n
}
// increaser 함수와는 별개의 독립된 렉시컬 환경을 갖기 때문에 카운터 상태가 연동하지 않는다
const increaser = makeCounter(increase)
console.log(increaser()) //1
console.log(increaser()) //2
const decreaser = makeCounter(decrease)
console.log(decreaser()) //-1
console.log(decreaser()) //-2
위 예제를 보면
makeCounter함수는 보조함수를 인자로 전달 받고 함수를 반환하는 고차 함수입니다.
makeCounter 함수에 increase 함수를 인자로 전달해줍니다.
makeCounter 함수가 반환하는 함수는 자신이 생성 됐을 때의 렉시컬 환경인
makeCounter 함수의 counter를 기억하는 클로저입니다.
이때 주의 할 점은 makeCounter 함수를 호출해 함수를 반환할 때에
반환 된 함수는 자신만의 독립된 렉시컬 환경을 갖는다는 사실입니다.
함수를 호출하면 그때마다 새로운 makeCounter 함수 실행 컨텍스트의 렉시컬 환경이 생성됩니다.
1. increaser = makeCounter(increase) 부분에서 makeCounter를 호출하면
makeCounter 함수의 실행 컨텍스트가 생성된 뒤 makeCounter함수는 함수 객체를 생성 반환 후 소멸됩니다.
2. makeCounter함수가 반환한 함수는 클로저입니다. 이 클로저는 전역 변수 increaser에 할당됩니다.
3. 이때 makeCounter 함수의 실행 컨텍스트는 소멸되지만 makeCounter의 렉시컬 환경은
클로저의 내부 슬롯 [[Environment]] 에 의해 참조되고 있기 때문에 소멸되지 않습니다.
increaser와 decreaser는 서로 다른 실행컨텍스트의 렉시컬 환경을
상위 스코프로 기억하는 다른 클로저이기때문에 카운터 상태가 연동되지 않습니다.
따라서 독립된 카운터가 아니라 서로 연동되는 카운터를 만들고 싶다면
렉시컬 환경을 공유하는 클로저를 만들어야하고 이를 위해서
makecounter 함수를 두번 호출해서는 안됩니다.
⚡그럼 카운터를 공유하고 싶으면 어떡해요?
//함수를 인수로 전달받고 함수를 반환하는 고차 함수
// 이 함수는 카운트 상태를 유지하기 위한 자유 변수 counter를 기억하는 클로저를 반환합니다.
const counter = (function () {
//카운트 상태를 유지하기 위한 자유변수
let counter = 0
//함수를 인수로 전달받는 클로저를 반환
return function(aux) {
//인수로 전달 받은 보조 함수에 상태 변경을 위임한다.
counter = aux(counter)
return counter
}
}())
//보조 함수
function increase(n) {
return ++n
}
//보조 함수
function decrease(n) {
return --n
}
//보조 함수를 전달하여 호출
console.log(counter(increase)) // 1
console.log(counter(increase)) // 2
console.log(counter(decrease)) // 1
console.log(counter(decrease)) // 0
//자유변수를 공유하는 결과가 나옴
이렇게 클로저를 만들어주는 함수를 두번 호출하지 않고 한번만 할당해서 사용하면 됩니다.
⚡캡슐화와 정보은닉
캡슐화란 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고
조작할 수 있는 동작인 메서드를 하나로 묶는 것을 말합니다.
캡슐화는 객체의 특정 프로퍼티나 메서드를 감출 목적으로 사용하기도 하는데
이것을 정보 은닉이라고 부릅니다.
정보 은닉은 외부에 공개할 필요 없는 구현의 일부를 감추어 적절치 못한 접근으로부터
객체의 상태가 변경되는 것을 방지해 정보를 보호하고
객체 간의 상호 의존성 (결합도)를 낮추는 효과를 가지고있습니다.
⚡자바스크립트에서 객체의 모든 프로퍼티와 메서드는 기본적으로 public
function Person(name, age) {
this.name = name
let _age = age
// 인스턴스 메서드
this.sayHi = function() {
console.log(`hi my name is ${this.name} i am ${_age}`)
}
}
const me = new Person('lee', 20)
console.log(me.name) // lee
console.log(me._age) // undefined
const you = new Person('Kim' , 30)
you.sayHi()//hi my name is kim 30
console.log(you.name) // kim
console.log(you._age) // undefined
위 예제를 보면
name 프로퍼티는 public하지만
_age 변수는 Person 생성자 함수의 지역 변수 이므로 private합니다.
외부에서 참조,변경할 수 없으니까요!
저기서 sayhi메서드를 생성자 함수 안에서 클로저로 만들어주지 않고
생성자 함수 밖에서 프로토타입으로 추가하면 let _age 접근하지 못합니다.
⚡정보 은닉 만들기
const Person = (function () {
let _age = 0;
//생성자 함수
function Person(name, age) {
this.name = name;
_age = age
}
//프로토타입 메서드
Person.prototype.sayHi = function () {
console.log(`hi my name is ${this.name} i am ${_age}`)
}
return Person
}())
const me = new Person('Lee' , 20)
me.sayHi() // hi my name is Lee i am 20
console.log(me.name) // Lee
console.log(me._age) // undefined
const you = new Person("kim" , 30)
you.sayHi() // hi my name is kim i am 30
console.log(you.name) // kim
console.log(you._age) // undefined
위 예제에서 sayHi() 메서드를 보면
즉시 실행 함수가 반환하는 Person 생성자 함수와 Person 생성자 함수의 인스턴스가
상속받아 호출할 sayhi 메서드는 즉시 실행 함수가 종료된 이후 호출됩니다.
하지만 Person 생성자 함수와 sayHi 메서드는 이미 종료되어
소멸한 즉시 실행 함수의 지역 변수 _age를 참조할 수 있는 클로저입니다.
그러나 위 코드도 Person 생성자 함수가 여러개의 인스턴스를 생성하면
변수의 상태가 유지되지 않는 문제가 있습니다.
⚡위 예제의 문제점
const me = new Person('Lee' , 20)
me.sayHi() // hi my name is Lee i am 20
console.log(me.name) // Lee
console.log(me._age) // undefined
const you = new Person("kim" , 30)
you.sayHi() // hi my name is kim i am 30
console.log(you.name) // kim
console.log(you._age) // undefined
me.sayHi() // hi my name is lee i am 30
엥 me의 age 변수 값이 변경되어버렸습니다.
이러한 현상이 발생하는 이유는 Person.prototype.sayHi 메서드가
단 한번 생성되는 클로저이기 때문에 발생하는 현상입니다.
Person.prototype.sayHi 메서드는 즉시 실행 함수가 호출될 때 생성된다.
이때 Person.prototyp.sayHi 메서드는 자신이 상위 스코프인 즉시 실행 함수의
실행 컨텍스트의 렉시컬 환경의 참조를 [[environment]]에 저장하여 기억합니다.
⚡자바스크립트는 정보은닉을 지원하나요?
완전하게는 지원하지 않습니다.
인스턴스 메서드를 사용하면 자유 변수를 통해 private를 흉내낼 수는 있지만
프로토타입 메서드를 사용하면 이마저도 불가능합니다.
위와 같이 prototype은 단 한번 생성되기 때문에
인스턴스를 여러 개 생성하면 상태유지가 곤란해지니까요
하지만 최근에는 private 필드를 정의 할 수 있는 표준 사양이 제안되어있다고 합니다.
⚡클로저를 사용할 때 자주 발생하는 실수가 뭐가 있을까요?
var funcs = [];
for(var i =0 ; i<3 ; i++) {
funcs[i] = function() {return i;}
}
for(var j=0 ; j< funcs.length; j++) {
console.log(funcs[j]())
}
위 예제에서 우리는 0,1,2가 콘솔에 찍히길 기대하지만 결과는 3,3,3이 반환됩니다.
var로 선언된 변수 선언문은 함수 레벨 스코프를 갖기 때문에 전역변수가 되고
전역변수 i에 0,1,2가 순차적으로 할당되기때문입니다.
우린 이걸 클로저로 해결할 수 있습니다.
var funcs = []
for(var i = 0 ; i<3 ; i++) {
funcs[i] = (function (id) { //1
return function () {
return id
}
}(i))
}
for( var j = 0 ; j < funcs.length; j++) {
console.log(funcs[j]())
}
1번에서 즉시 실행 함수의 동작은 다음과 같습니다.
전역 변수 i에 현재 할당되어 있는 값을 인수로 전달 받아
매개 변수 id에 할당한 후 중첩 함수를 반환하고 종료합니다.
즉시 실행 함수가 반환한 함수는 funcs 배열에 순차적으로 저장됩니다.
이때 즉시 실행 함수의 매개변수 id는 즉시 실행 함수가 반환한 중첩 함수의 상위 스코프에 존재합니다.
그런데 즉시 실행함수가 반환한 중첩 함수는 자신의 상위 스코프를 기억하는 클로저입니다.
따라서 매개변수 id는 즉시 실행 함수가 반환한 중첩 함수에 묶여있는 자유 변수가 되어서 값이 유지됩니다.
물론 let 쓰면 해결됨
var funcs = [];
for(let i =0 ; i<3 ; i++) {
funcs[i] = function() {return i;}
console.log(i)
}
for(let j=0 ; j< funcs.length; j++) {
console.log(funcs[j]())
}
console.log(funcs)//0,1,2
⚡for문과 let i의 동작 과정
for문의 변수 선언문에서 let 키워드로 선언한 변수를 사용하면
for 문의 코드 블록이 반복 실행될 때마다
for문 코드 블록의 새로운 렉시컬 환경이 생성됩니다.
1. for 문의 변수 선언문에서 let 키워드로 선언한 초기화 변수를 사용한 for문이 평가되면
먼저 새로운 렉시컬 환경을 생성하고 초기화 변수 식별자와 값을 등록합니다.
새롭게 생성된 렉시컬 환경을 현재 실행 중인 실행 컨텍스트의 렉시컬 환경으로 교체합니다.
2.for 문의 코드 블록이 반복 실행되기 시작하면 새로운 렉시컬 환경을 생성합니다.
for문 코드 블록 내의 식별자와 값을 증감문 반영 이전의 값으로 등록합니다.
새롭게 생성된 렉시컬 환경을 현재 실행중인 실행 컨텍스트의 렉시컬 환경으로 교체해줍니다.
3. for문의 코드 블록의 반복 실행이 모두 종료 되면 for문이 실행되기 이전의 렉시컬 환경을
실행 중인 실행 컨텍스트의 렉시컬 환경으로 되돌립니다.
이처럼 let,const 키워드를 사용하는 반복문은 마치 스냅샷을 찍는것처럼 값을 저장합니다.
⚡고차함수를 이용한 클로저
//요소가 3개인 배열을 생성하고 배열의 인덱스를 반환하는 함수를 요소로 추가합니다.
//배열의 요소로 추가된 함수들은 모두 클로저입니다.
const funcs = Array.from(new Array(3), (_,i) => () => i ) // (3) [f,f,f]
//배열의 요소로 추가된 함수들을 순차적으로 호출합니다.
funcs.forEach(e => console.log(e()))
반응형
'javascript' 카테고리의 다른 글
요약 정리는 못 참지 않을까요? (9) ES6 함수의 추가 기능 (0) | 2023.01.16 |
---|---|
요약 정리는 못 참지 않을까요?(8) 자바스크립트의 클래스 (0) | 2023.01.16 |
자바스크립트의 this를 이해해보자 (0) | 2023.01.12 |
요약 정리는 못 참지 않을까요? (6) (0) | 2023.01.12 |
요약 정리는 못 참지 않을까요? (5) 프로토타입 (1) | 2023.01.10 |