技術共有

フロントエンドインタビューコードの質問

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

この記事は、面接プロセス中に遭遇したコーディングに関する質問をまとめたものです。

1. 変動プロモーション

2. 配列関連のメソッド

返される真の値はフィルタリングではなく保持用であるため、忘れないでください。何でもない、半年も直接書かないと忘れてしまうだけだ。 。 。

arr.filter((項目, インデックス, 現在) => {return arr.indexOf(item) == インデックス});。重量を取り除くことができます

フィルターの本質は新しい配列を作成することであり、コールバック関数が true を返した場合、その配列は保持されます。上記のコード行は、最初の時間のみが内部に配置されることを意味します。

ダブルポインターの重複排除:

ダブルポインタを使用して配列を並べ替えます。それらが等しい場合、高速ポインタは 1 つ右に移動し、高速ポインタは 1 つ右に移動します。次回との比較のために右への高速ポインタ:

  1. function doublePointer(nums) {
  2. if(nums.length < 2) {
  3. return nums;
  4. }
  5. let slow = 0;
  6. let fast = 1;
  7. let result = [nums[0]];
  8. while(fast < nums.length) {
  9. if (result[slow] == nums[fast]) {
  10. fast++;
  11. } else {
  12. slow++;
  13. result[slow] = nums[fast];
  14. fast++;
  15. }
  16. }
  17. return result;
  18. }
  19. const arr = [1,1,2,2,4,4];
  20. console.log(doublePointer(arr));

[1,1,2,2,4,4]を入力し、[1,2,4]を出力します。

配列がオブジェクトの場合:

定数 arr2 = [{id:1,time: 2},{id:1,time: 4},{id:2,time: 2},{id:2,time: 4},{id:3,time: 5},

{id:3,時間: 2}];

ここで、ID に基づいて重複を削除する必要があります。ID が等しい場合、最大の時間を持つオブジェクトのみが保持されます。

[{"id":1,"時間":4},{"id":2,"時間":4},{"id":3,"時間":5}]

  1. function doublePointerByorder(nums) {
  2. if(nums.length < 2) {
  3. return nums;
  4. }
  5. let slow = 0;
  6. let fast = 1;
  7. let result = [nums[0]];
  8. while(fast < nums.length) {
  9. if (result[slow].id == nums[fast].id) {
  10. if(result[slow].time < nums[fast].time) {
  11. result[slow] = nums[fast];
  12. }
  13. fast++;
  14. } else {
  15. slow++;
  16. result[slow] = nums[fast];
  17. fast++;
  18. }
  19. }
  20. return result;
  21. }

console.log(doublePointerByorder(arr2)); 以上です。

もちろん、空のオブジェクトを使用して、その都度、オブジェクト内の ID に対応する時間を比較し、上書きするかどうかを選択することもできます。走査後、for in ループを使用してオブジェクトを配列に変換します。ただし、データ量が大きい場合は、ダブル ポインターを使用する方が効率的です。

3. 参考文献関連

参照型変数の等号の割り当ては相互に影響しません。

ただし、以下に示すように、浅いコピーとみなされる ab を使用すると影響を受けます。

  1. person1 = {name: 3};
  2. members = person1;
  3. members.name = 4;   // person1.name=4

引用に関連する典型的なケースを見てみましょう。これは、私がインタビュー中に初めて遭遇したときにメモしなかった質問でもありました。配列をツリー構造に変換します。

  1. function arrayToTree(items) {
  2. const tree = {};
  3. const map = {};
  4. items.forEach((item, index) => {
  5. const { id, parentId } = item;
  6. if (!map[id]) map[id] = { children: [] };
  7. const node = { ...item, children: map[id].children};
  8. map[id] = node;
  9. if (parentId) {
  10. if (!map[parentId]) {
  11. map[parentId] = { children: [] };
  12. } map[parentId].children.push(node);
  13. } else {
  14. tree[id] = node;
  15. }
  16. });
  17. console.log(map);
  18. }
  19. // 示例数组
  20. const items = [
  21. { id: 1, parentId: null, value: "A" },
  22. { id: 2, parentId: 1, value: "B" },
  23. { id: 3, parentId: 1, value: "C" },
  24. { id: 4, parentId: 2, value: "D" },
  25. { id: 5, parentId: 3, value: "E" }
  26. ];
  27. // 转换为树
  28. const tree = arrayToTree(items);

ロシアのマトリョーシカ人形のように、直接コピーして効果を確認できます。最初のレイヤーに 2 番目のレイヤーを追加すると、わかりやすいです。難しいのは、2 番目のレイヤーに 3 番目のレイヤーを追加する場合です。実際、よく考えてみると、a["1"] の下に a["1"].children["2"] があることがわかります。とその値が a["2"] と等しいだけでなく、参照もすべて同じなので、 a["1"].children.push(a["2"]); を実行します。この利点は、a["3"]={...item,children:[]} が実行されたとき、a["2"].children.push(a["3"]) が実行されたときに得られます。操作データなので、同じ参照を持つ場所 (たとえば、a=b、b.push は a.push にも影響します) もプッシュされるため、a["1"].children["2"] が表示されます。 .children a["3"]。これは正しいツリー構造です。

それでも理解できない場合は、次のことを試してみてください。

上に示すように、b1 は a1 の第 1 レベルのノードとみなされ、b1 を変更すると a1 に影響します。上記はループですが、各スコープ内の参照は同じです。

3. マクロタスクとマイクロタスク

2 4 5 同期コード、3 マイクロ タスク、1 マクロ タスク。唯一の落とし穴は、4 は出力されますが、return 3 は実行されないことです。

4. 比較演算子

暗黙的な変換比較中に、配列は toString メソッドを呼び出します。

5.手ぶれ防止と手書き入力制限

これまでに書いたことがない場合は、面接中に破る必要がありますが、破ることができない可能性が高くなります。以下は、アンチシェイクの即時実行と遅延実行、スロットリングの即時実行と遅延実行です。

  1. function debounce(fn, delay) {
  2. let timer = null;
  3. return function (...args) {
  4. timer && clearTimeout(timer);
  5. timer = setTimeout(() => {
  6. fn.apply(this, args);
  7. }, delay);
  8. }
  9. }
  10. function debounce_immediate(fn, delay, immediate = false) {
  11. let timer = null;
  12. let flag = true;
  13. return function (...args) {
  14. timer && clearTimeout(timer);
  15. if (immediate) {
  16. if (flag) {
  17. fn.apply(this, args);
  18. flag = false;
  19. }
  20. timer = setTimeout(() => {
  21. flag = true;
  22. }, delay);
  23. } else {
  24. timer = setTimeout(() => {
  25. fn.apply(this, args);
  26. }, delay);
  27. }
  28. }
  29. }
  30. function throttle(fn, delay) {
  31. let lastTime = 0;
  32. let timer = null;
  33. return function (...args) {
  34. const nowTime = Date.now();
  35. if (nowTime - lastTime > delay) {
  36. fn.apply(this, args);
  37. lastTime = nowTime;
  38. }
  39. }
  40. }
  41. function throttle_D(func, delayTime) {
  42. let delay = delayTime || 1000;
  43. let timer = null;
  44. return function (...args) {
  45. if (!timer) {
  46. timer = setTimeout(function () {
  47. func.apply(this, args);
  48. timer = null;
  49. }, delay);
  50. }
  51. }
  52. }

必ず引数を指定してください。アンチシェイクとスロットルの本質的な違いは、アンチシェイクは常にタイマーをリセットしますが、スロットルは常にトリガーされず、一定の時間間隔内で 1 回だけ実行されることです。手ぶれ補正が 1 分間トリガーされる場合、それは 1 回だけ実行されます (即時実行または最後のクリックによってトリガーされる遅延実行)。