http://www.reibang.com/p/769266edbd38
前言
經(jīng)過艱苦卓絕的面試歷程丝里,終于拿到了心儀的offer曲初。期間總結(jié)了一些面試題供各位參考体谒,涵蓋面很廣杯聚,并且面的都是知名大廠,所以這些題還是很有代表性的抒痒,都掌握以后一面基礎(chǔ)面應(yīng)該沒什么問題幌绍,二面也能應(yīng)付大半,奉上:
css相關(guān)
1. 萬能居中
1.margin: 0 auto;水平
2.text-align: center;水平
3.行高故响,垂直
4.表格傀广,center,middle;水平垂直
5.display:table-cell彩届;模擬表格伪冰,all
6.絕對(duì)定位,50%減自身寬高
7.絕對(duì)定位樟蠕,上下左右全0贮聂,margin:auto
8.絕對(duì)定位加相對(duì)定位。不需要知道寬高
9.IE6寨辩,IE7:給父元素設(shè)一個(gè)font-size:高度/1.14,vertical-align:middle
2. BFC優(yōu)化
塊格式化上下文, 特性:
- 使 BFC 內(nèi)部浮動(dòng)元素不會(huì)到處亂跑吓懈;
- 和浮動(dòng)元素產(chǎn)生邊界。
3. 盒模型哪兩種模式靡狞?什么區(qū)別耻警?如何設(shè)置
- 標(biāo)準(zhǔn)模式: box-sizing: content-box; 寬高不包括內(nèi)邊距和邊框
- 怪異模式: box-sizing: border-box
4. 常用清除浮動(dòng)的方法,如不清除浮動(dòng)會(huì)怎樣?
當(dāng)父元素不給高度的時(shí)候甘穿,內(nèi)部元素不浮動(dòng)時(shí)會(huì)撐開, 而浮動(dòng)的時(shí)候腮恩,父元素變成一條線, 造成塌陷.
- 額外標(biāo)簽法(在最后一個(gè)浮動(dòng)標(biāo)簽后,新加一個(gè)標(biāo)簽温兼,給其設(shè)置clear:both庆揪;)(不推薦)
- 父元素添加overflow:hidden; (觸發(fā)BFC)
- 使用after偽元素清除浮動(dòng)(推薦使用)
- 使用before和after雙偽元素清除浮動(dòng)
5. 刪格化的原理
比如antd的row和col, 將一行等分為24份, col是幾就占幾份, 底層按百分比實(shí)現(xiàn); 結(jié)合媒體查詢, 可以實(shí)現(xiàn)響應(yīng)式
6. 純css實(shí)現(xiàn)三角形
// 通過設(shè)置border
.box
{
width:0px;
height:0px;
border-top:50px solid rgba(0,0,0,0);
border-right:50px solid rgba(0,0,0,0);
border-bottom:50px solid green;
border-left:50px solid rgba(0,0,0,0);
}
7. 高度不定,寬100%妨托,內(nèi)一div高不確定缸榛,如何實(shí)現(xiàn)垂直居中?
- verticle-align: middle;
- 絕對(duì)定位50%加translateY(-50%)
- 絕對(duì)定位兰伤,上下左右全0内颗,margin:auto
8. 至少兩種方式實(shí)現(xiàn)自適應(yīng)搜索
- rem, em
- 百分比
- 媒體查詢
- bs, antd等的柵格布局
9. 設(shè)置一段文字的大小為6px
- 谷歌最小12px, 其他瀏覽器可以更小
- 通過transform: scale實(shí)現(xiàn)
10. css菊花圖
四個(gè)小圓點(diǎn)一直旋轉(zhuǎn)
// 父標(biāo)簽
animation: antRotate 1.2s infinite linear;
// 子標(biāo)簽
animation: antSpin 1s infinite linear;
@keyframe antSpin {
to {
opacity: 1
}
}
@keyframe antRotate {
to {
transform: rotate(405)
}
}
// animation-delay: 逐個(gè)延遲0.4s
11. 關(guān)于em
<div style="font-size: 20px">
123
<div style="font-size: 2em;width: 2em">456</div>
</div>
// 此時(shí)子元素的font-size為40px, 寬度為80px(還要乘以子元素font-size的系數(shù))
12. 關(guān)于vh, vw
vw:viewpoint width,視窗寬度敦腔,1vw等于視窗寬度的1%均澳。
vh:viewpoint height,視窗高度符衔,1vh等于視窗高度的1%找前。
vmin:vw和vh中較小的那個(gè)。
vmax:vw和vh中較大的那個(gè)判族。
13. Flex布局
- flex-direction控制主副軸
- flex-wrap控制換行(默認(rèn)不換行)
- flex-flow是上兩個(gè)的結(jié)合
- justify-content主軸對(duì)齊方式
- align-items交叉軸對(duì)齊方式
14. overflow原理
-
overflow: hidden
能清除塊內(nèi)子元素的浮動(dòng)影響. 因?yàn)樵搶傩赃M(jìn)行超出隱藏時(shí)需要計(jì)算盒子內(nèi)所有元素的高度, 所以會(huì)隱式清除浮動(dòng) - 創(chuàng)建BFC條件(滿足一個(gè)):
- float的值不為none躺盛;
- overflow的值不為visible;
- position的值為fixed / absolute形帮;
- display的值為table-cell / table-caption / inline-block / flex / inline-flex槽惫。
15. 實(shí)現(xiàn)自適應(yīng)的正方形:
- 使用vw, vh
-
width
百分比,height: 0
,padding-top(bottom): 50%
16. 標(biāo)準(zhǔn)模式和怪異模式
- document.compatMode屬性可以判斷是否是標(biāo)準(zhǔn)模式,當(dāng) document.compatMode為“CSS1Compat”辩撑,是標(biāo)準(zhǔn)模式界斜,“BackCompat”是怪異模式。
- 怪異模式是為了兼容舊版本的瀏覽器, 因?yàn)镮E低版本document.documentElement.clientWidth獲取不到
- 怪異模式盒模型:
box-sizing: border-box
; 標(biāo)準(zhǔn)模式:box-sizing: content-box
17. CSS3實(shí)現(xiàn)環(huán)形進(jìn)度條
兩個(gè)對(duì)半矩形遮罩, 使用rotate
以及overflow: hidden
進(jìn)行旋轉(zhuǎn)
18. css優(yōu)先級(jí)
選擇器的特殊性值表述為4個(gè)部分合冀,用0,0,0,0表示各薇。
- ID選擇器的特殊性值,加0,1,0,0君躺。
- 類選擇器峭判、屬性選擇器或偽類,加0,0,1,0晰洒。
- 元素和偽元素朝抖,加0,0,0,1。
- 通配選擇器*對(duì)特殊性沒有貢獻(xiàn)谍珊,即0,0,0,0治宣。
- 最后比較特殊的一個(gè)標(biāo)志!important(權(quán)重)急侥,它沒有特殊性值,但它的優(yōu)先級(jí)是最高的侮邀,為了方便記憶坏怪,可以認(rèn)為它的特殊性值為1,0,0,0,0。
JS相關(guān)
1. ES5和ES6繼承方式區(qū)別
- ES5定義類以函數(shù)形式, 以prototype來實(shí)現(xiàn)繼承
- ES6以class形式定義類, 以extend形式繼承
2. Generator了解
ES6 提供的一種異步編程解決方案, Generator 函數(shù)是一個(gè)狀態(tài)機(jī)绊茧,封裝了多個(gè)內(nèi)部狀態(tài)铝宵。
function* helloWorldGenerator() {
yield 'hello';
yield 'world';
return 'ending';
}
var hw = helloWorldGenerator();
調(diào)用后返回指向內(nèi)部狀態(tài)的指針, 調(diào)用next()才會(huì)移向下一個(gè)狀態(tài), 參數(shù):
hw.next()
// { value: 'hello', done: false }
hw.next()
// { value: 'world', done: false }
hw.next()
// { value: 'ending', done: true }
hw.next()
// { value: undefined, done: true }
3. 手寫Promise實(shí)現(xiàn)
var myPromise = new Promise((resolve, reject) => {
// 需要執(zhí)行的代碼
...
if (/* 異步執(zhí)行成功 */) {
resolve(value)
} else if (/* 異步執(zhí)行失敗 */) {
reject(error)
}
})
myPromise.then((value) => {
// 成功后調(diào)用, 使用value值
}, (error) => {
// 失敗后調(diào)用, 獲取錯(cuò)誤信息error
})
4. Promise優(yōu)缺點(diǎn)
- 優(yōu)點(diǎn): 解決回調(diào)地獄, 對(duì)異步任務(wù)寫法更標(biāo)準(zhǔn)化與簡潔化
- 缺點(diǎn): 首先,無法取消Promise华畏,一旦新建它就會(huì)立即執(zhí)行鹏秋,無法中途取消; 其次,如果不設(shè)置回調(diào)函數(shù)亡笑,Promise內(nèi)部拋出的錯(cuò)誤侣夷,不會(huì)反應(yīng)到外部; 第三,當(dāng)處于pending狀態(tài)時(shí)仑乌,無法得知目前進(jìn)展到哪一個(gè)階段(剛剛開始還是即將完成).
極簡版promise封裝:
function promise () {
this.msg = '' // 存放value和error
this.status = 'pending'
var that = this
var process = arguments[0]
process (function () {
that.status = 'fulfilled'
that.msg = arguments[0]
}, function () {
that.status = 'rejected'
that.msg = arguments[0]
})
return this
}
promise.prototype.then = function () {
if (this.status === 'fulfilled') {
arguments[0](this.msg)
} else if (this.status === 'rejected' && arguments[1]) {
arguments[1](this.msg)
}
}
5. 觀察者模式
又稱發(fā)布-訂閱模式, 舉例子說明.
實(shí)現(xiàn): 發(fā)布者管理訂閱者隊(duì)列, 并有新消息推送功能. 訂閱者僅關(guān)注更新就行
6. 手寫實(shí)現(xiàn)bind
Function.prototype.bind = function () {
// 保存原函數(shù)
var self = this
// 取出第一個(gè)參數(shù)作為上下文, 相當(dāng)于[].shift.call(arguments)
var context = Array.prototype.shift.call(arguments)
// 取剩余的參數(shù)作為arg; 因?yàn)閍rguments是偽數(shù)組, 所以要轉(zhuǎn)化為數(shù)組才能使用數(shù)組方法
var arg = Array.prototype.slice.call(arguments)
// 返回一個(gè)新函數(shù)
return function () {
// 綁定上下文并傳參
self.apply(context, Array.prototype.concat.call(arg, Array.prototype.slice.call(arguments)))
}
}
7. 手寫實(shí)現(xiàn)4種繼承
function Father () {}
function Child () {}
// 1\. 原型繼承
Child.prototype = new Father()
// 2\. 構(gòu)造繼承
function Child (name) {
Father.call(this, name)
}
// 3\. 組合繼承
function Child (name) {
Father.call(this, name)
}
Child.prototype = new Father()
// 4\. 寄生繼承
function cloneObj (o) {
var clone = object.create(o)
clone.sayName = ...
return clone
}
// 5\. 寄生組合繼承
// 6\. ES6 class extend繼承
8. css菊花圖
四個(gè)小圓點(diǎn)一直旋轉(zhuǎn)
// 父標(biāo)簽
animation: antRotate 1.2s infinite linear;
// 子標(biāo)簽
animation: antSpin 1s infinite linear;
@keyframe antSpin {
to {
opacity: 1
}
}
@keyframe antRotate {
to {
transform: rotate(405)
}
}
// animation-delay: 逐個(gè)延遲0.4s
9. http狀態(tài)碼
- 1**: 服務(wù)器收到請(qǐng)求, 需請(qǐng)求者進(jìn)一步操作
- 2**: 請(qǐng)求成功
- 3**: 重定向, 資源被轉(zhuǎn)移到其他URL了
- 4**: 客戶端錯(cuò)誤, 請(qǐng)求語法錯(cuò)誤或沒有找到相應(yīng)資源
- 5**: 服務(wù)端錯(cuò)誤, server error
- 304: Not Modified. 指定日期后未修改, 不返回資源
10. Object.create實(shí)現(xiàn)(原型式繼承百拓,特點(diǎn):實(shí)例的proto指向構(gòu)造函數(shù)本身)
11. async和await:
- Generator函數(shù)的語法糖,將*改成async晰甚,將yield換成await衙传。
- 是對(duì)Generator函數(shù)的改進(jìn), 返回promise角撞。
- 異步寫法同步化盖桥,遇到await先返回,執(zhí)行完異步再執(zhí)行接下來的.
- 內(nèi)置執(zhí)行器, 無需next()
12. 算法和數(shù)據(jù)結(jié)構(gòu):
- 算法:
解決具體問題所需要的解決方法赢织。執(zhí)行效率最快的最優(yōu)算法止剖。時(shí)間復(fù)雜度腺阳。輸入,輸出穿香,有窮性,確定性绎速,可行性皮获。冒泡排序,二叉樹遍歷纹冤,最長回文洒宝,二分查找,指針萌京,鏈表等雁歌,堆棧,隊(duì)列等知残。力扣靠瞎,codewar,算法導(dǎo)論。 - 數(shù)據(jù)結(jié)構(gòu):
邏輯結(jié)構(gòu):集合乏盐、線性佳窑、樹形、圖形結(jié)構(gòu)
物理結(jié)構(gòu):順序父能、鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)
13. 封裝JSONP
function jsonp ({url, param, callback}) {
return new Promise((resolve, reject) => {
var script = document.createElement('script')
window.callback = function (data) {
resolve(data)
document.body.removeChild('script')
}
var param = {...param, callback}
var arr = []
for (let key in param) {
arr.push(`${key}=${param[key]}`)
}
script.src = `${url}?${arr.join('&')}`
document.body.appendChild(script)
})
}
14. 手動(dòng)實(shí)現(xiàn)map(forEach以及filter也類似)
// for循環(huán)實(shí)現(xiàn)
Array.prototype.myMap = function () {
var arr = this
var [fn, thisValue] = Array.prototype.slice.call(arguments)
var result = []
for (var i = 0; i < arr.length; i++) {
result.push(fn.call(thisValue, arr[i], i, arr))
}
return result
}
var arr0 = [1, 2, 3]
console.log(arr0.myMap(v => v + 1))
// forEach實(shí)現(xiàn)(reduce類似)
Array.prototype.myMap = function (fn, thisValue) {
var result = []
this.forEach((v, i, arr) => {
result.push(fn.call(thisValue, v, i, arr))
})
return result
}
var arr0 = [1, 2, 3]
console.log(arr0.myMap(v => v + 1))
15. js實(shí)現(xiàn)checkbox全選以及反選
<body>
<button id="other">反選</button>
<input type="checkbox" id="all" />全選
<input type="checkbox" class="check" />1
<input type="checkbox" class="check" />2
<input type="checkbox" class="check" />3
<script>
var checkbox = document.getElementsByClassName('check')
var checkAll = document.getElementById('all')
var checkOther = document.getElementById('other')
checkAll.onclick = function() {
var flag = true
for (var i = 0; i < checkbox.length; i++) {
if (!checkbox[i].checked) flag = false
}
if (flag) {
for (var i = 0; i < checkbox.length; i++) {
checkbox[i].checked = false
}
} else {
for (var i = 0; i < checkbox.length; i++) {
checkbox[i].checked = true
}
}
}
checkOther.onclick = function() {
for (var i = 0; i < checkbox.length; i++) {
checkbox[i].checked = !checkbox[i].checked
}
}
</script>
</body>
16. 對(duì)原型鏈的理解神凑?prototype上都有哪些屬性
- 在js里,繼承機(jī)制是原型繼承何吝。繼承的起點(diǎn)是 對(duì)象的原型(Object prototype)溉委。
- 一切皆為對(duì)象,只要是對(duì)象爱榕,就會(huì)有 proto 屬性薛躬,該屬性存儲(chǔ)了指向其構(gòu)造的指針。
- Object prototype也是對(duì)象呆细,其 proto 指向null型宝。
- 對(duì)象分為兩種:函數(shù)對(duì)象和普通對(duì)象,只有函數(shù)對(duì)象擁有『原型』對(duì)象(prototype)絮爷。
- prototype的本質(zhì)是普通對(duì)象趴酣。
- Function prototype比較特殊,是沒有prototype的函數(shù)對(duì)象坑夯。
- new操作得到的對(duì)象是普通對(duì)象岖寞。
- 當(dāng)調(diào)取一個(gè)對(duì)象的屬性時(shí),會(huì)先在本身查找柜蜈,若無仗谆,就根據(jù) proto 找到構(gòu)造原型,若無淑履,繼續(xù)往上找隶垮。最后會(huì)到達(dá)頂層Object prototype,它的 proto 指向null秘噪,均無結(jié)果則返回undefined狸吞,結(jié)束。
- 由 proto 串起的路徑就是『原型鏈』指煎。
- 通過prototype可以給所有子類共享屬性
17. 為什么使用繼承
通常在一般的項(xiàng)目里不需要,因?yàn)閼?yīng)用簡單,但你要用純js做一些復(fù)雜的工具或框架系統(tǒng)就要用到了,比如webgis蹋偏、或者js框架如jquery、ext什么的,不然一個(gè)幾千行代碼的框架不用繼承得寫幾萬行,甚至還無法維護(hù)
18. setTimeout時(shí)間延遲為何不準(zhǔn)
單線程, 先執(zhí)行同步主線程, 再執(zhí)行異步任務(wù)隊(duì)列
19. 事件循環(huán)述至壤,宏任務(wù)和微任務(wù)有什么區(qū)別威始?
- 先主線程后異步任務(wù)隊(duì)列
- 先微任務(wù)再宏任務(wù)
20. let const var作用域
塊級(jí)作用域, 暫時(shí)性死區(qū)
21. 節(jié)流和防抖
- 函數(shù)節(jié)流是指一定時(shí)間內(nèi)js方法只跑一次。比如人的眨眼睛像街,就是一定時(shí)間內(nèi)眨一次黎棠。這是函數(shù)節(jié)流最形象的解釋晋渺。
// 函數(shù)節(jié)流 滾動(dòng)條滾動(dòng)
var canRun = true;
document.getElementById("throttle").onscroll = function(){
if(!canRun){
// 判斷是否已空閑,如果在執(zhí)行中葫掉,則直接return
return;
}
canRun = false;
setTimeout(function(){
console.log("函數(shù)節(jié)流");
canRun = true;
}, 300);
};
- 函數(shù)防抖是指頻繁觸發(fā)的情況下些举,只有足夠的空閑時(shí)間,才執(zhí)行代碼一次俭厚。比如生活中的坐公交户魏,就是一定時(shí)間內(nèi),如果有人陸續(xù)刷卡上車挪挤,司機(jī)就不會(huì)開車叼丑。只有別人沒刷卡了,司機(jī)才開車扛门。
// 函數(shù)防抖
var timer = false;
document.getElementById("debounce").onscroll = function(){
clearTimeout(timer); // 清除未執(zhí)行的代碼鸠信,重置回初始化狀態(tài)
timer = setTimeout(function(){
console.log("函數(shù)防抖");
}, 300);
};
22. 實(shí)現(xiàn)一個(gè)sleep函數(shù)
// 這種實(shí)現(xiàn)方式是利用一個(gè)偽死循環(huán)阻塞主線程。因?yàn)镴S是單線程的论寨。所以通過這種方式可以實(shí)現(xiàn)真正意義上的sleep()星立。
function sleep(delay) {
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < delay) {
continue;
}
}
function test() {
console.log('111');
sleep(2000);
console.log('222');
}
test()
23. 閉包
- 概念: 內(nèi)層函數(shù)能夠訪問外層函數(shù)作用域的變量
- 缺點(diǎn): 引起內(nèi)存泄漏(釋放內(nèi)存)
- 作用:
- 使用閉包修正打印值
- 實(shí)現(xiàn)柯里化
- 實(shí)現(xiàn)node commonJs 模塊化, 實(shí)現(xiàn)私有變量
- 保持變量與函數(shù)活性, 可延遲回收和執(zhí)行
24. Immutable.js
Facebook出品, 倡導(dǎo)數(shù)據(jù)的不可變性, 用的最多就是List和Map.
25. js實(shí)現(xiàn)instanceof
// 檢測(cè)l的原型鏈(__proto__)上是否有r.prototype,若有返回true葬凳,否則false
function myInstanceof (l, r) {
var R = r.prototype
while (l.__proto__) {
if (l.__proto__ === R) return true
}
return false
}
27. ES6的模塊引入和CommonJs區(qū)別
28. 嚴(yán)格模式
// 嚴(yán)格模式下, 隱式綁定丟失后this不會(huì)指向window, 而是指向undefined
'use strict'
var a = 2
var obj = {
a: 1,
b: function() {
// console.log(this.a)
console.log(this)
}
}
var c = obj.b
c() // undefined
29. fetch, axios區(qū)別
30. typescript缺點(diǎn)
- 并不是嚴(yán)格意義的js的超集, 與js不完全兼容, 會(huì)報(bào)錯(cuò)
- 更多的限制, 是一種桎梏
- 有些js第三方庫沒有dts, 有問題
31. 構(gòu)造函數(shù)實(shí)現(xiàn)原理
- 構(gòu)造函數(shù)中沒有顯示的創(chuàng)建Object對(duì)象, 實(shí)際上后臺(tái)自動(dòng)創(chuàng)建了
- 直接給this對(duì)象賦值屬性和方法, this即指向創(chuàng)建的對(duì)象
- 沒有return返回值, 后臺(tái)自動(dòng)返回了該對(duì)象
// 模擬構(gòu)造函數(shù)實(shí)現(xiàn)
var Book = function(name) {
this.name = name;
};
//正常用法
var java = new Book(‘Master Java’);
//使用代碼模擬绰垂,在非IE瀏覽器中測(cè)試,IE瀏覽器不支持
var python = {};
python.__proto__ = Book.prototype;
Book.call(python, 'Master Python');
32. for in 和 for of區(qū)別
-
for in
遍歷數(shù)組會(huì)遍歷到數(shù)組原型上的屬性和方法, 更適合遍歷對(duì)象 -
forEach
不支持break, continue, return
等 - 使用
for of
可以成功遍歷數(shù)組的值, 而不是索引, 不會(huì)遍歷原型 - for in 可以遍歷到myObject的原型方法method,如果不想遍歷原型方法和屬性的話火焰,可以在循環(huán)內(nèi)部判斷一下,hasOwnPropery方法可以判斷某屬性是否是該對(duì)象的實(shí)例屬性
33. JS實(shí)現(xiàn)并發(fā)控制:
使用消息隊(duì)列以及setInterval
或promise
進(jìn)行入隊(duì)和出隊(duì)
34. ajax和axios劲装、fetch的區(qū)別
35. promise.finally實(shí)現(xiàn)
Promise.prototype.finally = function (callback) {
let P = this.constructor;
return this.then(
value => P.resolve(callback()).then(() => value),
reason => P.resolve(callback()).then(() => { throw reason })
);
};
瀏覽器網(wǎng)絡(luò)相關(guān)
1. reflow(回流)和repaint(重繪)優(yōu)化
- 瀏覽器渲染過程: DOM tree, CSS tree --> Render tree --> Paint
- DOM tree根節(jié)點(diǎn)為html
- 渲染從瀏覽器左上角到右下角
- 第一次打開頁面至少觸發(fā)一次重繪和回流, 結(jié)構(gòu)如寬高位置變化時(shí), 觸發(fā)reflow回流;非結(jié)構(gòu)如背景色變化時(shí), 觸發(fā)repaint重繪. 二者都會(huì)造成體驗(yàn)不佳
- 如何減少重繪和回流?
- 通過classname或cssText一次性修改樣式, 而非一個(gè)一個(gè)改
- 離線模式: 克隆要操作的結(jié)點(diǎn), 操作后再與原始結(jié)點(diǎn)交換, 類似于虛擬DOM
- 避免頻繁直接訪問計(jì)算后的樣式, 而是先將信息保存下來
- 絕對(duì)布局的DOM, 不會(huì)造成大量reflow
- div不要嵌套太深, 不要超過六層
2.一個(gè)頁面從輸入 URL 到頁面加載顯示完成,這個(gè)過程中都發(fā)生了什么昌简?
- 瀏覽器根據(jù)請(qǐng)求的URL交給DNS域名解析占业,找到真實(shí)IP,向服務(wù)器發(fā)起請(qǐng)求纯赎;
- 服務(wù)器交給后臺(tái)處理完成后返回?cái)?shù)據(jù)谦疾,瀏覽器接收文件(HTML、JS址否、CSS餐蔬、圖象等);
- 瀏覽器對(duì)加載到的資源(HTML佑附、JS、CSS等)進(jìn)行語法解析仗考,建立相應(yīng)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)(如HTML的DOM Tree)音同;
- 載入解析到的資源文件,渲染頁面秃嗜,完成权均。
3.localStorage 與 sessionStorage 與cookie的區(qū)別總結(jié)
- 共同點(diǎn): 都保存在瀏覽器端, 且同源
- localStorage 與 sessionStorage 統(tǒng)稱webStorage,保存在瀏覽器,不參與服務(wù)器通信,大小為5M
- 生命周期不同: localStorage永久保存, sessionStorage當(dāng)前會(huì)話, 都可手動(dòng)清除
- 作用域不同: 不同瀏覽器不共享local和session, 不同會(huì)話不共享session
- Cookie: 設(shè)置的過期時(shí)間前一直有效, 大小4K.有個(gè)數(shù)限制, 各瀏覽器不同, 一般為20個(gè).攜帶在HTTP頭中, 過多會(huì)有性能問題.可自己封裝, 也可用原生
4.瀏覽器如何阻止事件傳播顿膨,阻止默認(rèn)行為
- 阻止事件傳播(冒泡): e.stopPropagation()
- 阻止默認(rèn)行為: e.preventDefault()
5.虛擬DOM方案相對(duì)原生DOM操作有什么優(yōu)點(diǎn),實(shí)現(xiàn)上是什么原理叽赊?
虛擬DOM可提升性能, 無須整體重新渲染, 而是局部刷新.
JS對(duì)象, diff算法
6.瀏覽器事件機(jī)制中事件觸發(fā)三個(gè)階段
- 事件捕獲階段: 從dom樹節(jié)點(diǎn)往下找到目標(biāo)節(jié)點(diǎn), 不會(huì)觸發(fā)函數(shù)
- 事件目標(biāo)處理函數(shù): 到達(dá)目標(biāo)節(jié)點(diǎn)
-
事件冒泡: 最后從目標(biāo)節(jié)點(diǎn)往頂層元素傳遞, 通常函數(shù)在此階段執(zhí)行.
addEventListener第三個(gè)參數(shù)默認(rèn)false(冒泡階段執(zhí)行),true(捕獲階段執(zhí)行).
阻止冒泡見以上方法
7.什么是跨域恋沃?為什么瀏覽器要使用同源策略?你有幾種方式可以解決跨域問題必指?了解預(yù)檢請(qǐng)求嘛囊咏?
跨域是指一個(gè)域下的文檔或腳本試圖去請(qǐng)求另一個(gè)域下的資源
防止XSS、CSFR等攻擊, 協(xié)議+域名+端口不同
-
jsonp; 跨域資源共享(CORS)(Access control); 服務(wù)器正向代理等
預(yù)檢請(qǐng)求: 需預(yù)檢的請(qǐng)求要求必須首先使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求到服務(wù)器塔橡,以獲知服務(wù)器是否允許該實(shí)際請(qǐng)求梅割。"預(yù)檢請(qǐng)求“的使用,可以避免跨域請(qǐng)求對(duì)服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響
8.了解瀏覽器緩存機(jī)制嗎葛家?
- 瀏覽器緩存就是把一個(gè)已經(jīng)請(qǐng)求過的資源拷貝一份存儲(chǔ)起來户辞,當(dāng)下次需要該資源時(shí),瀏覽器會(huì)根據(jù)緩存機(jī)制決定直接使用緩存資源還是再次向服務(wù)器發(fā)送請(qǐng)求.
- from memory cache ; from disk cache
- 作用: 減少網(wǎng)絡(luò)傳輸?shù)膿p耗以及降低服務(wù)器壓力癞谒。
- 優(yōu)先級(jí): 強(qiáng)制緩存 > 協(xié)商緩存; cache-control > Expires > Etag > Last-modified
9.為什么操作 DOM 慢?
DOM本身是一個(gè)js對(duì)象, 操作這個(gè)對(duì)象本身不慢, 但是操作后觸發(fā)了瀏覽器的行為, 如repaint和reflow等瀏覽器行為, 使其變慢
10.什么情況會(huì)阻塞渲染底燎?
- js腳本同步執(zhí)行
- css和圖片雖然是異步加載, 但js文件執(zhí)行需依賴css, 所以css也會(huì)阻塞渲染
11.如何判斷js運(yùn)行在瀏覽器中還是node中?
判斷有無全局對(duì)象global和window
12.關(guān)于web以及瀏覽器處理預(yù)加載有哪些思考弹砚?
圖片等靜態(tài)資源在使用之前就提前請(qǐng)求
資源使用到的時(shí)候能從緩存中加載, 提升用戶體驗(yàn)
頁面展示的依賴關(guān)系維護(hù)
13.http多路復(fù)用
- Keep-Alive: Keep-Alive解決的核心問題:一定時(shí)間內(nèi)双仍,同一域名多次請(qǐng)求數(shù)據(jù),只建立一次HTTP請(qǐng)求迅栅,其他請(qǐng)求可復(fù)用每一次建立的連接通道殊校,以達(dá)到提高請(qǐng)求效率的問題。這里面所說的一定時(shí)間是可以配置的读存,不管你用的是Apache還是nginx为流。
- 解決兩個(gè)問題: 串行文件傳輸(采用二進(jìn)制數(shù)據(jù)幀); 連接數(shù)過多(采用流, 并行傳輸)
14. http和https:
- http: 最廣泛網(wǎng)絡(luò)協(xié)議,BS模型让簿,瀏覽器高效敬察。
- https: 安全版,通過SSL加密尔当,加密傳輸莲祸,身份認(rèn)證,密鑰
- https相對(duì)于http加入了ssl層, 加密傳輸, 身份認(rèn)證;
- 需要到ca申請(qǐng)收費(fèi)的證書;
- 安全但是耗時(shí)多椭迎,緩存不是很好;
- 注意兼容http和https;
- 連接方式不同, 端口號(hào)也不同, http是80, https是443
15. CSRF和XSS區(qū)別及防御
16. cookie可設(shè)置哪些屬性锐帜?httponly?
chrome控制臺(tái)的application下可查看:
- name 字段為一個(gè)cookie的名稱。
- value 字段為一個(gè)cookie的值畜号。
- domain 字段為可以訪問此cookie的域名缴阎。
- path 字段為可以訪問此cookie的頁面路徑。 比如domain是abc.com,path是/test简软,那么只有/test路徑下的頁面可以讀取此cookie蛮拔。
- expires/Max-Age 字段為此cookie超時(shí)時(shí)間述暂。若設(shè)置其值為一個(gè)時(shí)間,那么當(dāng)?shù)竭_(dá)此時(shí)間后建炫,此cookie失效畦韭。不設(shè)置的話默認(rèn)值是Session,意思是cookie會(huì)和session一起失效肛跌。當(dāng)瀏覽器關(guān)閉(不是瀏覽器標(biāo)簽頁艺配,而是整個(gè)瀏覽器) 后,此cookie失效惋砂。
- Size 字段 此cookie大小妒挎。
- http 字段 cookie的httponly屬性。若此屬性為true西饵,則只有在http請(qǐng)求頭中會(huì)帶有此cookie的信息酝掩,而不能通過document.cookie來訪問此cookie。
- secure 字段 設(shè)置是否只能通過https來傳遞此條cookie
17. 登錄后眷柔,前端做了哪些工作期虾,如何得知已登錄
- 前端存放服務(wù)端下發(fā)的cookie, 簡單說就是寫一個(gè)字段在cookie中表明已登錄, 并設(shè)置失效日期
- 或使用后端返回的token, 每次ajax請(qǐng)求將token攜帶在請(qǐng)求頭中, 這也是防范csrf的手段之一
18. http狀態(tài)碼
- 1**: 服務(wù)器收到請(qǐng)求, 需請(qǐng)求者進(jìn)一步操作
- 2**: 請(qǐng)求成功
- 3**: 重定向, 資源被轉(zhuǎn)移到其他URL了
- 4**: 客戶端錯(cuò)誤, 請(qǐng)求語法錯(cuò)誤或沒有找到相應(yīng)資源
- 5**: 服務(wù)端錯(cuò)誤, server error
- 301: 資源(網(wǎng)頁等)被永久轉(zhuǎn)移到其他URL, 返回值中包含新的URL, 瀏覽器會(huì)自動(dòng)定向到新URL
- 302: 臨時(shí)轉(zhuǎn)移. 客戶端應(yīng)訪問原有URL
- 304: Not Modified. 指定日期后未修改, 不返回資源
- 403: 服務(wù)器拒絕執(zhí)行請(qǐng)求
- 404: 請(qǐng)求的資源(網(wǎng)頁等)不存在
- 500: 內(nèi)部服務(wù)器錯(cuò)誤
19. # Http請(qǐng)求頭緩存設(shè)置方法
Cache-control, expire, last-modify
20. 實(shí)現(xiàn)頁面回退刷新
- 舊: window.history.back() + window.location.href=document.referrer;
- 新: HTML5的新API擴(kuò)展了window.history,使歷史記錄點(diǎn)更加開放了驯嘱∠獍可以存儲(chǔ)當(dāng)前歷史記錄點(diǎn)、替換當(dāng)前歷史記錄點(diǎn)鞠评、監(jiān)聽歷史記錄點(diǎn)onpopstate, replaceState
21. 正向代理和反向代理
-
正向代理:
(1)訪問原來無法訪問的資源茂蚓,如google
(2) 可以做緩存,加速訪問資源
(3)對(duì)客戶端訪問授權(quán)剃幌,上網(wǎng)進(jìn)行認(rèn)證
(4)代理可以記錄用戶訪問記錄(上網(wǎng)行為管理)聋涨,對(duì)外隱藏用戶信息 -
反向代理:
(1)保證內(nèi)網(wǎng)的安全,可以使用反向代理提供WAF功能负乡,阻止web攻擊大型網(wǎng)站牍白,通常將反向代理作為公網(wǎng)訪問地址,Web服務(wù)器是內(nèi)網(wǎng)抖棘。
(2)負(fù)載均衡茂腥,通過反向代理服務(wù)器來優(yōu)化網(wǎng)站的負(fù)載
22. 關(guān)于預(yù)檢請(qǐng)求
在非簡單請(qǐng)求且跨域的情況下,瀏覽器會(huì)自動(dòng)發(fā)起options預(yù)檢請(qǐng)求切省。
23. 三次握手四次揮手
- 開啟連接用三次握手, 關(guān)閉用四次揮手
24. TCP和UDP協(xié)議
- TCP(Transmission Control Protocol:傳輸控制協(xié)議最岗;面向連接,可靠傳輸
- UDP(User Datagram Protocol):用戶數(shù)據(jù)報(bào)協(xié)議朝捆;面向無連接仑性,不可靠傳輸
25. 進(jìn)程和線程的區(qū)別
- 進(jìn)程:是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位,是一個(gè)動(dòng)態(tài)概念右蹦,競(jìng)爭計(jì)算機(jī)系統(tǒng)資源的基本單位诊杆。
- 線程:是進(jìn)程的一個(gè)執(zhí)行單元,是進(jìn)程內(nèi)科調(diào)度實(shí)體何陆。比進(jìn)程更小的獨(dú)立運(yùn)行的基本單位晨汹。線程也被稱為輕量級(jí)進(jìn)程。
- 一個(gè)程序至少一個(gè)進(jìn)程贷盲,一個(gè)進(jìn)程至少一個(gè)線程淘这。
vue相關(guān)
1. 生命周期
2 .雙向數(shù)據(jù)綁定v-model。這個(gè)最好也是自己實(shí)現(xiàn)一下 理解更深
通過v-model
VUE實(shí)現(xiàn)雙向數(shù)據(jù)綁定的原理就是利用了 Object.defineProperty() 這個(gè)方法重新定義了對(duì)象獲取屬性值(get)和設(shè)置屬性值(set)的操作來實(shí)現(xiàn)的巩剖。
// 依賴收集
// 簡化版
var obj = { }
var name
//第一個(gè)參數(shù):定義屬性的對(duì)象铝穷。
//第二個(gè)參數(shù):要定義或修改的屬性的名稱。
//第三個(gè)參數(shù):將被定義或修改的屬性描述符佳魔。
Object.defineProperty(obj, "data", {
//獲取值
get: function () {
return name
},
//設(shè)置值
set: function (val) {
name = val
console.log(val)
}
})
//賦值調(diào)用set
obj.data = 'aaa'
//取值調(diào)用get
console.log(obj.data)
// 詳細(xì)版
myVue.prototype._obverse = function (obj) { // obj = {number: 0}
var value;
for (key in obj) { //遍歷obj對(duì)象
if (obj.hasOwnProperty(key)) {
value = obj[key];
if (typeof value === 'object') { //如果值是對(duì)象曙聂,則遞歸處理
this._obverse(value);
}
Object.defineProperty(this.$data, key, { //關(guān)鍵
enumerable: true,
configurable: true,
get: function () {
console.log(`獲取${value}`);
return value;
},
set: function (newVal) {
console.log(`更新${newVal}`);
if (value !== newVal) {
value = newVal;
}
}
})
}
}
}
3.vue父子組件傳遞參數(shù)
- 父 -->子: 通過props
- 子 -->父: 通過 $$refs 或 $emit
4.vue傳遞參數(shù)方法
- 父子組件傳參如上, v-bind : v-on @
- 兄弟組件傳參:(通過EventBus事件總線實(shí)現(xiàn))
// 1\. 新建eventBus.js
import Vue from 'vue'
export default new Vue
// 或直接在main.js中初始化EventBus(全局)
Vue.prototype.$EventBus = new Vue()
// 2\. 發(fā)射與接收
// 如果是定義在eventBus.js中
import eventBus from 'eventBus.js'
eventBus.$emit()
eventBus.$on()
// 如果是定義在main.js中
this.bus.$emit()
this.bus.$on()
// 3\. 移除監(jiān)聽
eventBus.$off()
5.vue自定義組件
可以使用獨(dú)立可復(fù)用的自定義組件來構(gòu)成大型應(yīng)用, 采用帕斯卡命名法或橫線連接, 通過以上方式進(jìn)行組件間通信. 每一個(gè)組件都是Vue實(shí)例, 可以使用生命周期鉤子.
6. vue自定義指令
- 除核心指令之外的指令, 使用directive進(jìn)行注冊(cè).
- 指令自定義鉤子函數(shù): bind, inserted, update, componentUpdated, unbind
7.vuex組成和原理
- 組成: 組件間通信, 通過store實(shí)現(xiàn)全局存取
- 修改: 唯一途徑, 通過commit一個(gè)mutations(同步)或dispatch一個(gè)actions(異步)
- 簡寫: 引入mapState、mapGetters鞠鲜、mapActions
8.vue-router的原理宁脊,例如hashhistory和History interface這些東西要弄明白。其實(shí)看一下源碼就好了贤姆,看不懂可以直接看解析的相關(guān)技術(shù)博客榆苞。
-
vue-router用法:
在router.js或者某一個(gè)路由分發(fā)頁面配置path, name, component對(duì)應(yīng)關(guān)系- 每個(gè)按鈕一個(gè)value, 在watch功能中使用this.$router.push實(shí)現(xiàn)對(duì)應(yīng)跳轉(zhuǎn), 類似react的this.history.push
- 或直接用router-link to去跳轉(zhuǎn), 類似react的link to
-
vue-router原理: 通過hash和History interface兩種方式實(shí)現(xiàn)前端路由
- HashHistory: 利用URL中的hash(“#”);replace()方法與push()方法不同之處在于,它并不是將新路由添加到瀏覽器訪問歷史的棧頂霞捡,而是替換掉當(dāng)前的路由
- History interface: 是瀏覽器歷史記錄棧提供的接口坐漏,通過back(), forward(), go()等方法,我們可以讀取瀏覽器歷史記錄棧的信息碧信,進(jìn)行各種跳轉(zhuǎn)操作. pushState(), replaceState() 這下不僅是讀取了赊琳,還可以對(duì)瀏覽器歷史記錄棧進(jìn)行修改
9.vue的seo問題
seo關(guān)系到網(wǎng)站排名, vue搭建spa做前后端分離不好做seo, 可通過其他方法解決:
- SSR服務(wù)端渲染: 將同一個(gè)組件渲染為服務(wù)器端的 HTML 字符串.利于seo且更快.
- vue-meta-info, nuxt, prerender-spa-plugin頁面預(yù)渲染等
10.預(yù)渲染和ssr
以上
11.生命周期內(nèi)create和mounted的區(qū)別
- created: 在模板渲染成html前調(diào)用,即通常初始化某些數(shù)據(jù)音婶,然后再渲染成視圖慨畸。
- mounted: 在模板渲染成html后調(diào)用,通常是初始化頁面完成后衣式,再對(duì)html的dom節(jié)點(diǎn)進(jìn)行一些需要的操作和方法寸士。
12.監(jiān)聽watch
對(duì)應(yīng)一個(gè)對(duì)象,鍵是觀察表達(dá)式碴卧,值是對(duì)應(yīng)回調(diào)弱卡。值也可以是methods的方法名,或者是對(duì)象住册,包含選項(xiàng)婶博。在實(shí)例化時(shí)為每個(gè)鍵調(diào)用 $watch()
13.登錄驗(yàn)證攔截(通過router)
- 先設(shè)置requireAuth:
routes = [
{
name: 'detail',
path: '/detail',
meta: {
requireAuth: true
}
},
{
name: 'login',
path: '/login'
}
]
- 再配置router.beforeEach:
router.beforeEach((from, to, next) => {
if (to.meta.requireAuth) { // 判斷跳轉(zhuǎn)的路由是否需要登錄
if (store.state.token) { // vuex.state判斷token是否存在
next() // 已登錄
} else {
next({
path: '/login',
query: {redirect: to.fullPath} // 將跳轉(zhuǎn)的路由path作為參數(shù),登錄成功后跳轉(zhuǎn)到該路由
})
}
} else {
next()
}
})
14. v-for key值
不寫key值會(huì)報(bào)warning, 和react的array渲染類似. 根據(jù)diff算法, 修改數(shù)組后, 寫key值會(huì)復(fù)用, 不寫會(huì)重新生成, 造成性能浪費(fèi)或某些不必要的錯(cuò)誤
15. vue3.0的更新和defineProperty優(yōu)化
- 放棄 Object.defineProperty 荧飞,使用更快的原生 Proxy (訪問對(duì)象攔截器, 也成代理器)
- 提速, 降低內(nèi)存使用, Tree-shaking更友好
- 支持IE11等
- 使用Typescript
15. vue使用this獲取變量
正常要通過vm.[圖片上傳失敗...(image-6d2f4e-1570591304185)]
root傳參取值
16. jQuery的優(yōu)缺點(diǎn)凡人,與vue的不同名党,vue的優(yōu)缺點(diǎn)?
- jq優(yōu)點(diǎn): 比原生js更易書寫, 封裝了很多api, 有豐富的插件庫; 缺點(diǎn): 每次升級(jí)與之前版本不兼容, 只能手動(dòng)開發(fā), 操作DOM很慢, 不方便, 變量名污染, 作用域混淆等.
- vue優(yōu)缺點(diǎn): 雙向綁定, 虛擬DOM, diff算法, MVVM, 組件化, 通信方便, 路由分發(fā)等
17. vue解除雙向綁定
let obj = JSON.parse(JSON.stringify(this.temp1));
18. vue異步組件
為了簡化挠轴,Vue 允許你以一個(gè)工廠函數(shù)的方式定義你的組件传睹,這個(gè)工廠函數(shù)會(huì)異步解析你的組件定義。Vue 只有在這個(gè)組件需要被渲染的時(shí)候才會(huì)觸發(fā)該工廠函數(shù)岸晦,且會(huì)把結(jié)果緩存起來供未來重渲染
Vue.component(
'async-webpack-example',
// 這個(gè) `import` 函數(shù)會(huì)返回一個(gè) `Promise` 對(duì)象欧啤。
() => import('./my-async-component')
)
19. MVC與MVVM
- model-數(shù)據(jù)層 view-視圖層 controller-控制層
- MVC的目的是實(shí)現(xiàn)M和V的分離,單向通信启上,必須通過C來承上啟下
- MVVM中通過VM(vue中的實(shí)例化對(duì)象)的發(fā)布者-訂閱者模式實(shí)現(xiàn)雙向綁定邢隧,數(shù)據(jù)綁定,dom事件監(jiān)聽
- 區(qū)別:MVC和MVVM的區(qū)別并不是VM完全取代了C冈在,ViewModel存在目的在于抽離Controller中展示的業(yè)務(wù)邏輯倒慧,而不是替代Controller,其它視圖操作業(yè)務(wù)等還是應(yīng)該放在Controller中實(shí)現(xiàn)讥邻。也就是說MVVM實(shí)現(xiàn)的是業(yè)務(wù)邏輯組件的重用
20. vue漸進(jìn)式
小到可以只使用核心功能迫靖,比如單文件組件作為一部分嵌入;大到使用整個(gè)工程兴使,vue init webpack my-project來構(gòu)建項(xiàng)目系宜;VUE的核心庫及其生態(tài)系統(tǒng)也可以滿足你的各式需求(core+vuex+vue-route)
react相關(guān)
1. 新舊生命周期
- 舊: will, did; mount, update...
-
新: 16版本之后:
-
getDerivedStateFromProps
: 虛擬dom之后,實(shí)際dom掛載之前, 每次獲取新的props或state之后, 返回新的state, 配合didUpdate可以替代willReceiveProps -
getSnapshotBeforeUpdate
: update發(fā)生的時(shí)候发魄,組件更新前觸發(fā), 在render之后盹牧,在組件dom渲染之前;返回一個(gè)值励幼,作為componentDidUpdate的第三個(gè)參數(shù)汰寓;配合componentDidUpdate, 可以覆蓋componentWillUpdate的所有用法 -
componentDidCatch
: 錯(cuò)誤處理
-
- 對(duì)比: 棄用了三個(gè)will, 新增兩個(gè)get來代替will, 不能混用, 17版本會(huì)徹底刪除. 新增錯(cuò)誤處理
2. react核心
- 虛擬DOM, Diff算法, 遍歷key值
- react-dom: 提供了針對(duì)DOM的方法,比如:把創(chuàng)建的虛擬DOM苹粟,渲染到頁面上 或 配合ref來操作DOM
- react-router
3. fiber核心(react 16)
- 舊: 瀏覽器渲染引擎單線程, 計(jì)算DOM樹時(shí)鎖住整個(gè)線程, 所有行為同步發(fā)生, 有效率問題, 期間react會(huì)一直占用瀏覽器主線程有滑,如果組件層級(jí)比較深,相應(yīng)的堆棧也會(huì)很深嵌削,長時(shí)間占用瀏覽器主線程, 任何其他的操作(包括用戶的點(diǎn)擊毛好,鼠標(biāo)移動(dòng)等操作)都無法執(zhí)行
- 新: 重寫底層算法邏輯, 引入fiber時(shí)間片, 異步渲染, react會(huì)在渲染一部分樹后檢查是否有更高優(yōu)先級(jí)的任務(wù)需要處理(如用戶操作或繪圖), 處理完后再繼續(xù)渲染, 并可以更新優(yōu)先級(jí), 以此管理渲染任務(wù). 加入fiber的react將組件更新分為兩個(gè)時(shí)期(phase 1 && phase 2),render前的生命周期為phase1苛秕,render后的生命周期為phase2, 1可以打斷, 2不能打斷一次性更新. 三個(gè)will生命周期可能會(huì)重復(fù)執(zhí)行, 盡量避免使用
4. 渲染一個(gè)react
- 分為首次渲染和更新渲染
- 生命周期, 建立虛擬DOM, 進(jìn)行diff算法
- 對(duì)比新舊DOM, 節(jié)點(diǎn)對(duì)比, 將算法復(fù)雜度從O(n^3)降低到O(n)
- key值優(yōu)化, 避免用index作為key值, 兄弟節(jié)點(diǎn)中唯一就行
5. 高階組件
高階組件就是一個(gè)函數(shù)肌访,且該函數(shù)(wrapper)接受一個(gè)組件作為參數(shù),并返回一個(gè)新的組件艇劫。
高階組件并不關(guān)心數(shù)據(jù)使用的方式和原因吼驶,而被包裹的組件也不關(guān)心數(shù)據(jù)來自何處.
-
react-dnd: 根組件, source, target等
export default DragSource(type, spec, collect)(MyComponent)
- 重構(gòu)代碼庫使用HOC提升開發(fā)效率
6. hook(v16.7測(cè)試)
在無狀態(tài)組件(如函數(shù)式組件)中也能操作state以及其他react特性, 通過useState
7. redux和vuex以及dva:
- redux: 通過store存儲(chǔ),通過action唯一更改,reducer描述如何更改蟹演。dispatch一個(gè)action
- dva: 基于redux风钻,結(jié)合redux-saga等中間件進(jìn)行封裝
- vuex:類似dva,集成化轨帜。action異步魄咕,mutation非異步
8. react和vue的區(qū)別
- 數(shù)據(jù)是否可變: react整體是函數(shù)式的思想,把組件設(shè)計(jì)成純組件蚌父,狀態(tài)和邏輯通過參數(shù)傳入,所以在react中毛萌,是單向數(shù)據(jù)流苟弛,推崇結(jié)合immutable來實(shí)現(xiàn)數(shù)據(jù)不可變; vue的思想是響應(yīng)式的,也就是基于是數(shù)據(jù)可變的阁将,通過對(duì)每一個(gè)屬性建立Watcher來監(jiān)聽膏秫,當(dāng)屬性變化的時(shí)候,響應(yīng)式的更新對(duì)應(yīng)的虛擬dom做盅$拖鳎總之,react的性能優(yōu)化需要手動(dòng)去做吹榴,而vue的性能優(yōu)化是自動(dòng)的亭敢,但是vue的響應(yīng)式機(jī)制也有問題,就是當(dāng)state特別多的時(shí)候图筹,Watcher也會(huì)很多帅刀,會(huì)導(dǎo)致卡頓,所以大型應(yīng)用(狀態(tài)特別多的)一般用react远剩,更加可控扣溺。
- 通過js來操作一切,還是用各自的處理方式: react的思路是all in js瓜晤,通過js來生成html锥余,所以設(shè)計(jì)了jsx,還有通過js來操作css痢掠,社區(qū)的styled-component驱犹、jss等; vue是把html,css志群,js組合到一起着绷,用各自的處理方式,vue有單文件組件锌云,可以把html荠医、css、js寫到一個(gè)文件中,html提供了模板引擎來處理彬向。
- 類式的組件寫法兼贡,還是聲明式的寫法: react是類式的寫法,api很少; 而vue是聲明式的寫法娃胆,通過傳入各種options遍希,api和參數(shù)都很多。所以react結(jié)合typescript更容易一起寫里烦,vue稍微復(fù)雜凿蒜。
- 擴(kuò)展不同: react可以通過高階組件(Higher Order Components--HOC)來擴(kuò)展,而vue需要通過mixins來擴(kuò)展
-
什么功能內(nèi)置胁黑,什么交給社區(qū)去做: react做的事情很少废封,很多都交給社區(qū)去做,vue很多東西都是內(nèi)置的丧蘸,寫起來確實(shí)方便一些漂洋,
比如 redux的combineReducer就對(duì)應(yīng)vuex的modules,
比如reselect就對(duì)應(yīng)vuex的getter和vue組件的computed力喷,
vuex的mutation是直接改變的原始數(shù)據(jù)刽漂,而redux的reducer是返回一個(gè)全新的state,所以redux結(jié)合immutable來優(yōu)化性能弟孟,vue不需要贝咙。
9. react單向數(shù)據(jù)流怎么理解
React是單向數(shù)據(jù)流,數(shù)據(jù)主要從父節(jié)點(diǎn)傳遞到子節(jié)點(diǎn)(通過props)披蕉。如果頂層(父級(jí))的某個(gè)props改變了颈畸,React會(huì)重渲染所有的子節(jié)點(diǎn)。
10. React算法復(fù)雜度優(yōu)化
react樹對(duì)比是按照層級(jí)去對(duì)比的没讲, 他會(huì)給樹編號(hào)0,1,2,3,4.... 然后相同的編號(hào)進(jìn)行比較眯娱。 所以復(fù)雜度是n,這個(gè)好理解爬凑。
關(guān)鍵是傳統(tǒng)diff的復(fù)雜度是怎么算的徙缴? 傳統(tǒng)的diff需要出了上面的比較之外,還需要跨級(jí)比較嘁信。 他會(huì)將兩個(gè)樹的節(jié)點(diǎn)于样,兩兩比較,這就有n^2的復(fù)雜度了潘靖。 然后還需要編輯樹穿剖,編輯的樹可能發(fā)生在任何節(jié)點(diǎn),需要對(duì)樹進(jìn)行再一次遍歷操作卦溢,因此復(fù)雜度為n糊余。加起來就是n^3了秀又。
11. React優(yōu)點(diǎn)
聲明式, 組件化, 一次學(xué)習(xí), 隨處編寫. 靈活, 豐富, 輕巧, 高效
移動(dòng)端相關(guān)
1. 移動(dòng)端兼容適配
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- rem, em, 百分比
- 框架的柵格布局
- media query媒體查詢
- 手淘團(tuán)隊(duì)的一套flexible.js, 自動(dòng)判斷dpr進(jìn)行整個(gè)布局視口的放縮
2. flexible如何實(shí)現(xiàn)自動(dòng)判斷dpr
判斷機(jī)型, 找出樣本機(jī)型去適配. 比如iphone以6為樣本, 寬度375px, dpr是2
3. 為什么以iPhone6為標(biāo)準(zhǔn)的設(shè)計(jì)稿的尺寸是以750px寬度來設(shè)計(jì)的呢?
iPhone6的滿屏寬度是375px贬芥,而iPhone6采用的視網(wǎng)膜屏的物理像素是滿屏寬度的2倍吐辙,也就是dpr(設(shè)備像素比)為2, 并且設(shè)計(jì)師所用的PS設(shè)計(jì)軟件分辨率和像素關(guān)系是1:1。所以為了做出的清晰的頁面蘸劈,設(shè)計(jì)師一般給出750px的設(shè)計(jì)圖昏苏,我們?cè)俑鶕?jù)需求對(duì)元素的尺寸設(shè)計(jì)和壓縮。
4. 如何處理異形屏iphone X
-
safe area
: 默認(rèn)放置在安全區(qū)域以避免遮擋, 但會(huì)壓縮 - 在meta中添加
viewport-fit=cover
: 告訴瀏覽器要講整個(gè)頁面渲染到瀏覽器中威沫,不管設(shè)備是圓角與否贤惯,這個(gè)時(shí)候會(huì)造成頁面的元素被圓角遮擋 -
padding: constant(env)
: 解決遮擋問題
5. 移動(dòng)端首屏優(yōu)化
- 采用服務(wù)器渲染ssr
- 按需加載配合webpack分塊打包, 通過entry和commonChunkPlugin
- 很有必要將script標(biāo)簽?異步
- 有輪播圖 最好給個(gè)默認(rèn) 另外要處理圖片懶加載
- 打包線上也要注意去掉map 文件
- 組件, 路由懶加載
- webpack的一切配置 肯定是必須的
- 壓縮圖片 https://tinypng.com/
- 建議還是用webpack的圖片壓縮插件
- 骨架屏
- Loading頁面
6. PWA全稱Progressive Web App,即漸進(jìn)式WEB應(yīng)用
一個(gè) PWA 應(yīng)用首先是一個(gè)網(wǎng)頁, 可以通過 Web 技術(shù)編寫出一個(gè)網(wǎng)頁應(yīng)用. 隨后添加上 App Manifest 和 Service Worker 來實(shí)現(xiàn) PWA 的安裝和離線等功能
解決了哪些問題壹甥?
- 可以添加至主屏幕救巷,點(diǎn)擊主屏幕圖標(biāo)可以實(shí)現(xiàn)啟動(dòng)動(dòng)畫以及隱藏地址欄
- 實(shí)現(xiàn)離線緩存功能,即使用戶手機(jī)沒有網(wǎng)絡(luò)句柠,依然可以使用一些離線功能
- 實(shí)現(xiàn)了消息推送
它解決了上述提到的問題,這些特性將使得 Web 應(yīng)用漸進(jìn)式接近原生 App棒假。
7. 離線包方案
現(xiàn)在 web 頁面在移動(dòng)端的地位越來越高溯职,大部分主流 App 采用 native + webview 的 hybrid 模式,加載遠(yuǎn)程頁面受限于網(wǎng)絡(luò)帽哑,本地 webview 引擎谜酒,經(jīng)常會(huì)出現(xiàn)渲染慢導(dǎo)致的白屏現(xiàn)象,體驗(yàn)很差妻枕,于是離線包方案應(yīng)運(yùn)而生歇盼。動(dòng)態(tài)下載的離線包可以使得我們不需要走完整的 App 審核發(fā)布流程就完成了版本的更新
8. 自適應(yīng)和響應(yīng)式布局的區(qū)別
自適應(yīng)布局通過檢測(cè)視口分辨率亚再,來判斷當(dāng)前訪問的設(shè)備是:pc端、平板、手機(jī)叮雳,從而請(qǐng)求服務(wù)層,返回不同的頁面前方;響應(yīng)式布局通過檢測(cè)視口分辨率趋急,針對(duì)不同客戶端在客戶端做代碼處理,來展現(xiàn)不同的布局和內(nèi)容饵撑。
自適應(yīng)布局需要開發(fā)多套界面剑梳,而響應(yīng)式布局只需要開發(fā)一套界面就可以了。
自適應(yīng)對(duì)頁面做的屏幕適配是在一定范圍:比如pc端一般要大于1024像素滑潘,手機(jī)端要小于768像素垢乙。而響應(yīng)式布局是一套頁面全部適應(yīng)。
自適應(yīng)布局如果屏幕太小會(huì)發(fā)生內(nèi)容過于擁擠语卤。而響應(yīng)式布局正是為了解決這個(gè)問題而衍生出的概念追逮,它可以自動(dòng)識(shí)別屏幕寬度并做出相應(yīng)調(diào)整的網(wǎng)頁設(shè)計(jì)酪刀。
插件及工具相關(guān)
1. babel和polyfill
Babel
: Babel 是一個(gè)廣泛使用的 ES6 轉(zhuǎn)碼器,可以將 ES6 代碼轉(zhuǎn)為 ES5 代碼羊壹。注意:Babel 默認(rèn)只轉(zhuǎn)換新的 JavaScript 句法(syntax)蓖宦,而不轉(zhuǎn)換新的 APIPolyfill
: Polyfill的準(zhǔn)確意思為,用于實(shí)現(xiàn)瀏覽器并不支持的原生API的代碼油猫。
2. jpg, jpeg和png區(qū)別
- jpg是jpeg的縮寫, 二者一致
- PNG就是為取代GIF而生的, 無損壓縮, 占用內(nèi)存多
- jpg犧牲圖片質(zhì)量, 有損, 占用內(nèi)存小
- PNG格式可編輯稠茂。如圖片中有字體等,可利用PS再做更改情妖。JPG格式不可編輯
3. git rebase和merge區(qū)別
前端性能優(yōu)化
- 減少HTTP請(qǐng)求(合并css睬关、js,雪碧圖/base64圖片)
- 壓縮(css毡证、js电爹、圖片皆可壓縮,使用webpack uglify和 svg)
- 樣式表放頭部,腳本放底部
- 使用CDN(這部分丐箩,不少前端都不用考慮,負(fù)責(zé)發(fā)布的兄弟可能會(huì)負(fù)責(zé)搞好)
- http緩存
- bosify圖片壓縮: 根據(jù)具體情況修改圖片后綴或格式 后端根據(jù)格式來判斷存儲(chǔ)原圖還是縮略圖
- 懶加載, 預(yù)加載
- 替代方案: 骨架屏, SSR
- webpack優(yōu)化
原生通信
1.JSBridge通信原理, 有哪幾種實(shí)現(xiàn)的方式恤煞?
JsBridge給JavaScript提供了調(diào)用Native功能屎勘,Native也能夠操控JavaScript。這樣前端部分就可以方便使用地理位置居扒、攝像頭以及登錄支付等Native能力啦概漱。JSBridge構(gòu)建 Native和非Native間消息通信的通道,而且是 雙向通信的通道喜喂。
- JS 向 Native 發(fā)送消息 : 調(diào)用相關(guān)功能瓤摧、通知 Native 當(dāng)前 JS 的相關(guān)狀態(tài)等。
- Native 向 JS 發(fā)送消息 : 回溯調(diào)用結(jié)果玉吁、消息推送照弥、通知 JS 當(dāng)前 Native 的狀態(tài)等。
2.實(shí)現(xiàn)一個(gè)簡單的 JSBridge诈茧,設(shè)計(jì)思路产喉?
算法相關(guān)
1. 二分查找和冒泡排序
- 二分查找: 遞歸(分左右, 傳遞start,end參數(shù))和非遞歸(使用while(l < h))
- 冒泡排序: 兩個(gè)for循環(huán)
2. 快速排序
function quickSort (arr) {
if (arr.length < 2) return arr
var middle = Math.floor(arr.length / 2)
var flag = arr.splice(middle, 1)[0]
var left = [],
right = []
for (var i = 0; i < arr.length; i++) {
if (arr[i] < flag) {
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return quickSort(left).concat([flag], quickSort(right))
}
3. 最長公共子串
function findSubStr(str1, str2) {
if (str1.length > str2.length) {
[str1, str2] = [str2, str1]
}
var result = ''
var len = str1.length
for (var j = len; j > 0; j--) {
for (var i = 0; i < len - j; i++) {
result = str1.substr(i, j)
if (str2.includes(result)) return result
}
}
}
console.log(findSubStr('aabbcc11', 'ppooiiuubcc123'))
4. 最長公共子序列(LCS動(dòng)態(tài)規(guī)劃)
// dp[i][j] 計(jì)算去最大長度,記住口訣:相等左上角加一敢会,不等取上或左最大值
function LCS(str1, str2){
var rows = str1.split("")
rows.unshift("")
var cols = str2.split("")
cols.unshift("")
var m = rows.length
var n = cols.length
var dp = []
for(var i = 0; i < m; i++){
dp[i] = []
for(var j = 0; j < n; j++){
if(i === 0 || j === 0){
dp[i][j] = 0
continue
}
if(rows[i] === cols[j]){
dp[i][j] = dp[i-1][j-1] + 1 //對(duì)角+1
}else{
dp[i][j] = Math.max( dp[i-1][j], dp[i][j-1]) //對(duì)左邊曾沈,上邊取最大
}
}
console.log(dp[i].join(""))//調(diào)試
}
return dp[i-1][j-1]
}
//!!!如果它來自左上角加一,則是子序列鸥昏,否則向左或上回退塞俱。
//findValue過程,其實(shí)就是和 就是把T[i][j]的計(jì)算反過來吏垮。
// 求最長子序列
function findValue(input1,input2,n1,n2,T){
var i = n1-1,j=n2-1;
var result = [];//結(jié)果保存在數(shù)組中
console.log(i);
console.log(j);
while(i>0 && j>0){
if(input1[i] == input2[j]){
result.unshift(input1[i]);
i--;
j--;
}else{
//向左或向上回退
if(T[i-1][j]>T[i][j-1]){
//向上回退
i--;
}else{
//向左回退
j--;
}
}
}
console.log(result);
}
5. 數(shù)組去重障涯,多種方法
- 雙for循環(huán), splice剔除并i--回退
- indexOf等于index
- filter indexOf === index
- 新數(shù)組indexOf === index
- 使用空對(duì)象等
6. 實(shí)現(xiàn)一個(gè)函數(shù)功能:sum(1,2,3,4..n)轉(zhuǎn)化為 sum(1)(2)(3)(4)…(n)
// 使用柯里化 + 遞歸
function curry ( fn ) {
var c = (...arg) => (fn.length === arg.length) ?
fn (...arg) : (...arg1) => c(...arg, ...arg1)
return c
}
7. 反轉(zhuǎn)二叉樹
var invertTree = function (root) {
if (root !== null) {
[root.left, root.right] = [root.right, root.left]
invertTree(root.left)
invertTree(root.right)
}
return root
}
8. 貪心算法解決背包問題
var items = ['A','B','C','D']
var values = [50,220,60,60]
var weights = [5,20,10,12]
var capacity = 32 //背包容積
greedy(values, weights, capacity) // 320
function greedy(values, weights, capacity) {
var result = 0
var rest = capacity
var sortArray = []
var num = 0
values.forEach((v, i) => {
sortArray.push({
value: v,
weight: weights[i],
ratio: v / weights[i]
})
})
sortArray.sort((a, b) => b.ratio - a.ratio)
sortArray.forEach((v, i) => {
num = parseInt(rest / v.weight)
rest -= num * v.weight
result += num * v.value
})
return result
}
9. 輸入一個(gè)遞增排序的數(shù)組和一個(gè)數(shù)字S罐旗,在數(shù)組中查找兩個(gè)數(shù),使得他們的和正好是S唯蝶,如果有多對(duì)數(shù)字的和等于S九秀,輸出兩個(gè)數(shù)的乘積最小的。
function FindNumbersWithSum(array, sum)
{
var index = 0
for (var i = 0; i < array.length - 1 && array[i] < sum / 2; i++) {
for (var j = i + 1; j < array.length; j++) {
if (array[i] + array[j] === sum) return [array[i], array[j]]
}
//index = array.indexOf(sum - array[i], i + 1)
// if (index !== -1) {
// return [array[i], array[index]]
//}
}
return []
10. 二叉樹各種(層序)遍歷
// 根據(jù)前序和中序重建二叉樹
/* function TreeNode(x) {
this.val = x;
this.left = null;
this.right = null;
} */
function reConstructBinaryTree(pre, vin)
{
var result = null
if (pre.length === 1) {
result = {
val: pre[0],
left: null,
right: null
}
} else if (pre.length > 1) {
var root = pre[0]
var vinRootIndex = vin.indexOf(root)
var vinLeft = vin.slice(0, vinRootIndex)
var vinRight = vin.slice(vinRootIndex + 1, vin.length)
pre.shift()
var preLeft = pre.slice(0, vinLeft.length)
var preRight = pre.slice(vinLeft.length, pre.length)
result = {
val: root,
left: reConstructBinaryTree(preLeft, vinLeft),
right: reConstructBinaryTree(preRight, vinRight)
}
}
return result
}
// 遞歸
// 前序遍歷
function prevTraverse (node) {
if (node === null) return;
console.log(node.data);
prevTraverse(node.left);
prevTraverse(node.right);
}
// 中序遍歷
function middleTraverse (node) {
if (node === null) return;
middleTraverse(node.left);
console.log(node.data);
middleTraverse(node.right);
}
// 后序遍歷
function lastTraverse (node) {
if (node === null) return;
lastTraverse(node.left);
lastTraverse(node.right);
console.log(node.data);
}
// 非遞歸
// 前序遍歷
function preTraverse(tree) {
var arr = [],
node = null
arr.unshift(tree)
while (arr.length) {
node = arr.shift()
console.log(node.root)
if (node.right) arr.unshift(node.right)
if (node.left) arr.unshift(node.left)
}
}
// 中序遍歷
function middleTraverseUnRecursion (root) {
let arr = [],
node = root;
while (arr.length !== 0 || node !== null) {
if (node === null) {
node = arr.shift();
console.log(node.data);
node = node.right;
} else {
arr.unshift(node);
node = node.left;
}
}
}
// 廣度優(yōu)先-層序遍歷
// 遞歸
var result = []
var stack = [tree]
var count = 0
var bfs = function () {
var node = stack[count]
if (node) {
result.push(node.value)
if (node.left) stack.push(node.left)
if (node.right) stack.push(node.right)
count++
bfs()
}
}
bfs()
console.log(result)
// 非遞歸
function bfs (node) {
var result = []
var queue = []
queue.push(node)
while (queue.length) {
node = queue.shift()
result.push(node.value)
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
return result
}
11. 各種排序
// 插入排序
function insertSort(arr) {
var temp
for (var i = 1; i < arr.length; i++) {
temp = arr[i]
for (var j = i; j > 0 && temp < arr[j - 1]; j--) {
arr[j] = arr[j - 1]
}
arr[j] = temp
}
return arr
}
console.log(insertSort([3, 1, 8, 2, 5]))
// 歸并排序
function mergeSort(array) {
var result = array.slice(0)
function sort(array) {
var length = array.length
var mid = Math.floor(length * 0.5)
var left = array.slice(0, mid)
var right = array.slice(mid, length)
if (length === 1) return array
return merge(sort(left), sort(right))
}
function merge(left, right) {
var result = []
while (left.length || right.length) {
if (left.length && right.length) {
if (left[0] < right[0]) {
result.push(left.shift())
} else {
result.push(right.shift())
}
} else if (left.length) {
result.push(left.shift())
} else {
result.push(right.shift())
}
}
return result
}
return sort(result)
}
console.log(mergeSort([5, 2, 8, 3, 6]))
// 二分插入排序
function twoSort(array) {
var len = array.length,
i,
j,
tmp,
low,
high,
mid,
result
result = array.slice(0)
for (i = 1; i < len; i++) {
tmp = result[i]
low = 0
high = i - 1
while (low <= high) {
mid = parseInt((high + low) / 2, 10)
if (tmp < result[mid]) {
high = mid - 1
} else {
low = mid + 1
}
}
for (j = i - 1; j >= high + 1; j--) {
result[j + 1] = result[j]
}
result[j + 1] = tmp
}
return result
}
console.log(twoSort([4, 1, 7, 2, 5]))
12. 使用尾遞歸對(duì)斐波那契優(yōu)化
遞歸非常耗費(fèi)內(nèi)存粘我,因?yàn)樾枰瑫r(shí)保存成千上百個(gè)調(diào)用幀鼓蜒,很容易發(fā)生“棧溢出”錯(cuò)誤(stack overflow)。但對(duì)于尾遞歸來說征字,由于只存在一個(gè)調(diào)用幀都弹,所以永遠(yuǎn)不會(huì)發(fā)生“棧溢出”錯(cuò)誤。
// 傳統(tǒng)遞歸斐波那契, 會(huì)造成超時(shí)或溢出
function Fibonacci (n) {
if ( n <= 1 ) {return 1};
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
Fibonacci(10) // 89
Fibonacci(100) // 超時(shí)
Fibonacci(500) // 超時(shí)
// 使用尾遞歸優(yōu)化, 可規(guī)避風(fēng)險(xiǎn)
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
if( n <= 1 ) {return ac2};
return Fibonacci2 (n - 1, ac2, ac1 + ac2);
}
Fibonacci2(100) // 573147844013817200000
Fibonacci2(1000) // 7.0330367711422765e+208
Fibonacci2(10000) // Infinity
13. 兩個(gè)升序數(shù)組合并為一個(gè)升序數(shù)組
function sort (A, B) {
var i = 0, j = 0, p = 0, m = A.length, n = B.length, C = []
while (i < m || j < n) {
if (i < m && j < n) {
C[p++] = A[i] < B[j] ? A[i++] : B[j++]
} else if (i < m) {
C[p++] = A[i++]
} else {
C[p++] = B[j++]
}
}
return C
}
node相關(guān)
1. node的router是什么
2. 數(shù)據(jù)庫索引是啥
- 狹義上: 索引是數(shù)據(jù)庫針對(duì)每條數(shù)據(jù)自動(dòng)生成的內(nèi)部唯一id標(biāo)識(shí), 用以快速搜索定位數(shù)據(jù)
- 廣義上: 是數(shù)據(jù)庫根據(jù)每條數(shù)據(jù)形成的關(guān)鍵字, 將劃分為樹形結(jié)構(gòu), 便于sql語句對(duì)數(shù)據(jù)的查找, 使算法復(fù)雜度降低到O(logn)