찾다
웹 프론트엔드JS 튜토리얼JavaScript의 클로저에 대한 자세한 설명

JavaScript의 클로저에 대한 자세한 설명

Apr 24, 2023 pm 05:57 PM
javascript프런트 엔드폐쇄

JavaScript 클로저는 JavaScript 프로그래밍에서 널리 사용되는 중요한 개념입니다. 초보자에게는 혼란스러울 수 있지만 JavaScript 언어의 핵심을 이해하는 데 있어 핵심 개념 중 하나입니다. 이 기사에서는 JavaScript 클로저에 대해 자세히 알아보고 실제 애플리케이션에서 작동 방식과 사용 방법을 이해할 것입니다.

JavaScript의 클로저에 대한 자세한 설명

JavaScript 클로저란 무엇인가요?

JavaScript에서 클로저는 함수가 외부에 정의된 변수에 액세스할 수 있음을 의미합니다. 이러한 변수는 함수에 국한되지도 않고 함수에 대한 인수도 아니기 때문에 종종 "자유 변수"라고 합니다. 클로저는 함수 내부 또는 함수 외부에서 생성될 수 있습니다.

JavaScript의 모든 함수는 모두 자유 변수에 접근할 수 있기 때문에 클로저입니다. 함수가 호출되면 함수의 지역 변수와 매개변수를 포함하는 새로운 실행 환경이 생성됩니다. 실행 컨텍스트에는 함수가 정의된 범위에 대한 참조도 포함됩니다. 이 참조를 함수의 정의를 포함하는 모든 범위 개체의 연결된 목록인 함수의 "범위 체인"이라고 합니다. [추천 학습: javascript 비디오 튜토리얼]

함수 내에서 자유 변수에 접근해야 할 때, 먼저 해당 변수가 자신의 지역 변수에 존재하는지 확인합니다. 존재하지 않으면 변수를 찾을 때까지 범위 체인을 계속 진행합니다. 이것이 클로저의 핵심 메커니즘입니다.

간단히 말하면, 클로저는 외부 변수에 대한 참조를 포함하는 함수입니다. 이러한 변수는 함수 외부에서 정의되지만 여전히 함수 내부에서 액세스하고 조작할 수 있습니다. 클로저의 본질은 함수와 그것이 참조하는 외부 변수를 캡슐화하여 외부 간섭이 없는 환경을 형성하여 함수가 외부 변수에 접근하고 수정할 수 있도록 하는 것이며, 이러한 수정은 함수 외부의 변수에도 반영됩니다.

클로저 작동 방식을 이해하는 것은 고품질 JavaScript 코드를 작성하는 데 중요합니다. 이를 통해 변수와 함수의 범위를 더 잘 관리하고 더 복잡한 기능을 구현할 수 있습니다.

클로저 사용

변수 및 함수 캡슐화

클로저는 변수가 외부 간섭을 받지 않도록 캡슐화하는 데 사용할 수 있습니다. 이는 클로저가 함수 내부에 변수를 정의하고 해당 변수에 액세스하는 함수 외부에 함수를 생성할 수 있기 때문입니다. 이 접근 기능은 변수에 접근할 수 있으나, 외부에서 변수에 직접 접근할 수 없으므로 변수의 보안이 보장됩니다.

예를 들어, 클로저를 사용하여 카운터를 구현할 수 있습니다:

function createCounter() {
  let count = 0;
  return function() {
    count++;
    return count;
  }
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

이 예에서는 클로저를 사용하여 카운터 변수 개수를 캡슐화하여 외부 간섭을 받지 않도록 합니다. 카운터 함수가 호출될 때마다 카운터의 다음 값을 반환합니다.

데이터 캐싱

클로저를 사용하면 함수의 계산 결과를 캐시하여 동일한 값을 여러 번 계산하는 것을 방지하여 코드 성능을 향상시킬 수 있습니다. 이 방법은 피보나치 수열과 같이 계산량이 많지만 결과가 자주 변하지 않는 함수에 적합합니다.

아래 코드 예제를 보세요:

function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key]) {
      return cache[key];
    } else {
      const result = fn(...args);
      cache[key] = result;
      return result;
    }
  }
}

function fibonacci(n) {
  if (n <= 1) {
    return n;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

const memoizedFib = memoize(fibonacci);
console.log(memoizedFib(10)); // 输出 55
console.log(memoizedFib(10)); // 输出 55,直接从缓存中读取

이 예제에서는 함수를 매개변수로 받아들이고 클로저 함수를 반환하는 memoize 함수를 정의합니다. 클로저 함수는 함수의 계산 결과를 저장하는 데 사용되는 캐시 개체 캐시를 내부적으로 유지합니다. 클로저 함수가 호출될 때마다 전달된 매개변수를 기반으로 고유한 키 값을 생성하고 캐시에서 계산 결과를 읽으려고 시도합니다. 키 값이 캐시에 이미 존재하는 경우 캐시 결과를 직접 반환하고, 그렇지 않은 경우 전달된 함수를 호출하여 결과를 계산하고 결과를 캐시에 저장합니다. 이 접근 방식은 동일한 값을 여러 번 계산하는 것을 방지하여 코드 성능을 향상시킵니다.

모듈화 달성

클로저를 사용하면 모듈형 프로그래밍을 구현할 수 있습니다. 이 방법을 사용하면 코드를 여러 모듈로 나눌 수 있으므로 각 모듈은 해당 기능에만 집중할 수 있으므로 코드의 유지 관리성과 안전성이 향상됩니다. 동시에 클로저는 전역 변수의 오염을 방지하면서 공개 및 비공개 변수를 캡슐화할 수도 있습니다.

예를 들어, 클로저를 사용하여 간단한 모듈을 구현할 수 있습니다:

const module = (function() {
  const privateVar = &#39;I am private&#39;;
  const publicVar = &#39;I am public&#39;;
  function privateFn() {
    console.log(&#39;I am a private function&#39;);
  }
  function publicFn() {
    console.log(&#39;I am a public function&#39;);
  }
  return {
    publicVar,
    publicFn
  };
})();

console.log(module.publicVar); // 输出 &#39;I am public&#39;
module.publicFn(); // 输出 &#39;I am a public function&#39;
console.log(module.privateVar); // 输出 undefined
module.privateFn(); // 报错,无法访问私有函数

이 예에서는 내부적으로 객체를 반환하는 즉시 실행 함수를 정의합니다. 객체에는 공용 변수와 함수뿐만 아니라 개인 변수와 함수도 포함됩니다. 이러한 방식으로 코드를 여러 모듈로 나눌 수 있으며, 각 모듈은 자체 기능에만 중점을 두어 코드의 유지 관리성과 가독성을 향상시킵니다. 동시에 개인 변수와 함수는 함수 내부에서만 볼 수 있고 외부에서는 접근 및 수정할 수 없으므로 전역 변수의 오염을 피할 수 있습니다.

이벤트 처리

다음은 이벤트 처리에 클로저를 사용하는 예입니다.

function createCounter() {
  let count = 0;

  function increment() {
    count++;
    console.log(`Clicked ${count} times`);
  }

  function decrement() {
    count--;
    console.log(`Clicked ${count} times`);
  }

  function getCount() {
    return count;
  }

  return {
    increment,
    decrement,
    getCount
  };
}

const counter = createCounter();

document.querySelector(&#39;#increment&#39;).addEventListener(&#39;click&#39;, counter.increment);
document.querySelector(&#39;#decrement&#39;).addEventListener(&#39;click&#39;, counter.decrement);

在这个示例中,我们定义了一个名为createCounter的函数,该函数返回一个对象,该对象包含三个方法:increment,decrement和getCount。increment方法将计数器加1,decrement方法将计数器减1,getCount方法返回当前计数器的值。

我们使用createCounter函数创建了一个计数器对象counter,并将increment方法和decrement方法分别注册为加1和减1按钮的点击事件处理函数。由于increment和decrement方法内部引用了createCounter函数内部的局部变量count,因此它们形成了闭包,可以访问和修改count变量。

这个示例中,我们将计数器对象的逻辑封装在一个函数内部,并返回一个包含方法的对象,这样可以避免全局变量的使用,提高代码的可维护性和可重用性。

函数柯里化

以下是一个使用闭包实现的函数柯里化例子:

function add(x) {
  return function(y) {
    return x + y;
  }
}

const add5 = add(5); // x = 5
console.log(add5(3)); // 输出 8
console.log(add5(7)); // 输出 12

在这个例子中,我们定义了一个名为add的函数,该函数接受一个参数x并返回一个内部函数,内部函数接受一个参数y,并返回x + y的结果。

我们使用add函数创建了一个新的函数add5,该函数的x值为5。我们可以多次调用add5函数,每次传入不同的y值进行求和运算。由于add函数返回了一个内部函数,并且内部函数引用了add函数内部的参数x,因此内部函数形成了一个闭包,可以访问和保留x值的状态。

这个例子中,我们实现了一个简单的函数柯里化,将接收多个参数的函数转化为接收一个参数的函数。函数柯里化可以帮助我们更方便地进行函数复合和函数重用。

异步编程

以下是一个使用闭包实现的异步编程的例子:

function fetchData(url) {
  return function(callback) {
    fetch(url)
      .then(response => response.json())
      .then(data => {
        callback(null, data);
      })
      .catch(error => {
        callback(error, null);
      });
  }
}

const getData = fetchData(&#39;https://jsonplaceholder.typicode.com/todos/1&#39;);
getData(function(error, data) {
  if (error) {
    console.error(error);
  } else {
    console.log(data);
  }
});

在这个例子中,我们定义了一个名为fetchData的函数,该函数接受一个URL参数,并返回一个内部函数。内部函数执行异步操作,请求URL并将响应解析为JSON格式的数据,然后调用传入的回调函数并将解析后的数据或错误作为参数传递。

我们使用fetchData函数创建了一个getData函数,该函数请求JSONPlaceholder API的一个TODO项,并将响应解析为JSON格式的数据,然后将数据或错误传递给回调函数。由于fetchData函数返回了一个内部函数,并且内部函数引用了fetchData函数内部的URL参数和回调函数,因此内部函数形成了闭包,可以访问和保留URL参数和回调函数的状态。

这个例子中,我们使用了异步编程模型,通过将回调函数作为参数传递,实现了在异步请求完成后执行相关的操作。使用闭包可以方便地管理异步请求和相关的状态,提高代码的可读性和可维护性。

闭包的缺陷

JS 闭包具有许多优点,但也有一些缺点,包括:

内存泄漏问题

由于闭包会将外部函数的局部变量引用保存在内存中,因此如果闭包一直存在,外部函数的局部变量也会一直存在,从而导致内存泄漏。

在 JavaScript 中,闭包是指一个函数能够访问并操作其父级作用域中的变量,即便该函数已经执行完毕,这些变量仍然存在。由于闭包会引用父级作用域中的变量,因此,这些变量不会在函数执行完毕时被垃圾回收机制回收,从而占用了内存资源,这就是闭包引起内存泄漏的原因。

以下是一个闭包引起内存泄漏的示例:

function myFunc() {
  var count = 0;
  setInterval(function() {
    console.log(++count);
  }, 1000);
}

myFunc();

在这个示例中,myFunc 函数中定义了一个变量 count,然后创建了一个计时器,在每秒钟打印 count 的值。由于计时器函数是一个闭包,它会保留对 myFunc 中的 count 变量的引用,这意味着即使 myFunc 函数执行完毕,计时器函数仍然可以访问 count 变量,从而阻止 count 变量被垃圾回收机制回收。如果我们不停地调用 myFunc 函数,将会创建多个计时器函数,每个函数都会占用一定的内存资源,最终会导致内存泄漏。

性能问题

由于闭包会在每次函数调用时创建新的作用域链,因此会增加函数的内存消耗和运行时间。在循环中创建闭包时,尤其需要注意性能问题。

在JavaScript中,每当创建一个函数时,都会为该函数创建一个新的作用域链。函数作用域链是一个指向其父级作用域的指针列表,其中包含了该函数能够访问的变量和函数。

클로저란 외부 함수의 변수와 매개변수에 액세스할 수 있고 외부 함수가 호출된 후에도 이러한 변수와 매개변수를 계속 사용할 수 있는 함수 내부에 정의된 함수를 의미합니다. 클로저가 생성되면 필요할 때 액세스할 수 있도록 외부 함수의 범위 체인에 대한 참조를 저장합니다.

클로저는 외부 함수의 범위 체인에 대한 참조를 보유하므로 각 함수 호출마다 새 범위 체인이 생성됩니다. 이는 함수가 동일한 클로저에 의해 생성되더라도 함수를 호출할 때마다 새로운 함수 범위 체인이 생성되기 때문입니다. 즉, 각 클로저에는 자체 범위 체인이 있고 클로저에 대한 각 호출은 새 범위 체인을 생성합니다.

이것이 클로저를 사용할 때 주의해야 하는 이유 중 하나입니다. 클로저를 호출할 때마다 새로운 범위 체인이 생성되므로 메모리 소비 및 성능 문제가 발생할 수 있습니다. 어떤 경우에는 메모리 누수 문제를 피하기 위해 클로저의 리소스를 수동으로 해제해야 할 수도 있습니다.

보안 문제

클로저는 외부 함수의 로컬 변수에 접근할 수 있으므로 개인 데이터가 실수로 로컬 변수에 저장되면 클로저에 의해 접근 및 수정되어 보안 문제가 발생할 수 있습니다.

가독성 문제

클로저는 변수의 수명을 연장하고 데이터를 암시적으로 전달하기 때문에 특히 여러 수준의 함수를 중첩할 때 코드를 이해하고 디버깅하기 어렵게 만들 수 있습니다.

요약

따라서 클로저는 강력한 프로그래밍 기술이지만 이를 사용할 때는 위의 단점에 주의해야 하며 코드의 유지 관리 가능성과 성능을 보장하기 위해 적절한 응용 프로그램 시나리오와 프로그래밍 스타일을 선택해야 합니다.

더 많은 프로그래밍 관련 지식을 보려면 프로그래밍 교육을 방문하세요! !

위 내용은 JavaScript의 클로저에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
Python vs. JavaScript : 커뮤니티, 라이브러리 및 리소스Python vs. JavaScript : 커뮤니티, 라이브러리 및 리소스Apr 15, 2025 am 12:16 AM

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지C/C에서 JavaScript까지 : 모든 것이 어떻게 작동하는지Apr 14, 2025 am 12:05 AM

C/C에서 JavaScript로 전환하려면 동적 타이핑, 쓰레기 수집 및 비동기 프로그래밍으로 적응해야합니다. 1) C/C는 수동 메모리 관리가 필요한 정적으로 입력 한 언어이며 JavaScript는 동적으로 입력하고 쓰레기 수집이 자동으로 처리됩니다. 2) C/C를 기계 코드로 컴파일 해야하는 반면 JavaScript는 해석 된 언어입니다. 3) JavaScript는 폐쇄, 프로토 타입 체인 및 약속과 같은 개념을 소개하여 유연성과 비동기 프로그래밍 기능을 향상시킵니다.

JavaScript 엔진 : 구현 비교JavaScript 엔진 : 구현 비교Apr 13, 2025 am 12:05 AM

각각의 엔진의 구현 원리 및 최적화 전략이 다르기 때문에 JavaScript 엔진은 JavaScript 코드를 구문 분석하고 실행할 때 다른 영향을 미칩니다. 1. 어휘 분석 : 소스 코드를 어휘 단위로 변환합니다. 2. 문법 분석 : 추상 구문 트리를 생성합니다. 3. 최적화 및 컴파일 : JIT 컴파일러를 통해 기계 코드를 생성합니다. 4. 실행 : 기계 코드를 실행하십시오. V8 엔진은 즉각적인 컴파일 및 숨겨진 클래스를 통해 최적화하여 Spidermonkey는 유형 추론 시스템을 사용하여 동일한 코드에서 성능이 다른 성능을 제공합니다.

브라우저 너머 : 실제 세계의 JavaScript브라우저 너머 : 실제 세계의 JavaScriptApr 12, 2025 am 12:06 AM

실제 세계에서 JavaScript의 응용 프로그램에는 서버 측 프로그래밍, 모바일 애플리케이션 개발 및 사물 인터넷 제어가 포함됩니다. 1. 서버 측 프로그래밍은 Node.js를 통해 실현되며 동시 요청 처리에 적합합니다. 2. 모바일 애플리케이션 개발은 재교육을 통해 수행되며 크로스 플랫폼 배포를 지원합니다. 3. Johnny-Five 라이브러리를 통한 IoT 장치 제어에 사용되며 하드웨어 상호 작용에 적합합니다.

Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축Next.js (백엔드 통합)로 멀티 테넌트 SAAS 애플리케이션 구축Apr 11, 2025 am 08:23 AM

일상적인 기술 도구를 사용하여 기능적 다중 테넌트 SaaS 응용 프로그램 (Edtech 앱)을 구축했으며 동일한 작업을 수행 할 수 있습니다. 먼저, 다중 테넌트 SaaS 응용 프로그램은 무엇입니까? 멀티 테넌트 SAAS 응용 프로그램은 노래에서 여러 고객에게 서비스를 제공 할 수 있습니다.

Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법Next.js (Frontend Integration)를 사용하여 멀티 테넌트 SaaS 응용 프로그램을 구축하는 방법Apr 11, 2025 am 08:22 AM

이 기사에서는 Contrim에 의해 확보 된 백엔드와의 프론트 엔드 통합을 보여 주며 Next.js를 사용하여 기능적인 Edtech SaaS 응용 프로그램을 구축합니다. Frontend는 UI 가시성을 제어하기 위해 사용자 권한을 가져오고 API가 역할 기반을 준수하도록합니다.

JavaScript : 웹 언어의 다양성 탐색JavaScript : 웹 언어의 다양성 탐색Apr 11, 2025 am 12:01 AM

JavaScript는 현대 웹 개발의 핵심 언어이며 다양성과 유연성에 널리 사용됩니다. 1) 프론트 엔드 개발 : DOM 운영 및 최신 프레임 워크 (예 : React, Vue.js, Angular)를 통해 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축합니다. 2) 서버 측 개발 : Node.js는 비 차단 I/O 모델을 사용하여 높은 동시성 및 실시간 응용 프로그램을 처리합니다. 3) 모바일 및 데스크탑 애플리케이션 개발 : 크로스 플랫폼 개발은 개발 효율을 향상시키기 위해 반응 및 전자를 통해 실현됩니다.

JavaScript의 진화 : 현재 동향과 미래 전망JavaScript의 진화 : 현재 동향과 미래 전망Apr 10, 2025 am 09:33 AM

JavaScript의 최신 트렌드에는 Typescript의 Rise, 현대 프레임 워크 및 라이브러리의 인기 및 WebAssembly의 적용이 포함됩니다. 향후 전망은보다 강력한 유형 시스템, 서버 측 JavaScript 개발, 인공 지능 및 기계 학습의 확장, IoT 및 Edge 컴퓨팅의 잠재력을 포함합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

SublimeText3 Linux 새 버전

SublimeText3 Linux 새 버전

SublimeText3 Linux 최신 버전

맨티스BT

맨티스BT

Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

WebStorm Mac 버전

WebStorm Mac 버전

유용한 JavaScript 개발 도구