ホームページ  >  記事  >  ウェブフロントエンド  >  知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。

知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。

青灯夜游
青灯夜游転載
2022-07-29 09:49:532345ブラウズ

知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。

記事を公開する主な目的は、知識を統合し、より熟練することです。すべては私自身の理解とオンラインで検索した情報に基づいています。何か間違っている場合は、アドバイスをいただければ幸いです。以下は、面接でよくある質問をまとめたものです。自分を鼓舞するために、

js パート

1 を更新し続けます。 me about you プロトタイプ チェーンの理解

js 言語では、各インスタンス オブジェクトには、そのプロトタイプ オブジェクトと、このインスタンス オブジェクトのコンストラクターを指す __proto__ 属性があります。プロトタイプ属性 prototype があります。これは、インスタンス オブジェクトの __proto__ 属性と同じオブジェクトを指します。オブジェクトが属性の値を探しているときに、値がない場合は、それが参照されます。 #Prototype プロトタイプ オブジェクトを検索します。プロトタイプ オブジェクトが存在しない場合は、インスタンス オブジェクトを生成したコンストラクターのプロトタイプ オブジェクトを検索します。まだ存在しない場合は、プロトタイプ オブジェクトを検索します。 Object のプロトタイプ オブジェクトを検索し続けます。上方向に検索すると null になります。この連鎖検索プロセスを Prototype Chain と呼びます。

2. プロトタイプ、コンストラクター、インスタンス オブジェクトの関係

まずはコンストラクターから始めましょう。コンストラクターは、

prototype プロトタイプ オブジェクトを指します。 constructor 属性を通じてこのコンストラクターを参照し、プロトタイプ オブジェクトがどのコンストラクターによって生成されたかを示します。プロトタイプオブジェクトはnewキーワードにより生成されるインスタンスオブジェクトであり、__proto__属性によりインスタンスオブジェクトを生成したコンストラクタのプロトタイプオブジェクトを指すことができ、三角関係を実現する。

知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。

#3. 継承の実装方法

継承にはさまざまな方法があり、インターネット上には多くの答えがあります。自分なりにまとめてみますと、大まかに言うとこの5種類です

1) プロトタイプチェーンの継承

プロトタイプを利用すると、以下に基づいてオブジェクトを作成できます。既存のオブジェクトを使用するため、独自のオブジェクトを作成する必要はありません。タイプを定義します。 object() 関数内では、最初に一時的なコンストラクターが作成され、次に渡されたオブジェクトがコンストラクターのプロトタイプとして使用され、最後にこの一時的な型の新しいインスタンスが返されます。キーコード:

Star.proyotype = new Person(), Star.proyotype.constructor = Star欠点: 親クラスのメソッドのみ継承可能

2) コンストラクターの借用継承

サブクラス コンストラクター内でスーパータイプ コンストラクターを呼び出します。コンストラクターは、

apply() メソッドと call() メソッドを使用して、新しく作成されたオブジェクトに対して実行できます。キーコード: Person.call(this,age,name)欠点: 再利用できず、親クラスの属性のみ継承可能

3) 結合継承

擬似古典継承とも呼ばれます。これは、プロトタイプ チェーンとコンストラクターの借用のテクニックを組み合わせて、両方の長所を活用することを指します。プロトタイプ チェーンを使用してプロトタイプのプロパティとメソッドを継承し、コンストラクターを借用してインスタンス プロパティを継承します。 プロトタイプ上でメソッドを定義することで関数の再利用を実現するだけでなく、各インスタンスが独自の属性を持つことも保証します。ただし、小さなバグがあります。年齢と名前のコピーが 2 つあり、

apply() メソッドと call() メソッドが自動的に呼び出されるため、1 つの値は未定義です。一度。

4) 寄生組み合わせ継承

コンストラクターを借用することでプロパティを継承し、プロトタイプ チェーンの混合形式を通じてメソッドを継承します。基本的に、寄生継承を使用してスーパータイプのプロトタイプから継承し、その結果をサブタイプのプロトタイプに割り当てます。包括的な継承方法として認識されています。すべてを書こうと思っても、まだ膨大です。簡単なものしか知りません。キー コード:

Star.prototype = Object.create(person.prototype )

5) ES6 の Class クラス継承メソッド

class キーワードと extends キーワードを併用して継承を実現できます。 class キーワードはクラスを宣言するために ES6 で導入されました。クラス (クラス) は、

extendssuper のプロトタイプ オブジェクトを指すことによって、親クラスのプロパティとメソッドを継承できます。親クラスであり、呼び出すことができます。 親クラスの属性とメソッド、および super キーワードはサブクラスのコンストラクター メソッド内に存在し、その前に指定する必要があります。

4. js データ型

データ型は一般に 2 つのタイプに分類されます

    基本的なデータ型:文字列、数値、ブール値、Null、未定義、シンボル(nbs)
  • 複雑なデータ型: オブジェクト、配列、関数
  • シンボルは属性名の競合を避けるために一意の値を表します

5. データ型の検出

  • typeof 既存の問題の検出: null または配列がオブジェクトとして出力される

  • instanceof (複雑なデータ型のみが検出可能)
    戻り値は true または false 関連するコンストラクターがプロトタイプ チェーン上にある限り true、それ以外の場合は false となり、それが array

  • #Object.prototype であるかどうかを検出するために使用できます。 toString.call(必須の検出データ値)
    なぜ Object.prototype.toString を借用する必要があるのですか? toString は独自のプロトタイプによって書き換えられており、[object Object]

    のようなものを取得できないためです。

#6. データが配列であることを検出する方法##
var arr = [2, 3, 4]
console.log(arr instanceof Array)
console.log(Array.isArray(arr))
console.log(Object.prototype.toString.call(arr))
##7. 深いコピーと浅いコピー

##浅いコピー: 1 つのレイヤーごとにコピーするだけで、より深いオブジェクト レベルではアドレスのみがコピーされます

  • 深いコピー: レイヤーごとcopy、各レベルのデータがコピーされます

  • 浅いコピー メソッド:

    1. lodash の浅いコピー
  • clone
  • メソッドを使用し、異なるアドレスを指すようにします。

    2.
    Object.assign メソッドを使用する 3. es6 文法を使用する
    .... 拡張演算子
    ディープ コピー メソッド:

    1.
  • JSON.parse(JSON.stringify(obj)) を使用します
  • 、欠点: オブジェクトにメソッドと未定義のプロパティがある場合、それらは失われます

    2.
    recursion を使用します
    循環参照がある場合

      スタック オーバーフローが表示される
    • 解決策: 処理済みのオブジェクトを保存します。新しいオブジェクトの場合は、この保管場所を調べて、それらが適切に処理されたかどうかを確認します。直接返す場合は、
    • let obj = {
              name: "zs",
              age: 20,
              father: [2, 3, 4],
            };
      
            function deepClone(target) {
              //这一行如果不用三元判断 如果是数组会有bug会被拷贝成伪数组对象
              let tempObj = Array.isArray(target) ? [] : {};
              for (let key in target) {
                if (typeof target[key] === "object") {
                  tempObj[key] = deepClone(target[key]);
                } else {
                  tempObj[key] = target[key];
                }
              }
              return tempObj;
            }
      
            let obj1 = deepClone(obj);
            console.log(obj1);
    8. スライスとスライスの違いsplice

両方とも配列の削除方法

  • 1.spliceは元の配列を変更しますが、sliceは元の配列を変更しません。 2.slice は新しい配列を返します。これを使用して配列をインターセプトできます。
  • 3.削除に加えて、スプライスを置換して配列に追加することもできます。
4.splice は渡すことができます。 3 つのパラメータで、スライスは 2 つのパラメータを受け入れます



9、substr と substring の違い

両方の機能は文字列をインターセプトすることです

  • substr は、開始インデックス番号から始まる指定された長さの文字列を抽出します。

  • substring は、指定された 2 つのインデックス番号を抽出します。文字列内の

  • #10 の間の文字 let const var

let と const の違いは両方とも変数の宣言に使用されます

、ES5 では var を使用して変数を宣言できます - let 関数と const 関数を使用する- for ループでの変数昇格の古典的なシナリオを防止します-

グローバル変数を汚染しないでください


var キーワードで変数を宣言します
1. var キーワードで宣言された変数が存在します

変数昇格の問題

; 2. var で宣言された変数が存在しません ブロックレベルのスコープ

、その場合、グローバル変数はどこからでも呼び出すことができます;

3. var 宣言変数の名前が繰り返される場合、後の宣言は前の宣言を上書きします;
let key sub-宣言変数
1.

変数プロモーションなし

、let が変数を宣言するときに変数プロモーションの問題はありません。let が変数を宣言する前に変数が呼び出される場合、エラーが発生します。報告 (初期化前に変数にアクセスできないことを示すプロンプト) ;2.ブロックレベルのスコープ

、変数がブロックレベルのスコープ (グローバル、関数、eval 厳密モード) に存在することを宣言します。現在のコード ブロック内でのみ有効です。現在のコード ブロックの外にある場合、呼び出しはエラーを報告します (現在の変数が定義されていません);

3.スコープ チェーンの操作には影響しません
4.変数の繰り返し宣言は許可されません, let 宣言 変数を繰り返し宣言することはできません。同じ名前が繰り返し宣言されると、エラーが報告されます (現在の識別子はすでに宣言されている);
変数の const 宣言
1. const で宣言された変数には、次の特性もあります:

変数昇格なし

, ブロック レベルのスコープ

繰り返しの宣言

は許可されません;2.const 宣言された変数はすべて 定数 (変更が許可されない量) です。一度宣言すると、変更することはできません。変更すると、エラーが報告されます - 定数変数の割り当て3。一般に、サードパーティのフレームワークでは、変数の宣言に const を多用すると、ユーザーが変数を変更できなくなる可能性があります。フレームワーク; 4. const が実際に保証しているのは、変数の値が変更できないことではなく、変数が指すメモリ アドレスに格納されているデータが変更できないことです。単純なタイプのデータ (数値、文字列、ブール値) の場合、値は変数が指す メモリ アドレス
に格納されるため、定数と同等です。
11. new

の処理 新しい空のオブジェクトを作成します。 (つまり、インスタンス オブジェクト)

    これがこの新しいオブジェクトを指すようにします
  • コンストラクターでコードを実行し、この新しいオブジェクトにプロパティとメソッドを追加しますobject
  • #この新しいオブジェクト obj を返します。 (戻り値は定義されたコンストラクターには書き込まれません。)
  • 12. アンチシェイク スロットリング
  • アンチシェイク

  • 防抖是指在事件触发n秒后再执行,如果在n秒内再次被触发,则重新计算时间。(就是在触发某个事件后,在下一次触发之前,中间的间隔时间如果超过设置的时间才会发送请求,一直触发就不会发送请求 应用场景:
    a、scroll事件滚动触发,
    b、搜索框输入查询
    c、表单验证
    d、按钮提交事件
    e、浏览器窗口缩放,resize事件
function debounce(func, delay) {
        let timer = null // 计时器
        return function (...args) {
          clearTimeout(timer) // 清除上一次计时器
          timer = setTimeout(() => {
            // 重新定时
            func.apply(this, args)
          }, delay)
        }
      }

节流

  • 节流是指如果持续触发某个事件,则每隔n秒执行一次。
function throtte(func, time) {
        let timer = null // 计时器
        return function (...args) {
          if (timer) return // 无视,直接返回
          timer = setTimeout(() => {
            func.apply(this, args)
          }, time)
        }
      }

13、promise的3种状态

这点简单介绍概念,用法后面在详细介绍

1) . 初始态pending

- pending。它的意思是 "待定的,将发生的",相当于是一个初始状态。创建[Promise]对象时,且没有调用resolve或者是reject方法,相当于是初始状态。这个初始状态会随着你调用resolve,或者是reject函数而切换到另一种状态。

2 ). 成功态resolved--也叫fulfilled

- resolved。表示解决了,就是说这个承诺实现了。 要实现从pending到resolved的转变,需要在 创建Promise对象时,在函数体中调用了resolve方法(即第一个参数)。

3) . 失败态rejected

- rejected。拒绝,失败。表示这个承诺没有做到,失败了。要实现从pending到rejected的转换,只需要在创建Promise对象时,调用reject函数。

14、冒泡排序

// 上口诀 双层for循环 外层长度-1 内层长度-1-i
      let arr = [4, 3, 1, 7, 8, 10]
      for (let i = 0; i  arr[j + 1]) {
            let temp = arr[j]
            arr[j] = arr[j + 1]
            arr[j + 1] = temp
          }
        }
      }
      console.log(arr)

Vue部分

1、MVVM

MVVM是三个单词的缩写,model(数据,一般来自ajax或本地存储)+view(视图template)+viewmodel(vue实例)

  • model数据变了,视图会跟着改变,如果用的是v-model,数据也会跟着改变,viewmodel在中间起一个桥梁作用
  • model 和 view 就像现实中房东和租客一样,他们是不认识的,通过中介 viewmodel
    好处
    • 数据驱动
      • 因为数据变了。视图也会跟着变,所以在 vue 中不用操作dom来改变视图
    • 解耦(降低了耦合性)
      • 由于 model 和 view 是没有关系的,是通过 viewmodel 结合在一起的,所以维护起来很方便,因为 model 逻辑代买改了,view 不用改

2、vue生命周期

  • vue中的生命周期是指组件从创建到销毁的过程,主要分为4个周期8个钩子函数

1.分别是创建阶段的beforeCreatecreated,一般在beforeCreate写loading加载效果,使用户体验更好,一般在created中发送ajax请求获取数据

2.然后是挂载阶段的beforeMountmounted,一般会在mounted中操作DOM元素

3.更新阶段的是beforeUpdateupdated,当数据更新时需要做统一的业务处理时,拿到最新的dom,可以使用updated 这个钩子函数

4.最后是销毁阶段的beforeDestroydestroyed,可以在beforeDestroy做一些清理的工作,比如说定时器 和解绑一些addEventListener监听的事件

  • 补充:(还有keep-alive的两个钩子函数,使用场景是当组件切换时会进行销毁,因此组件中的初始化的4个钩子函数会多次执行,比较浪费资源,此时可以使用keep-alive纪行组件的缓存,可以让组件切换时不被销毁,keep-alive有两个独有的钩子函数,分别是activateddeactivated,是组件激活和失活时会执行的两个钩子函数)

3、单向数据流

单向数据流是指父组件向子组件传递数据,子组件通过props接收,当父组件中的值改变了,子组件中对应的数据也会改变,因为props是只读的,所以无法直接在子组件中对父组件传递过来的值进行修改,但是如果这个数据是一个引用数据类型,是可以直接在子组件中修改数据中的某个属性的,只要不改变这个数据的内存地址就可以

4、双向数据绑定

  • 数据 -> 视图
  • 视图 -> 数据

vue中普通指令都可以实现数据变了,视图会跟着变,但是有一个特殊的指令叫v-model,它一般用于表单控件,它可以实现双向数据绑定,所谓的双向数据就是数据变了,视图就会跟着改变,反过来也是

5、v-model原理

v-model一般配合input框使用,实现双向数据绑定的效果,它是v-bindv-on的语法糖,原理是通过v-bind将数据绑定给input框,再通过v-on:input,在input中的值改变时,通过$event可以获取到事件源对象 再通过target.value获取到input中更新后的值 将这个值再赋值给绑定的数据即可

知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。

6、事件传参

在vue的组件使用自定义事件时,$event代表子组件抛出的数据,当这个自定义事件触发一个方法时,
可以不传$event而且可以在方法中进行接收,但是如果写的话就一定要写成$event的形式,这是一个固定写法,
或者这个方法既要传参又要使用事件对象,这个时候$event也是必须要写的
- @click='fn' 在回调函数直接通过参数可以拿到事件对象
- @click='fn($event)' 这个时候@event是固定写法

7、父子组件的声明周期执行顺序

1.初始化阶段时,先执行父组件的beforeCreatecreatedbeforeMount三个钩子函数,然后执行子组件的beforeCreatecreatedbeforeMountmounted四个钩子函数,最后执行父组件的mounted钩子函数

2.更新阶段,先执行父组件的beforeUpdate,然后执行子组件的beforeUpdateupdated,最后执行父组件的updated

3.销毁阶段,先执行父组件的beforeDestroy,然后执行子组件的eforeDestroydestroyed,最后执行父组件的destroyed

8、v-if和v-show的区别

v-ifv-show都可以控制标签,实现组件的显示与隐藏,不同点是v-show是通过display的block和none属性来控制的,当元素隐藏时,页面结构依然存在

  • v-if是通过将元素创建和销毁来控制显示与隐藏的,当v-if的条件为否时,会直接销毁该元素,当满足时会重新创建出来,有可能会影响页面的回流或重绘

  • 如果该元素需要频繁切换时可以使用v-show,不需要频繁切换时可以使用v-if,提高性能

9、v-for和v-if为什么要避免一起使用

  • 因为v-for的优先级比v-if要高,两者同时作用于一个标签或组件时,v-for会优先执行,执行后再进行v-if的判断,但是不满足v-if的条件的时候是可以不执行v-for的,这时候就会造成资源浪费,性能比较差
  • 解决办法是可以通过计算属性将满足v-if判断条件的数据筛选出来,再使用v-if直接渲染筛选后的数据,或者是当v-if不依赖v-for时,可以通过template将v-if写在循环的外部,这样当不满足v-if的判断条件时,就不会再执行v-for了,也可以将数据放在计算属性里面计算过滤出来的数据在交给v-for循环,代替v-if的作用,即可解决。

10、自定义指令:directive

应用场景

  • v-imgerror 公司项目中有的用户头像可能加载报错,可以给他一张默认图片, onerror this.img=默认图片

  • v-focus 打开带有搜索的页面的时候,实现自动把光标定位到 input 中

  • 自定义指令的钩子函数

1.bind 属性绑定的时候执行 只会有一次
2. inserted 当前指令所在的元素插入到页面中的时候执行一次
3. update 当前指令所在的组件中的 data 数据有更新就会执行,可以执行多次

// 指令的钩子有三个 bind inserted update
// bind inserted 只会执行一次
// update 会反复执行
Vue.directive('focus', {
  inserted(el) {
    el.focus()
  },
})

Vue.directive('red', {
  bind(el) {
    el.style.color = 'red'
  },
})

Vue.directive('check', {
  update(el) {
    const reg = /^[a-zA-Z0-9]+$/
    if (reg.test(el.value)) {
      el.style.color = 'green'
    } else {
      el.style.color = 'red'
    }
  },
})

浏览器的缓存机制

这块部分理解不是很透彻,大家浅看一下就可以了?

  • コンセプト: ブラウザーは、リクエストされたリソースをオフライン リソースとして保存します。次回リソースが必要になったとき、ブラウザーは、キャッシュされたリソースを直接使用するか、キャッシュに基づいてサーバーにリクエストを再度送信するかを決定します。メカニズム
    機能:
  • 不要なデータの送信を削減し、サーバーへの負荷を軽減します
  • クライアントのアクセス速度を高速化します
  • ユーザーの機能を強化しますエクスペリエンス
  1. 強力なキャッシュ: 有効期限が切れる前にローカルのオフライン リソースを使用し、サーバーと対話しません
    • http1.0 の有効期限は特定の時間 2023 年 1 月 1 日
    • http1 .1 キャッシュ制御期間 1 年 (高優先度)
  2. ネゴシエーション キャッシュの本質は、ローカルのものとサーバーが古くなっていないか (更新されたリソースがあるかどうか) を確認することです。強力なキャッシュ ネゴシエートのためにサーバーと対話しません。キャッシュは、ものが古くなったかどうかを判断するために一度対話します。
    • http1.0 last-modified/if-modified-since
    • http1.1 etag/if-none-match (高優先度)
  • 現在のページに img があり、その src はロゴです。 png
    1. まず、ローカル キャッシュ リソースがあるかどうかを確認し、ない場合は、サーバーにリクエストを送信して同時にリソースを取得する必要があります expire,cache- control,last-modified,etag(応答メッセージ内)
    2. 一定期間 (不確実) が経過すると、画像とsrc も logo.png です。このとき、ローカルにキャッシュされたリソースがあるかどうかを確認します。見つかった場合は、expire,catch-control (存在する場合) を確認します。つまり、優先順位は cache-control) を確認することであり、有効期限が切れていない場合は、それは問題ありません (この部分は強力なキャッシュに属します) を使用しますが、有効期限が切れていることが判明した場合は、それが開始されます。キャッシュ ネゴシエーション ステージに入り、サーバーにリクエストを送信します。if-modified-since (値は last-modified )/if-none-match( etag)リクエストが送信された後、サーバーは、サーバー上のリソースがローカルのリソースよりも新しいかどうかを確認する比較を開始します。サーバーのリソースがまだ古い場合は、ステータスが返されます。コードは 304 です。ブラウザはステータスが 304 であることを認識し、引き続きローカルのオフライン リソースを使用します。サーバー リソースに更新されたリソースがある場合、ステータス コードは 200 になり、サーバーは新しい logo.png をブラウザとプロセスに渡す必要があります。

デザイン パターン

私の技術スタックは主にフロントエンド Vue であるため、この分野の知識がまだ不足しているため、自分の技術を試してみます。それを明確に説明するのが最善です。実際、私はそれをよく理解していません。それを完全に理解したい場合は、まだ多くの技術的予備力が必要であることは大まかに理解しています。明らかに、私はそうではありません、はは?

1. オブザーバー モード

オブザーバー パターンは、オブジェクトが複数のオブジェクトに依存していることを意味します。依存オブジェクトが更新されると、すべての依存オブジェクトに自動的に通知されます。

  • オブザーバー パターンが定義されていますオブジェクト間の 1 対多の依存関係。オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトが通知され、自動的に更新されます。比喩:
    赤ちゃん-> 両親、祖父母 1 対多の依存関係
    赤ちゃんの泣き声-> 両親と祖父母が駆けつけてくれる オブジェクトの状態が変化すると、それに依存しているすべてのオブジェクトが変化する通知され、自動的に更新されます

  • モードの機能:

    2 つの被験者があります 1 つは観察者です Dep もう 1 つは観察者 監視者です, in vuev-band はこのモデルのコンセプトを採用していますが、結合が高すぎるという欠点があります

2. パブリッシュ/サブスクライブ モデル

パブリッシュ/サブスクライブ モデル実際には、オブジェクト間の 1 対多の依存関係です。オブジェクトの状態が変化すると、それに依存するすべてのオブジェクトに状態変化が通知されます。 。

  • 現在のパブリッシュ/サブスクライブ モデルでは、パブリッシャーと呼ばれるメッセージ送信者はサブスクライバーにメッセージを直接送信しません。つまり、パブリッシャーとサブスクライバーはお互いの存在を知りません。パブリッシャーとサブスクライバーの間には、ディスパッチ センターまたはイベント バスと呼ばれる 3 番目のコンポーネントがあり、パブリッシャーとサブスクライバー間の接続を維持し、パブリッシャーからのすべての受信メッセージをフィルターし、それに応じて応答します。

  • モードの機能:

    3 つの主題があります パブリッシャー ディスパッチ センターのサブスクライバー (vue に反映されます)eventBus このモデルの概念は分離を実現できます

3. 2 つのモデルの違い

  • 被験者の数が異なります。オブザーバー モードには 2 つの被験者があります。

    とオブザーバー watcher。パブリッシュおよびサブスクライブ モデルには、パブリッシャー ディスパッチ センター (イベント チャネル) とサブスクライバー

  • という 3 つの主体があります。オブザーバー モードと同様に、パブリッシュ/サブスクライブ モードにはもう 1 つのイベント チャネルがあります。イベント チャネルは、イベントのサブスクリプションとパブリッシュを管理するディスパッチ センターとして機能し、サブスクライバーとパブリッシャー間の依存関係を完全に分離します。サブスクライバーとパブリッシャーは分離されています (認識されていません)。お互いの存在について)

(学習ビデオ共有: Web フロントエンドの概要 jQuery ビデオ チュートリアル )

以上が知識を定着させるのに役立つ、フロントエンド面接でよくある質問 (回答付き) をまとめました。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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