首頁  >  文章  >  web前端  >  總結一些前端常見面試題(附答案),帶你鞏固知識點!

總結一些前端常見面試題(附答案),帶你鞏固知識點!

青灯夜游
青灯夜游轉載
2022-07-29 09:49:532415瀏覽

總結一些前端常見面試題(附答案),帶你鞏固知識點!

發布文章主要也是鞏固自己的知識更加熟練,全憑自己的理解和網上查資料總結出來的,如有不對的地方還望多多指點。以下是我總結的常見面試題,為了督促自己還可以會繼續更新

#js部分

1、談一談你對原型鏈的理解

在js語言中,每個實例物件都有一個__proto__屬性,改屬性指向他的原型對象,而這個實例對象的建構函數都有一個原型屬性prototype,與實例對象的__proto__屬性指向同一個對象,當這個對像在查找一個屬性的值時,自身沒有就會根據__proto__向他的原型上尋找,如果不存在,則會到生成這個實例物件的建構函式的原型物件上尋找,如果還是不存在,就繼續道Object的原型物件上找,在往上找就為null了,這個鍊式尋找的過程,就被稱為原型鏈

2、原型、建構子、實例物件三者的關係

先從建構子說起,建構子透過prototype指向他的原型對象,原型物件透過他的constructor屬性指回這個建構函數,表明原型物件是由哪個建構函數產生的。原型對象透過new關鍵字產生的實例對象,這個實例對象可以透過__proto__屬性指向產生這個實例對象的建構函數的原型對象,實現一個三角關係。

總結一些前端常見面試題(附答案),帶你鞏固知識點!

3、實現繼承的方式

#繼承的方式有很多種,網路上的答案都有很多,我自己總結且大致說的明白的有這五種

1)原型鏈繼承

借助原型可以基於已有的對象創建對象,同時還不必因此創建自定義類型。在 object()函數內部,先建立一個暫時的建構函數,然後將傳入的物件作為這個建構 函數的原型,最後傳回了這個臨時型別的一個新實例。關鍵程式碼:Star.proyotype = new Person(), Star.proyotype.constructor = Star缺點:只能繼承父類別的方法

2)借用建構子繼承

在子類別建構子的內部呼叫超類型建構函式。可以透過使用 apply()call()方 法在新建立的物件上執行建構子。關鍵程式碼:Person.call(this,age,name)缺點:無法重複使用,只能繼承父類別的屬性

3)組合繼承

也叫偽經典繼承。指的是將原型鍊和借用構造函數的技術組合到一 起,從而發揮二者之長。使用原型鏈實作原型屬性屬性和方法的繼承,透過借用建構函式來實現實例 屬性的繼承。 既透過在原型上定義方法實現了函數復用,又能保證每一個實例都有它自己的屬性。但會有一個小bug,裡面的age,name,有兩份,有一份的值為undefined,因為裡面的apply()call()方法會自動多調用一次。

4)寄生組合繼承

透過借用建構子來繼承屬性,透過原型鏈的混成形式來繼承方法。本質上,就是使用寄生式繼承來繼承超類型的原型,然後再將結果指定給子類型的原型。是公認繼承比較全面的一種方法,要寫全的話還是非常多的,我只會一個簡單的?,關鍵代碼:Star.prototype = Object.create(Person.prototype)

5)ES6的Class類別繼承方式

可利用class關鍵字配合extends關鍵字來實現繼承。 ES6中引入了class關鍵字來聲明類,而class(類)可透過extends來繼承父類中屬性和方法,super指向父類的原型對象,可以調用父類別的屬性和方法,且子類別constructor方法中必須有super關鍵字,且必須出現在this之前。

4、js資料型別

資料型別從大的方向來說分為兩種

  • 基本資料類型:字串(String),數字(Number),布林(Boolean),空(Null),未定義(Undefined),Symbol(nbs)
  • 複雜資料類型:物件(Object),陣列(Array),函數(Function)
    Symbol表示獨一無二的值,避免屬性名稱的衝突

5、偵測資料型別

  • typeof 偵測存在的問題:null 或陣列印出來也是object

  • instanceof (只能偵測複雜資料型別)
    傳回值是 true 或 false 相關的建構子只要在原型鏈上,就是true,否則就是false 可以用來偵測是不是陣列

  • 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. 使用lodash 淺拷貝clone 方法,讓他們兩個指向不同位址
    2. 使用Object.assign 方法
    3. 使用es6語法的... 拓展運算子

  • 深拷貝方法:
    1. 使用JSON.parse(JSON.stringify(obj)) ,缺點:當物件有方法和undefined屬性的時候會遺失
    2. 使用遞歸

      ##如果存在
    • 循環引用就會出現堆疊溢位
    • 解決想法:把處理好的物件存起來,在處理新的物件的時候,會現在這個存的地方找一找有沒有處理好,如果有就直接回傳就行了
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、slice和splice的差別

##兩者都是
    數組刪除
  • 的方法
  • 1.splice改變原始數組,slice不改變原始數組。
2.slice會傳回新的數組,可以用來截取數組

3.splice除了可以刪除之外,還可以替換,新增數組
4.splice可傳入3個參數,slice接受2個參數

9、substr和substring的區別

    都的作用都是
  • 截取字串

  • substr是從起始索引號開始提取指定長度的字串
  • substring是提取字串中兩個指定索引號之間的字元
10、let const  var區別

let和const都是用來

宣告變數

的,在ES5中我們可以使用var來進行變數聲明 -使用let和const作用- 防止for迴圈中變數提升的經典場景-
不污染全域變數

var關鍵字宣告變數

1.var關鍵字宣告變數存在,

變數提升

的問題;2.var宣告的變數不存在區塊層級作用域
,如果是全域變數在任何地方都可以呼叫;3.var宣告變數如果名稱重複了,後面宣告的會將前面宣告的覆寫掉;

let關鍵子宣告變數

1.

不存在變數提升

,let宣告變數不存在變數提升的問題:如果在let宣告變數前呼叫變數就會報錯(提示初始化前無法存取該變數) ;2.區塊級作用域
,let宣告變數存在區塊級作用域(全域、函數、eval嚴格模式),只在目前的程式碼區塊中生效,如果在目前程式碼區塊以外呼叫就會報錯(目前的變數沒有定義);3.不影響作用域鏈的操作
4.不允許變數重複宣告
,let宣告的變數是不允許重複宣告的,如果同一個名稱被重複宣告了就會報錯(目前的識別已經被宣告了);

const宣告變數

# 1.const宣告的變數也具有:

不存在變數提升

區塊層級作用域不允許重複宣告的特點;2.const宣告的變數都是常數
(不允許改變的量),一旦宣告就不允許被修改,如果修改就會報錯--常數變數賦值3.一般第三方的框架中會大量使用const聲明變量,這樣可以避免用戶修改框架中的變量;4.const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對於簡單類型的資料(數值、字串、布林值),值就保存在變數指向的那個
記憶體位址
,因此等同於常數。

11、new的流程

    建立一個新的空物件。 (即實例物件)
  • 讓this指向這個新物件
  • 執行建構子裡面的程式碼,為這個新物件新增屬性和方法
  • 回傳這個新物件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 expire 特定的時間2023年1月1日
    • #http1 .1 cache-control 時間期限1年(優先級高)
  2. #協商快取本質是看本地東西和伺服器有沒有變舊(伺服器上有沒有更新的資源) 強緩存不會和伺服器互動協商快取會互動一次來判斷東西有沒有變舊
    • http1.0 last-modified/if-modified-since
    • http1.1 etag/if-none- match(優先順序高)
  • 目前頁面中有一個img,它的src是logo.png
    1. 先看本機有沒有快取資源,如果沒有,就需要向伺服器發送請求拿回來這個資源同時拿回來expire,cache-control,last-modified,etag(回應封包中)
    2. 過了一段時間(不確定的),又有個別的頁面上面有一個img,src也是logo.png,這個時候就去看一下本地有沒有快取資源,發現有,再看一下它expire,catch-control(如果有,優先權是看cache-control),如果沒有過期,就用就行了(這塊屬於強緩存) 但是發現如果過期了,就開始進入協商緩存的階段,就向伺服器發送一個請求把if-modified-since(值就是last-modifyed )/if-none-match(etag)透過要求頭髮過去,  伺服器開始比較看看伺服器上的資源有沒有比本地更新一點,如果伺服器資源還是舊的,傳回一個狀態碼叫304,瀏覽器一看狀態是304就繼續用本地離線資源,如果伺服器資源有更新的資源,狀態碼就是200,伺服器就需要傳給瀏覽器一個新的logo.png,流程重新再走一遍

設計模式

本人技術堆疊是主要是前端vue的,所以對這方面的知識還是有所欠缺的,盡量說的明白一點,其實我也不是很懂,大致明白,如果想要全面理解透還是需要很多技術儲備的,很明顯我不是的哈哈?

1、觀察者模式

觀察者模式即一個物件被多個物件所依賴,當被依賴的物件發生更新時,會自動通知所有依賴的物件

  • 觀察者模式定義了物件間的一種一對多的依賴關係,當一個物件的狀態改變時,所有依賴它的物件都會被通知,並自動更新
    比喻:
    寶寶-> 父母爺爺奶奶一對多的依賴關係
    寶寶哭-> 父母爺爺奶奶趕緊過來服務當一個對象的狀態發生改變時,所有依賴於它的對像都將得到通知,並自動更新

  • 模式特徵: 有二主體 一個是被觀察者Dep 一個是觀察者watcher,在vue中v- band就是採用這種模式理念,缺點是耦合性太高

#2、發布訂閱模式

發布-訂閱模式其實是一種物件間一對多的依賴關係,當一個物件的狀態發送改變時,所有依賴它的物件都會得到狀態改變的通知。

  • 在現在的發布訂閱模式中,稱為發布者的訊息發送者不會將訊息直接發送給訂閱者,這意味著發布者和訂閱者不知道彼此的存在。在發布者和訂閱者之間存在第三個元件,稱為調度中心或事件通道(event bus),它維持著發布者和訂閱者之間的聯繫,過濾所有發布者傳入的消息並相應地分發它們給訂閱者

  • 模式特點:有三個主體 發布者調度中心訂閱者,在vue中eventBus體現出來了這種模式理念,可以實現解耦

3、兩者模式區別

  • 主體數量不一樣,觀察者模式有二個主體分別是被觀察者Dep 和觀察者watcher,發布訂閱模式有三個主體分別是發布者調度中心(事件通道) 訂閱者

  • 發布訂閱模式相比觀察者模式多了個事件通道,事件通道作為調度中心,管理事件的訂閱和發布工作,徹底隔絕了訂閱者和發布者的依賴關係,訂閱者和發布者是解耦的(不知道彼此存在)

(學習影片分享:web前端入門jQuery影片教學

以上是總結一些前端常見面試題(附答案),帶你鞏固知識點!的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除