ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript のクロージャーに関する面接での 7 つの質問、答えることができますか?

JavaScript のクロージャーに関する面接での 7 つの質問、答えることができますか?

青灯夜游
青灯夜游転載
2021-03-26 09:41:575929ブラウズ

JavaScript のクロージャーに関する面接での 7 つの質問、答えることができますか?

関連する推奨事項: 2021 年の主要なフロントエンド面接の質問の概要 (コレクション)

すべての JavaScript プログラマーが知っておくべきこと閉鎖です。 JavaScript の面接では、おそらくクロージャーの概念について質問されるでしょう。

以下は、JavaScript クロージャーに関する面接でのさらに難しい 7 つの質問です。

自分の実力を確かめるために、答えを見たり、コードを実行したりしないでください。これらの質問を完了するには約 30 分かかります。

1. スコープ

には、次の関数 clickHandlerimmediate、および layedReload があります。 # #

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 外部スコープ内の変数にはアクセスできません。

  • layedReload グローバル スコープ (つまり、最も外側のスコープ) からグローバル変数 location にアクセスします。

推奨される関連チュートリアル:

javascript ビデオ チュートリアル

2. 失われたパラメータ

次のコード出力内容:

(function immediateA(a) {
  return (function immediateB(b) {
    console.log(a); // => ?
  })(1);
})(0);

Answer

出力は次のとおりです:

0

パラメータを指定した呼び出し

0immediateA なので、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); // 输出什么?
})();

答え

出力

1

0最初のステートメント

let count = 0

は変数 count を宣言します。

immediate()

は、外部スコープから count 変数を取得するクロージャです。 immediate() 関数のスコープ内では、count0 です。 ただし、条件内では、別の

let count = 1

がローカル変数 count を宣言しており、スコープ外の count# をオーバーライドします。最初の console.log(count)1 を出力します。 2 番目の console.log(count)

出力は

0 です。これは、ここの count 変数が外部スコープからアクセスされているためです。 4. トリッキーなクロージャ

次のコードは何を出力しますか:
for (var i = 0; i < 3; i++) {
  setTimeout(function log() {
    console.log(i); // => ?
  }, 1000);
}

回答

出力: 3

33コードは 2 段階で実行されます。

フェーズ 1

for()
    3 回繰り返します。新しい関数
  1. log() が各ループで作成され、変数 i をキャプチャします。 setTimout() log() が 1000 ミリ秒後に実行されるようにスケジュールします。 for()
  2. ループが完了すると、変数
  3. i の値は 3 になります。
  4. フェーズ 2

2 番目のフェーズは 1000 ミリ秒後に発生します:

setTimeout()
    スケジュールされた実行
  1. log() 関数。 log() 変数 i3 の現在の値を読み取り、3 を出力します。
  2. 3

33#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(); // => ?

Answer

Output : '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 にもその他の詳細にもアクセスできません。 <p>使用闭包的概念重构上面的栈实现,这样就无法在 <code>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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。