일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 보안
- 클라우드컴퓨팅
- 컴퓨터과학
- 딥러닝
- 컴퓨터비전
- 소프트웨어
- 알고리즘
- 자바스크립트
- 데이터과학
- 파이썬
- 데이터베이스
- 컴퓨터공학
- 데이터분석
- 소프트웨어공학
- 빅데이터
- 데이터구조
- 네트워크보안
- 2
- 코딩
- Yes
- 네트워크
- 자료구조
- 프로그래밍언어
- 머신러닝
- 웹개발
- I'm Sorry
- 사이버보안
- 인공지능
- 버전관리
- 프로그래밍
- Today
- Total
스택큐힙리스트
자바스크립트 클로저는 어떻게 작동하나요? 본문
이 질문에 대한 답변은 #@$$#^$$&입니다. 기존에 있는 답변을 편집하여이 게시물을 개선하십시오. 새로운 답변이나 상호 작용을 현재 받지 않고 있습니다.
JavaScript 클로저를 함수, 변수 및 관련 개념에 대한 이해는 있지만 클로저 자체를 이해하지 못하는 사람에게 설명하는 방법은 어떻게 될까요?
저는 위키백과에서 the Scheme example을(를) 본 적이 있지만, 유감스럽게 도움이 되지 않았습니다.
답변 1
클로저는 쌍을 이룹니다:
기능과
그 함수의 외부 범위 (어휘적 환경)에 대한 참조
어휘 환경은 모든 실행 문맥(스택 프레임)의 일부이며 식별자(즉, 로컬 변수 이름)와 값 사이의 매핑입니다.
자바스크립트의 모든 함수는 외부 어휘적 환경에 대한 참조를 유지합니다. 이 참조는 함수가 호출될 때 생성된 실행 컨텍스트를 구성하는 데 사용됩니다. 이 참조는 함수 내부의 코드가 호출된 함수 외부에서 선언된 변수를 보도록하며, 함수가 호출되는 시간과 장소에 관계없이 작동합니다.
만약 함수가 다른 함수에서 호출되고, 다른 함수가 또 다른 함수에서 호출되었다면 바깥쪽 렉시컬 환경에 대한 참조 체인이 만들어집니다. 이 체인은 스코프 체인이라고 합니다.
다음 코드에서, inner은 foo가 호출될 때 생성된 실행 컨텍스트의 언어적 환경과 변수 secret을 close over하는 closure를 형성합니다.
function foo() {
const secret = Math.trunc(Math.random() * 100)
return function inner() {
console.log(`The secret number is ${secret}.`)
}
}
const f = foo() // `secret` is not directly accessible from outside `foo`
f() // The only way to retrieve `secret`, is to invoke `f`
다른 말로, 자바스크립트에서 함수는 접근 권한이있는 함수 (그리고 같은 어휘적 환경 내에 선언 된 다른 함수)만 액세스 할 수있는 프라이빗 상태 상자 참조를 지니고 있습니다. 이 상태 상자는 함수를 호출하는 사람에게는 보이지 않으며 데이터 숨김과 캡슐화를 위한 우수한 메커니즘을 제공합니다.
그리고 기억하세요: JavaScript의 함수는 변수처럼 전달될 수 있습니다 (first-class functions). 이것은 기능과 상태의 쌍을 프로그램 전체에서 전달할 수 있다는 것을 의미합니다. 이는 C++에서 클래스의 인스턴스를 전달하는 것과 유사합니다.
자바스크립트에 클로저가 없다면, 함수 간에 더 많은 상태를 명시적으로 전달해야 하므로 매개변수 목록이 길어지고 코드가 더 복잡해질 것입니다.
그러므로, 함수가 항상 개인 상태에 접근 할 수 있도록하려면 클로저를 사용할 수 있습니다.
...자주 우리는 상태를 기능과 연결하길 원합니다. 예를 들어, 자바나 C++에서 클래스에 개인 인스턴스 변수와 메서드를 추가할 때, 우리는 상태를 기능과 연관시킵니다.
C와 대부분의 주요 언어에서 함수가 반환된 후에는 스택 프레임이 파괴되므로 모든 로컬 변수에 더 이상 액세스할 수 없습니다. JavaScript에서 다른 함수 내에서 함수를 선언하면 바깥 함수의 로컬 변수가 반환 후에도 접근 가능합니다. 이 방법으로 위의 코드에서는 secret 가 inner 함수 객체에서 반환 된 후에도 사용 가능합니다.
클로저의 사용 예시
클로저는 함수와 관련된 비공개 상태가 필요할 때 유용합니다. 이는 매우 일반적인 시나리오이며, 기억하세요: 자바스크립트는 2015년까지 클래스 구문이 없었으며, 아직도 비공개 필드 구문이 없습니다. 클로저가 이러한 필요를 충족합니다.
개인 인스턴스 변수
다음 코드에서 함수 # $$ ** !! @ $ &는 차의 세부 정보를 닫습니다.
function Car(manufacturer, model, year, color) {
return {
toString() {
return `${manufacturer} ${model} (${year}, ${color})`
}
}
}
const car = new Car('Aston Martin', 'V8 Vantage', '2012', 'Quantum Silver')
console.log(car.toString())
함수형 프로그래밍
다음 코드에서 함수inner은 fn와 args 둘 다에 대한 클로져를 닫습니다.
function curry(fn) {
const args = []
return function inner(arg) {
if(args.length === fn.length) return fn(...args)
args.push(arg)
return inner
}
}
function add(a, b) {
return a + b
}
const curriedAdd = curry(add)
console.log(curriedAdd(2)(3)()) // 5
이벤트 중심 프로그래밍
다음 코드에서 함수 onClick는 변수 BACKGROUND_COLOR을 포함합니다.
const $ = document.querySelector.bind(document)
const BACKGROUND_COLOR = 'rgba(200, 200, 242, 1)'
function onClick() {
$('body').style.background = BACKGROUND_COLOR
}
$('button').addEventListener('click', onClick)
모듈화
다음 예제에서는 구현 세부 정보가 즉시 실행 함수 표현식 내부에 숨겨져 있습니다. 함수 tick와 toString는 작업을 완료하는 데 필요한 개인 상태 및 함수를 클로저로 닫습니다. 클로저는 코드를 모듈화하고 캡슐화하는 데 우리에게 능력을 부여했습니다.
let namespace = {};
(function foo(n) {
let numbers = []
function format(n) {
return Math.trunc(n)
}
function tick() {
numbers.push(Math.random() * 100)
}
function toString() {
return numbers.map(format)
}
n.counter = {
tick,
toString
}
}(namespace))
const counter = namespace.counter
counter.tick()
counter.tick()
console.log(counter.toString())
예시
예시 1
이 예시는 지역 변수가 클로저에 복사되지 않음을 보여줍니다: 클로저는 원래 변수에 대한 참조를 유지합니다. 마치 스택 프레임이 외부 함수가 종료된 후에도 메모리에 계속 살아 있는 것처럼 보입니다.
function foo() {
let x = 42
let inner = () => console.log(x)
x = x + 1
return inner
}
foo()() // logs 43
예시 2
다음 코드에서, 세 개의 메서드 log , increment , update는 모두 동일한 어휘적 환경을 둘러싸고(closing over) 있습니다.
그리고 createObject 함수가 호출 될 때마다 새로운 실행 컨텍스트 (스택 프레임)가 생성되며 새로운 변수 x 및 함수 집합 ( log 등)이 생성됩니다. 이 새로운 변수를 포함하는 함수 클로저입니다.
function createObject() {
let x = 42;
return {
log() { console.log(x) },
increment() { x++ },
update(value) { x = value }
}
}
const o = createObject()
o.increment()
o.log() // 43
o.update(5)
o.log() // 5
const p = createObject()
p.log() // 42
예시 3
만약 var 로 선언된 변수를 사용하고 있다면, 이 변수 중 어떤 변수를 클로징하고 있는지 꼭 이해해야 합니다. var 로 선언된 변수들은 호이스트됩니다. let 와 const 의 도입으로 인해 현대의 자바스크립트에서는 이 문제가 훨씬 적게 발생합니다.
다음 코드에서 루프마다 새로운 함수 inner가 생성되며 i을 감싸고 있습니다. 하지만 var i!@은 루프 밖에서 호이스트되므로, 이러한 모든 내부 함수는 같은 변수를 감싸고 있어, i의 마지막 값인 (3) 이 세 번 출력됩니다.
function foo() {
var result = []
for (var i = 0; i < 3; i++) {
result.push(function inner() { console.log(i) } )
}
return result
}
const result = foo()
// The following will print `3`, three times...
for (var i = 0; i < 3; i++) {
result[i]()
}
최종 점수:
자바스크립트에서 함수가 선언될 때마다 클로저가 생성됩니다.
내부 함수에서 # $ @ ** # $ #$ &를 반환하는 것은 클로저의 대표적인 예입니다. 외부 함수 안의 상태는 반환된 내부 함수에서 암묵적으로 사용 가능하기 때문입니다. 이는 외부 함수가 실행 완료된 후에도 유지됩니다.
함수 안에서 eval()를 사용하면 클로저가 사용됩니다. 당신이 eval를 사용하면 함수의 지역 변수를 참조할 수 있으며 비 엄격 모드에서는 eval('var foo = …')를 사용하여 새로운 지역 변수를 생성할 수도 있습니다.
함수 내에서 new Function(…) (the Function constructor)를 사용하면, 의미상 환경을 닫지 않습니다. 대신 전역 컨텍스트를 닫습니다. 새 함수는 외부 함수의 지역 변수에 대한 참조를 할 수 없습니다.
자바스크립트에서의 클로저는 함수 선언 시점에서 해당 스코프의 참조(복사가 아님)를 유지하는 것으로, 이는 다시 외부 스코프를 참조하고, 이와 같이 전부 스코프 체인의 맨 위에 있는 전역 개체까지 참조를 유지합니다.
함수가 선언될 때 클로저가 생성됩니다. 이 클로저는 함수가 호출될 때 실행 컨텍스트를 구성하는 데 사용됩니다.
함수가 호출될 때마다 새로운 지역 변수 집합이 생성됩니다.
링크
다글라스 크로포드의 클로저를 사용한 객체의 시뮬레이션 private attributes and private methods입니다.
클로저가 조심하지 않으면 어떻게 문제가 생길 수 있는지에 대한 훌륭한 설명입니다.
JavaScript Closures에 대한 MDN 문서.
답변 2
자바스크립트의 클로저는 매우 유용한 개념입니다. 클로저가 무엇인지, 어떻게 작동하는지, 그리고 어떻게 활용할 수 있는지 알아보겠습니다.
클로저란 함수 내에서 함수를 반환하거나 다른 함수에서 반환된 함수를 참조할 때 생성되는 개념입니다. 이는 함수가 반환된 후에도 함수 내에서 선언된 변수에 접근할 수 있다는 것을 의미합니다. 따라서, 클로저는 함수의 범위 밖에서도 변수에 접근할 수 있게 해줍니다.
클로저는 주로 콜백 함수로 사용됩니다. 이는 함수(클로저)가 함수(외부 함수)의 변수를 참조하기 때문입니다. 클로저는 외부 함수의 지역 변수도 포함하는데, 이는 외부 함수가 이미 실행된 후에도 해당 변수에 접근이 가능하다는 것을 의미합니다.
클로저를 이용하면, 내부 함수가 외부 함수에 액세스할 수 있음에도 불구하고, 외부 함수는 외부 함수의 지역 변수를 보호할 수 있습니다. 예를 들어, 외부 함수의 변수에 접근이 불가능하더라도 클로저를 이용하여 해당 변수를 변경할 수 있습니다.
그러나 클로저를 사용하는 것이 항상 좋은 것은 아닙니다. 클로저를 남용하면 메모리 누수가 발생할 수 있습니다. 즉, 클로저를 사용하여 참조된 객체가 메모리에서 해제되지 않을 수 있습니다. 따라서, 클로저를 사용할 때에는 적극적으로 메모리 해제를 해주어야 합니다.
결론적으로, 클로저는 자바스크립트에서 매우 유용한 개념입니다. 이를 통해 내부 함수가 외부 함수의 변수를 사용할 수 있으면서도, 외부 변수를 보호할 수 있습니다. 하지만 클로저를 남용하지 않도록 주의해야 하며, 메모리 누수에 대해서도 항상 주의해야 합니다.