마감은 누구나 외울 수 있는 한두 문장이면 됩니다. 그러나 종결은 초보자가 인터뷰 10번 중 8번을 접할 수 있는 질문 유형입니다. 대답하지 못하면 제안이 주어지고, 대답할 수 있으면 점수를 얻지 못합니다. 프론트엔드 개발을 시작하고 포기하는 일을 방지하기 위해 제가 생각하는 JS의 클로저에 대해 이야기하겠습니다.
클로저란 무엇인가요?
클로저는 이 범위의 변수를 참조한 후 어휘 범위 외부에서 자유롭게 액세스할 수 있는 함수입니다.
의 조합 클로저는 자유 변수를 참조하는 함수라고 다른 말로 표현할 수 있습니다. 이 자유 변수는 생성된 환경과 분리되어 있어도 함수와 함께 존재합니다. 따라서 클로저가 컨텍스트에 바인딩된 함수라는 것을 자주 볼 수 있으며 아마도 이것이 의미하는 바일 것입니다. 일단 당신이 그것을 이해하고 나면, 그것은 사실 아주 단순한 일이고 그리 심오하지 않다는 것을 느끼게 될 것입니다.
다음 소개에서도 클로저란 함수와 함수가 선언되는 어휘적 환경의 결합이라는 설명이 여전히 마음에 들어서 이 설명을 바탕으로 설명도 해보겠습니다.
클로저는 실제로 컴퓨터 과학의 개념이며 JS에만 국한된 것이 아닙니다. 클로저의 개념은 1960년대에 등장했으며, 클로저를 구현한 최초의 프로그래밍 언어는 Scheme이었습니다. (Scheme이 무엇인지는 묻지 마세요. 물어봐도 모르겠습니다. 이 문단은 Wiki에서 복사한 것입니다.) 그 이후에는 함수형 프로그래밍 언어에서 클로저가 널리 사용되었습니다.
JS의 클로저
이제 최선을 다해 맨손으로 클로저를 당겨보겠습니다.function sayHello(name) { let str = `Hello,${name}`; function say() { console.log(str); } return say; } let myHello = sayHello('abby'); myHello(); // Hello,abby
예를 들어
예 1: 클로저는 반드시 함수를 반환할 필요는 없습니다일반적인 클로저는 함수를 반환하지만 클로저는 반드시 반환할 필요는 없습니다. 범위 외부의 변수입니다. 다음과 같은 다른 방법으로도 이를 수행할 수 있습니다.let say; function sayHello(name) { let str = `Hello,${name}`; say = function() { console.log(str); } } let myHello = sayHello('abby'); say(); // Hello,abby
let get, up, down function setUp() { let number = 20 get = function() { console.log(number); } up = function() { number += 3 } down = function() { number -=2; } } setUp(); get(); // 20 up(); down(); get(); // 21
function newClosure() { let array = [1, 2]; return function(num) { array.push(num); console.log(`array:${array}`); } } let myClosure = newClosure(); let yourClosure = newClosure(); myClosure(3); // array:1,2,3 yourClosure(4); // array:1,2,4 myClosure(5); // array:1,2,3,5
function newClosure() { for(var i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }) } } newClosure(); // 5个5
打印的结果大家也知道是5个5,因为 setTimeout 里面的函数保持对 i 的引用,在setTimeout的回调函数被执行的时候这个循环早已经执行完成,这里我之前在另一篇文章里面做过更深入的介绍:深入浅出Javascript事件循环机制(上)。
这里我要说的是我们如何才能得到我们想要的01234,在这里有两种做法。
一种是 创建一个新的闭包对象,这样每个闭包对象里面的变量就互不影响。例如下面的代码种每次 log(i)都会创建不同的闭包对象,所有的回调函数不会指向同一个环境。
function log(i) { return function() { console.log(i); } } function newClosure() { for(var i = 0; i < 5; i++) { setTimeout(log(i)); } } newClosure(); // 0 1 2 3 4
另一种做法就是使用自执行函数,外部的匿名函数会立即执行,并把 i 作为它的参数,此时函数内 e 变量就拥有了 i 的一个拷贝。当传递给 setTimeout 的匿名函数执行时,它就拥有了对 e 的引用,而这个值是不会被循环改变的。写法如下:
function newClosure() { for(var i = 0; i < 5; i++) { (function(e) { setTimeout(function() { console.log(e); }) })(i) } } newClosure(); // 0 1 2 3 4
看看,写这么多,多累是不是,还是let省事,所以赶紧拥抱 es6 吧。。。
好了,这次是真的结束了,我所理解的闭包大概就是这样了,如果理解有所偏差,欢迎指出,谁当初不是从颗白菜做起的呢,学习前端的小伙伴们可以看看哦!
关于闭包:
위 내용은 JavaScript의 클로저의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!