發布文章主要也是鞏固自己的知識更加熟練,全憑自己的理解和網上查資料總結出來的,如有不對的地方還望多多指點。以下是我總結的常見面試題,為了督促自己還可以會繼續更新
在js語言中,每個實例物件都有一個__proto__
屬性,改屬性指向他的原型對象,而這個實例對象的建構函數都有一個原型屬性prototype
,與實例對象的__proto__屬性指向同一個對象,當這個對像在查找一個屬性的值時,自身沒有就會根據__proto__向他的原型
上尋找,如果不存在,則會到生成這個實例物件的建構函式的原型物件上尋找,如果還是不存在,就繼續道Object的原型物件上找,在往上找就為null了,這個鍊式尋找的過程,就被稱為原型鏈
。
先從建構子說起,建構子透過prototype
指向他的原型對象,原型物件透過他的constructor
屬性指回這個建構函數,表明原型物件是由哪個建構函數產生的。原型對象透過new關鍵字產生的實例對象,這個實例對象可以透過__proto__
屬性指向產生這個實例對象的建構函數的原型對象,實現一個三角關係。
#繼承的方式有很多種,網路上的答案都有很多,我自己總結且大致說的明白的有這五種
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之前。
資料型別從大的方向來說分為兩種
typeof
偵測存在的問題:null 或陣列印出來也是object
instanceof
(只能偵測複雜資料型別)
傳回值是 true 或 false
相關的建構子只要在原型鏈上,就是true,否則就是false 可以用來偵測是不是陣列
Object.prototype.toString.call
(要檢測的資料值)
為什麼要藉Object.prototype.toString,因為自己的toString 被自己原型重寫了,得不到類似[object Object]
var arr = [2, 3, 4] console.log(arr instanceof Array) console.log(Array.isArray(arr)) console.log(Object.prototype.toString.call(arr))
#淺拷貝:只是拷貝一層,更深層物件層級的只拷貝了位址
#深拷貝:層層拷貝,每一層的資料都會拷貝
淺拷貝方法:
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);
3.splice除了可以刪除之外,還可以替換,新增數組
4.splice可傳入3個參數,slice接受2個參數
的
的,在ES5中我們可以使用var來進行變數聲明
-使用let和const作用- 防止for迴圈中變數提升的經典場景
-
不污染全域變數
1.var關鍵字宣告變數存在,
變數提升的問題;2.var宣告的變數不存在
區塊層級作用域
,如果是全域變數在任何地方都可以呼叫;3.var宣告變數如果名稱重複了,後面宣告的會將前面宣告的覆寫掉;
1.
不存在變數提升,let宣告變數不存在變數提升的問題:如果在let宣告變數前呼叫變數就會報錯(提示初始化前無法存取該變數) ;2.
區塊級作用域
,let宣告變數存在區塊級作用域(全域、函數、eval嚴格模式),只在目前的程式碼區塊中生效,如果在目前程式碼區塊以外呼叫就會報錯(目前的變數沒有定義);3.
不影響作用域鏈的操作4.
不允許變數重複宣告
,let宣告的變數是不允許重複宣告的,如果同一個名稱被重複宣告了就會報錯(目前的識別已經被宣告了);
# 1.const宣告的變數也具有:
不存在變數提升、區塊層級作用域
、不允許重複宣告
的特點;2.const宣告的變數都是
常數
(不允許改變的量),一旦宣告就不允許被修改,如果修改就會報錯--常數變數賦值3.一般第三方的框架中會大量使用const聲明變量,這樣可以避免用戶修改框架中的變量;
4.const實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對於簡單類型的資料(數值、字串、布林值),值就保存在變數指向的那個
記憶體位址
,因此等同於常數。
节流 这点简单介绍概念,用法后面在详细介绍 1) . 初始态 - pending。它的意思是 "待定的,将发生的",相当于是一个初始状态。创建[Promise]对象时,且没有调用resolve或者是reject方法,相当于是初始状态。这个初始状态会随着你调用resolve,或者是reject函数而切换到另一种状态。 2 ). 成功态 - resolved。表示解决了,就是说这个承诺实现了。 要实现从pending到resolved的转变,需要在 创建Promise对象时,在函数体中调用了resolve方法(即第一个参数)。 3) . 失败态 - rejected。拒绝,失败。表示这个承诺没有做到,失败了。要实现从pending到rejected的转换,只需要在创建Promise对象时,调用reject函数。 1.分别是创建阶段的 2.然后是挂载阶段的 3.更新阶段的是 4.最后是销毁阶段的 单向数据流是指父组件向子组件传递数据,子组件通过 vue中普通指令都可以实现数据变了,视图会跟着变,但是有一个特殊的指令叫 1.初始化阶段时,先执行父组件的 2.更新阶段,先执行父组件的 3.销毁阶段,先执行父组件的 v-if是通过将元素创建和销毁来控制显示与隐藏的,当v-if的条件为否时,会直接销毁该元素,当满足时会重新创建出来,有可能会影响页面的回流或重绘 如果该元素需要频繁切换时可以使用v-show,不需要频繁切换时可以使用v-if, 应用场景 自定义指令的钩子函数 1. 这块部分理解不是很透彻,大家浅看一下就可以了? 本人技術堆疊是主要是前端vue的,所以對這方面的知識還是有所欠缺的,盡量說的明白一點,其實我也不是很懂,大致明白,如果想要全面理解透還是需要很多技術儲備的,很明顯我不是的哈哈? 觀察者模式即一個物件被多個物件所依賴,當被依賴的物件發生更新時,會自動通知所有依賴的物件 觀察者模式定義了物件間的一種一對多的依賴關係,當一個物件的狀態改變時,所有依賴它的物件都會被通知,並自動更新 模式特徵: 有 發布-訂閱模式其實是一種物件間一對多的依賴關係,當一個物件的狀態發送改變時,所有依賴它的物件都會得到狀態改變的通知。 在現在的發布訂閱模式中,稱為發布者的訊息發送者不會將訊息直接發送給訂閱者,這意味著發布者和訂閱者不知道彼此的存在。在發布者和訂閱者之間存在第三個元件,稱為調度中心或事件通道(event bus),它維持著發布者和訂閱者之間的聯繫,過濾所有發布者傳入的消息並相應地分發它們給訂閱者 模式特點:有 主體數量不一樣,觀察者模式有二個主體分別是被觀察者 發布訂閱模式相比觀察者模式多了個事件通道,事件通道作為調度中心,管理事件的訂閱和發布工作,徹底隔絕了訂閱者和發布者的依賴關係,訂閱者和發布者是解耦的(不知道彼此存在) (學習影片分享:web前端入門、jQuery影片教學)
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)
}
}
function throtte(func, time) {
let timer = null // 计时器
return function (...args) {
if (timer) return // 无视,直接返回
timer = setTimeout(() => {
func.apply(this, args)
}, time)
}
}
13、promise的3种状态
pending
resolved--
也叫fulfilled
rejected
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实例)
好处
:
降低了耦合性
)2、vue生命周期
beforeCreate
,created
,一般在beforeCreate写loading加载效果,使用户体验更好,一般在created中发送ajax请求获取数据beforeMount
,mounted
,一般会在mounted中操作DOM元素beforeUpdate
,updated
,当数据更新时需要做统一的业务处理时,拿到最新的dom,可以使用updated 这个钩子函数beforeDestroy
,destroyed
,可以在beforeDestroy做一些清理的工作,比如说定时器 和解绑一些addEventListener监听的事件keep-alive
的两个钩子函数,使用场景是当组件切换时会进行销毁,因此组件中的初始化的4个钩子函数会多次执行,比较浪费资源,此时可以使用keep-alive纪行组件的缓存,可以让组件切换时不被销毁,keep-alive有两个独有的钩子函数,分别是activated
和deactivated
,是组件激活和失活时会执行的两个钩子函数)3、单向数据流
props
接收,当父组件中的值改变了,子组件中对应的数据也会改变,因为props是只读
的,所以无法直接在子组件中对父组件传递过来的值进行修改,但是如果这个数据是一个引用数据类型,是可以直接在子组件中修改数据中的某个属性的,只要不改变这个数据的内存地址
就可以4、双向数据绑定
v-model
,它一般用于表单控件,它可以实现双向数据绑定,所谓的双向数据就是数据变了,视图就会跟着改变,反过来也是5、v-model原理
v-model
一般配合input
框使用,实现双向数据绑定的效果,它是v-bind
和v-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、父子组件的声明周期执行顺序
beforeCreate
、created
、beforeMount
三个钩子函数,然后执行子组件的beforeCreate
、created
、beforeMount
、mounted
四个钩子函数,最后执行父组件的mounted钩子函数beforeUpdate
,然后执行子组件的beforeUpdate
,updated
,最后执行父组件的updatedbeforeDestroy
,然后执行子组件的eforeDestroy
,destroyed
,最后执行父组件的destroyed8、v-if和v-show的区别
v-if
和v-show
都可以控制标签,实现组件的显示与隐藏,不同点是v-show是通过display
的block和none
属性来控制的,当元素隐藏时,页面结构依然存在
提高性能
9、v-for和v-if为什么要避免一起使用
template
将v-if写在循环的外部,这样当不满足v-if的判断条件时,就不会再执行v-for了,也可以将数据放在计算属性
里面计算过滤出来的数据在交给v-for循环,代替v-if的作用,即可解决。10、自定义指令:directive
v-imgerror
公司项目中有的用户头像可能加载报错,可以给他一张默认图片, onerror this.img=默认图片v-focus
打开带有搜索的页面的时候,实现自动把光标定位到 input 中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. 先看本機有沒有快取資源,如果沒有,就需要向伺服器發送請求拿回來這個資源同時拿回來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,流程重新再走一遍設計模式
1、觀察者模式
比喻:
寶寶-> 父母爺爺奶奶一對多的依賴關係
寶寶哭-> 父母爺爺奶奶趕緊過來服務當一個對象的狀態發生改變時,所有依賴於它的對像都將得到通知,並自動更新二主體
一個是被觀察者Dep
一個是觀察者watcher
,在vue中v- band
就是採用這種模式理念,缺點是耦合性太高#2、發布訂閱模式
三個主體
發布者調度中心訂閱者,在vue中eventBus
體現出來了這種模式理念,可以實現解耦3、兩者模式區別
Dep
和觀察者watcher
,發布訂閱模式有三個主體分別是發布者調度中心(事件通道) 訂閱者
以上是總結一些前端常見面試題(附答案),帶你鞏固知識點!的詳細內容。更多資訊請關注PHP中文網其他相關文章!