JavaScript 클로저에 관한 7가지 인터뷰 질문에 답할 수 있나요?

青灯夜游
풀어 주다: 2021-04-14 09:22:44
앞으로
5901명이 탐색했습니다.

JavaScript 클로저에 관한 7가지 인터뷰 질문에 답할 수 있나요?

관련 추천: 2021년 대규모 프런트엔드 면접 질문 요약(모음)

모든 JavaScript 프로그래머는 클로저가 무엇인지 알아야 합니다. JavaScript 인터뷰에서는 클로저 개념에 대해 질문을 받을 가능성이 높습니다.

다음은 JavaScript 클로저에 관한 7가지 어려운 인터뷰 질문입니다.

당신이 얼마나 잘하는지 확인하기 위해 답변을 보거나 코드를 실행하지 마세요. 이 질문을 완료하는 데 약 30분이 소요됩니다.

1. 범위

에는 clickHandler, immediatedelayedReload 기능이 있습니다. clickHandlerimmediatedelayedReload

let countClicks = 0;
button.addEventListener('click', function clickHandler() {
  countClicks++;
});
const result = (function immediate(number) {
  const message = `number is: ${number}`;
  return message;
})(100);
setTimeout(function delayedReload() {
  location.reload();
}, 1000);
로그인 후 복사

这3个函数中哪个能够访问外部范围变量?

答案

  • clickHandler 能够从外部作用域访问变量 countClicks

  • immediate 无法访问外部作用域中的任何变量。

  • delayedReload 从全局作用域(也就是最外层作用域)中访问全局变量 location

相关教程推荐:javascript视频教程

2.  丢失的参数

下列代码输出什么:

(function immediateA(a) {
  return (function immediateB(b) {
    console.log(a); // => ?
  })(1);
})(0);
로그인 후 복사

答案

输出为:0

用参数 0 调用 immediateA,因此 a 参数为 0

immediateB 函数嵌套在 immediateA 函数中,是一个闭包,它从外部 immediateA 作用域中得到 a 变量,其中 a0。因此 console.log(a) 的输出为 0

3. 谁是谁

下面的代码将会输出什么内容?

let count = 0;
(function immediate() {
  if (count === 0) {
    let count = 1;
    console.log(count); // 输出什么?
  }
  console.log(count); // 输出什么?
})();
로그인 후 복사

答案

输出 10

第一个语句  let count = 0 声明了一个变量 count

immediate() 是一个闭包,它从外部作用域得到 count 变量。在 immediate()  函数作用域内, count0

但是,在条件内,另一个 let count = 1 声明了局部变量 count,该变量覆盖了作用域之外的 count。第一个 console.log(count) 输出 1

第二个 console.log(count) 输出为 0 ,因为这里的 count 变量是从外部作用域访问的。

4. 棘手的闭包

下列代码输出什么:

for (var i = 0; i < 3; i++) {
  setTimeout(function log() {
    console.log(i); // => ?
  }, 1000);
}
로그인 후 복사

答案

输出:3, 3, 3

代码分为两个阶段执行。

阶段1

  1. for() 重复 3 次。在每次循环都会创建一个新函数 log(),该函数将捕获变量 isetTimout() 安排log() 在 1000 毫秒后执行。
  2. for() 循环完成时,变量 i 的值为 3

阶段2

第二阶段发生在 1000ms 之后:

  1. setTimeout() 执行预定的 log() 函数。 log() 读取变量 i 当前的值 3,并输出 3

所以输出 3, 3, 3

5. 错误的信息

下面的代码将会输出什么:

function createIncrement() {
  let count = 0;
  function increment() { 
    count++;
  }

  let message = `Count is ${count}`;
  function log() {
    console.log(message);
  }
  
  return [increment, log];
}

const [increment, log] = createIncrement();
increment(); 
increment(); 
increment(); 
log(); // => ?
로그인 후 복사

答案

输出:'Count is 0'

increment() 函数被调用 3 次,将 count 增加到 3

message 变量存在于 createIncrement() 函数的作用域内。其初始值为 'Count is 0'。但即使 count 变量已经增加了几次,message 变量的值也始终为 'Count is 0'

log() 函数是一个闭包,它从 createIncrement() 作用域中获取 message 变量。 console.log(message) 输出录'Count is 0'到控制台。

6. 重新封装

下面的函数 createStack() 用于创建栈结构:

function createStack() {
  return {
    items: [],
    push(item) {
      this.items.push(item);
    },
    pop() {
      return this.items.pop();
    }
  };
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => [10]
stack.items = [10, 100, 1000]; // 栈结构的封装被破坏了
로그인 후 복사

它能正常工作,但有一个小问题,因为暴露了 stack.items 属性,所以任何人都可以直接修改 items 数组。

这是一个大问题,因为它破坏了栈的封装:应该只有 push()pop() 方法是公开的,而 stack.items

function createStack() {
  // 把你的代码写在这里
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined
로그인 후 복사
로그인 후 복사
이 3가지 기능 중 어느 것이 될 수 있나요? 외부 범위 변수에 액세스했습니까? 🎜

🎜Answer🎜

  • 🎜clickHandler는 다음에서 countClicks. 🎜
  • 🎜immediate는 외부 범위의 변수에 액세스할 수 없습니다. 🎜
  • 🎜delayedReload는 전역 범위(즉, 가장 바깥쪽 범위)에서 전역 변수 location에 액세스합니다. 🎜
🎜추천 튜토리얼: javascript 비디오 튜토리얼🎜🎜🎜🎜2. 매개변수 누락🎜🎜🎜다음 코드는 무엇을 출력합니까?🎜
function createStack() {
  const items = [];
  return {
    push(item) {
      items.push(item);
    },
    pop() {
      return items.pop();
    }
  };
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined
로그인 후 복사
로그인 후 복사

🎜Answer🎜

🎜출력은 다음과 같습니다: 0🎜🎜매개변수 사용 0는 immediateA를 호출하므로 a 매개변수는 0입니다. 🎜🎜 immediateB 함수는 immediateA 함수에 중첩되어 있으며 외부 immediateA 범위에서 a 변수, 여기서 <code>a0입니다. 따라서 console.log(a)의 출력은 0입니다. 🎜🎜🎜3. 누구입니까? 🎜🎜🎜다음 코드는 무엇을 출력할까요? 🎜
function multiply(num1, num2) {
  // 把你的代码写在这里...
}
로그인 후 복사
로그인 후 복사

🎜Answer🎜

🎜출력 10🎜🎜첫 번째 문 let count = 0이 A로 선언되었습니다. 변수 개수. 🎜🎜immediate()는 외부 범위에서 count 변수를 가져오는 클로저입니다. immediate() 함수 범위 내에서 count0입니다. 🎜🎜그러나 조건 내에서 또 다른 let count = 1은 지역 변수 count를 선언하며, 이는 범위 > 외부의 count를 재정의합니다. 첫 번째 console.log(count)1을 출력합니다. 🎜🎜여기의 count 변수가 외부 범위에서 액세스되기 때문에 두 번째 console.log(count) 출력은 0입니다. 🎜🎜🎜4. 까다로운 클로저 🎜🎜🎜다음 코드는 무엇을 출력합니까? 🎜
multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22
로그인 후 복사
로그인 후 복사

🎜Answer🎜

🎜출력: 3, 3, 3. 🎜🎜코드는 두 단계로 실행됩니다. 🎜🎜🎜1단계🎜🎜
  1. for() 3번 반복하세요. 변수 i를 캡처하는 새로운 함수 log()가 루프를 통해 매번 생성됩니다. setTimout()log()가 1000밀리초 후에 실행되도록 예약합니다.
  2. for() 루프가 완료되면 변수 i의 값은 3입니다.
🎜🎜2단계🎜🎜🎜두 번째 단계는 1000ms 후에 발생합니다. 🎜
  1. setTimeout() 예약된 log() 함수. <code> log()는 변수 i 3의 현재 값을 읽고 3
을 출력합니다. 🎜그래서 출력은 3, 3, 3입니다. 🎜🎜🎜5. 오류 메시지 🎜🎜🎜다음 코드는 무엇을 출력합니까? 🎜
function multiply(number1, number2) {
  if (number2 !== undefined) {
    return number1 * number2;
  }
  return function doMultiply(number2) {
    return number1 * number2;
  };
}

multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22
로그인 후 복사
로그인 후 복사

🎜Answer🎜

🎜출력: 'Count is 0'🎜🎜 increment() 함수가 세 번 호출되어 count3으로 증가합니다. 🎜🎜message 변수는 createIncrement() 함수 범위 내에 존재합니다. 초기값은 'Count is 0'입니다. 그러나 count 변수가 여러 번 증가하더라도 message 변수의 값은 항상 'Count is 0'입니다. 🎜🎜 log() 함수는 createIncrement() 범위에서 message 변수를 가져오는 클로저입니다. console.log(message)는 콘솔에 'Count is 0'을 출력합니다. 🎜🎜🎜6. 리패키징 🎜🎜🎜다음 함수 createStack()은 스택 구조를 생성하는 데 사용됩니다. 🎜rrreee🎜잘 작동하지만 스택이 .items 속성이 노출되어 누구나 items 배열을 직접 수정할 수 있습니다. 🎜🎜이것은 스택의 캡슐화를 깨기 때문에 큰 문제입니다. push()pop() 메서드만 공개되어야 하고 stack입니다. 항목 또는 기타 세부정보에 접근할 수 없습니다. 🎜

使用闭包的概念重构上面的栈实现,这样就无法在 createStack() 函数作用域之外访问 items 数组:

function createStack() {
  // 把你的代码写在这里
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined
로그인 후 복사
로그인 후 복사

答案

以下是对 createStack() 的重构:

function createStack() {
  const items = [];
  return {
    push(item) {
      items.push(item);
    },
    pop() {
      return items.pop();
    }
  };
}

const stack = createStack();
stack.push(10);
stack.push(5);
stack.pop(); // => 5

stack.items; // => undefined
로그인 후 복사
로그인 후 복사

items 已被移至 createStack() 作用域内。

这样修改后,从 createStack() 作用域的外部无法访问或修改 items 数组。现在 items 是一个私有变量,并且栈被封装:只有 push()pop() 方法是公共的。

push()pop() 方法是闭包,它们从 createStack() 函数作用域中得到 items 变量。

7. 智能乘法

编写一个函数  multiply() ,将两个数字相乘:

function multiply(num1, num2) {
  // 把你的代码写在这里...
}
로그인 후 복사
로그인 후 복사

要求:

如果用 2 个参数调用 multiply(num1,numb2),则应返回这 2 个参数的乘积。

但是如果用 1个参数调用,则该函数应返回另一个函数: const anotherFunc = multiply(num1) 。返回的函数在调用 anotherFunc(num2)  时执行乘法  num1 * num2

multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22
로그인 후 복사
로그인 후 복사

答案

以下是  multiply()  函数的一种实现方式:

function multiply(number1, number2) {
  if (number2 !== undefined) {
    return number1 * number2;
  }
  return function doMultiply(number2) {
    return number1 * number2;
  };
}

multiply(4, 5); // => 20
multiply(3, 3); // => 9

const double = multiply(2);
double(5);  // => 10
double(11); // => 22
로그인 후 복사
로그인 후 복사

如果 number2 参数不是 undefined,则该函数仅返回 number1 * number2

但是,如果 number2undefined,则意味着已经使用一个参数调用了 multiply() 函数。这时就要返回一个函数 doMultiply(),该函数稍后被调用时将执行实际的乘法运算。

doMultiply() 是闭包,因为它从 multiply() 作用域中得到了number1 变量。

总结

如果你答对了 5 个以上,说明对闭包掌握的很好。如果你答对了不到 5 个,则需要好好的复习一下了。

原文地址:https://dmitripavlutin.com/simple-explanation-of-javascript-closures/

转载地址:https://segmentfault.com/a/1190000039366748

更多编程相关知识,请访问:编程视频!!

위 내용은 JavaScript 클로저에 관한 7가지 인터뷰 질문에 답할 수 있나요?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:segmentfault.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!