其實(shí)感覺(jué)前端的面試就是一些零碎的知識(shí)點(diǎn)蛤虐,最后上升為架構(gòu)而已唇撬。這篇博客我也會(huì)將架構(gòu)設(shè)計(jì)融入其中。大致通過(guò)以下幾個(gè)分類進(jìn)行分析:
- HTML/CSS部分
- JavaScript部分
- 數(shù)據(jù)結(jié)構(gòu)部分(算法)
- 框架之Angular.js
- 框架之Vue.js
- 框架之React.js
- 移動(dòng)端
- HTTP
- WEB安全
- WEB滲透之Kali Linux
- 前端性能
- 設(shè)計(jì)模式
- 正則表達(dá)式
- 前端架構(gòu)設(shè)計(jì)
一、HTML/CSS部分
1.1 什么是盒子模型叙凡?
在網(wǎng)頁(yè)中,一個(gè)元素占有空間的大小由幾個(gè)部分構(gòu)成密末,其中包括元素的內(nèi)容(content)握爷,元素的內(nèi)邊距(padding)跛璧,元素的邊框(border),元素的外邊距(margin)四個(gè)部分新啼。這四個(gè)部分占有的空間中追城,有的部分可以顯示相應(yīng)的內(nèi)容,而有的部分只用來(lái)分隔相鄰的區(qū)域或區(qū)域燥撞。4個(gè)部分一起構(gòu)成了css中元素的盒模型座柱。
1.2 什么是css Hack?
一般來(lái)說(shuō)物舒,css Hack就是針對(duì)不同的瀏覽器寫(xiě)不同css樣式色洞。css hack一般來(lái)說(shuō)是為了兼容IE瀏覽器的。
IE瀏覽器Hack一般又分為三種: 條件Hack冠胯、屬性Hack火诸、選擇器Hack。
// 1.條件Hack
<!--[if IE]>
<style>
.test {color:red;}
</style>
<![endif]-->
// 2.屬性Hack
.test {
color: #090\9; /* For IE8+ */
*color: #f00; /* For IE7 and earlier */
_color: #ff0; /* For IE6 and earlier */
}
// 3.選擇器Hack
*html .test{
color: #090; /* For IE6 and earlier */
}
*+html .test {
color: #ff0; /* For IE7 */
}
1.3 什么是同步荠察?異步惭蹂?
當(dāng)我在學(xué)習(xí)前端的時(shí)候,看到這個(gè)問(wèn)題的時(shí)候割粮,讓不不禁想起了學(xué)習(xí)Linux時(shí)盾碗,一直想的一個(gè)問(wèn)題。什么是異步舀瓢,同步廷雅?什么是阻塞,非阻塞當(dāng)時(shí)這個(gè)問(wèn)題困惑了我很久京髓,一直搞不清楚有什么區(qū)別航缀,異步不就是非阻塞嗎,同步不就是阻塞嗎堰怨?下面咱們就嘮嘮嗑來(lái)說(shuō)說(shuō)這里面的玄機(jī)芥玉。在這里咱們主要來(lái)以網(wǎng)絡(luò)I/O為例:
1.3.1 同步和異步
實(shí)際上同步與異步是針對(duì)***應(yīng)用程序***與***內(nèi)核***的交互而言的。同步過(guò)程中進(jìn)程觸發(fā)IO操作并等待或者輪詢的去查看IO操作是否完成备图。異步過(guò)程中進(jìn)程觸發(fā)IO操作后灿巧,直接返回,做自己的事情揽涮,IO交給內(nèi)核來(lái)處理抠藕,完成后內(nèi)核通知進(jìn)程IO完成。
(這里大家不禁要問(wèn)了蒋困,什么是IO盾似,如果你是做后端開(kāi)發(fā)的,IO對(duì)于你來(lái)說(shuō)很容易理解雪标,但是純做前端的話就不容易理解了零院。IO就是input/output溉跃,輸入輸出。比如文件的讀寫(xiě)操作告抄,網(wǎng)絡(luò)的請(qǐng)求和得到數(shù)據(jù)的操作等等撰茎。不懂的童鞋要去學(xué)習(xí)操作系統(tǒng)了)
直接上圖吧:
1.3.2 阻塞與非阻塞
簡(jiǎn)單理解為需要做一件事情能不能立即得到返回應(yīng)答。如果不能立刻獲得返回玄妈,需要等待,那就阻塞了髓梅,否則就可以理解為非阻塞拟蜻。詳細(xì)區(qū)別如下圖所示:
需要注意了, 這里的立即返回,是針對(duì)內(nèi)核來(lái)說(shuō)的枯饿。就是說(shuō)這個(gè)應(yīng)用程序的某些代碼會(huì)不會(huì)阻塞內(nèi)核(CPU)的執(zhí)行酝锅。而同步異步是針對(duì)于應(yīng)用程序來(lái)說(shuō)的,到底某些代碼會(huì)不會(huì)影響下面代碼的執(zhí)行奢方。
1.4 px和rem和em的區(qū)別搔扁?
px和rem和em都是長(zhǎng)度單位, 區(qū)別是px的值是固定的,指定是多少就是多少蟋字,計(jì)算比較容易稿蹲。em的值不是固定的,它的值是繼承父級(jí)元素的字體大小(其實(shí)也不能說(shuō)是父級(jí)鹊奖,應(yīng)該說(shuō)是自身苛聘,如果自身沒(méi)有設(shè)置font-size, 則去找父級(jí),然后父級(jí)沒(méi)設(shè)置忠聚,在往上找设哗,如果沒(méi)有找到,就是瀏覽器默認(rèn)的字體)两蟀。下面舉例說(shuō)明:
/* 1. em的案列 */
.test {
font-size: 20px; /* 這句話聲明之后就代表了1em = 20px;但是后面的代碼與這個(gè)沒(méi)有關(guān)系 */
text-indent: 2em; /* 單位轉(zhuǎn)換之后2em = 40px */
}
/* 2.rem的案列 -- rem是根據(jù)html的font-size大小定的网梢,一般用于移動(dòng)端網(wǎng)站開(kāi)發(fā)時(shí)使用,進(jìn)行屏幕適配赂毯。*/
html {
font-size: 40px;
}
.test {
font-size: 1rem; /* 單位轉(zhuǎn)換后為40px */
}
1.5 瀏覽器的內(nèi)核分別是什么?
IE: trident內(nèi)核
Firefox: gecko內(nèi)核
Safari: webkit內(nèi)核
Opera: 以前是presto內(nèi)核战虏,Opera現(xiàn)已改用Google Chrome的Blink內(nèi)核。
Chrome: Blink(基于Webkit內(nèi)核党涕,google和Opera公同開(kāi)發(fā))
1.6 清除浮動(dòng)的影響的方法活烙?
這個(gè)問(wèn)題之前一直說(shuō)一直說(shuō),沒(méi)有時(shí)間去總結(jié)遣鼓。咱們從下面幾種方式進(jìn)行探究啸盏。
- 1.空的div方式(不是特別好,如果清除浮動(dòng)地方多了骑祟,就會(huì)有多個(gè)空標(biāo)簽)
/* 在要清除浮動(dòng)的地方加上<div class="clearfix"></div> */
.clearfix {
clear: both;
height: 0px;
}
- 2.使用overflow方式進(jìn)行清除浮動(dòng)帶來(lái)的影響回懦。
/* 想要使用overflow清除浮動(dòng)帶來(lái)的影響气笙,一般分為兩步驟:
1. 給它加一個(gè)父元素
2. 在父元素上寫(xiě)overflow: hidden;
*/
<div style="overflow:hidden;">
<div class="right">
</div>
</div>
- 3.使用偽元素的方式進(jìn)行清除浮動(dòng)帶來(lái)的影響。
/* 這里說(shuō)明一下怯晕,一般使用這種方式也是需要給它加一個(gè)父元素的... */
.test::after {
content:"";
display:block;
height:0;
clear:both;
/* visibility:hidden; */
}
1.7 margin折疊現(xiàn)象?
要想解釋這個(gè)現(xiàn)象潜圃,還是要了解BFC的。這里的我就不啰嗦了舟茶,就直接說(shuō)一下解決方案了谭期。(我經(jīng)常使用的方案, 其他方案自行百度)
/* 這個(gè)很簡(jiǎn)單和上一個(gè)題目一樣
*/
在父層加上overflow:hidden;
其他CSS的問(wèn)題待續(xù)吧(CSS3動(dòng)畫(huà)、漸進(jìn)吧凉、Canvas隧出、SVG等等先忽略),特別是less阀捅、sass胀瞪、stylus等預(yù)處理語(yǔ)言,面試中也是常問(wèn)的重點(diǎn)饲鄙。
二凄诞、JavaScript部分
這一部分涉及的內(nèi)容就多了,那么我會(huì)從ES5和ES6都會(huì)講解到忍级。
先列個(gè)目錄
2.1 如何快速合并兩個(gè)數(shù)組帆谍?
這個(gè)問(wèn)題看起來(lái)很簡(jiǎn)單,實(shí)則沒(méi)有那么簡(jiǎn)單轴咱。給大家提幾個(gè)問(wèn)題既忆,合并數(shù)組什么方式最好也就是說(shuō)性能最佳?合并之后用不用去重嗦玖?等等都需要考慮患雇。網(wǎng)上給出了push和concat的對(duì)比。(溫馨提示:如果不懂call和apply的童鞋宇挫,自行學(xué)習(xí)苛吱。)
2.1.1. 先使用代碼來(lái)對(duì)比(concat函數(shù)與Array.prototype.push.apply)
function testClass() {
var testArray1 = [];
var testArray2 = [];
this.resetArray = function() {
for (var i = 0; i < 100000; i++) {
testArray1.push(i);
testArray2.push(i + 100000);
}
}
this.applyTest = function() {
var startTime = 0,
endTime = 0;
console.log('開(kāi)始合并的時(shí)間是:' + (startTime = new Date().getTime()));
var aa = Array.prototype.push.apply(testArray1, testArray2);
console.log(aa);
console.log('合并完成的時(shí)間是:' + (endTime = new Date().getTime()));
console.log('合并數(shù)組所用的時(shí)間是:' + (endTime - startTime));
}
this.concatTest = function() {
var startTime = 0,
endTime = 0;
console.log('開(kāi)始合并的時(shí)間是:' + (startTime = new Date().getTime()));
var aa = testArray1.concat(testArray2);
console.log(aa.length);
console.log('合并完成的時(shí)間是:' + (endTime = new Date().getTime()));
console.log('合并數(shù)組所用的時(shí)間是:' + (endTime - startTime));
}
}
var apply = new testClass();
apply.resetArray();
apply.applyTest();
var concat = new testClass();
concat.resetArray();
concat.concatTest();
通過(guò)測(cè)試結(jié)果可知:
使用Array.prototype.push.apply 方式性能非常低下,在20w的數(shù)據(jù)下器瘪,執(zhí)行時(shí)間將近是concat方法的11-17倍左右翠储。
2.1.2 Array.prototype.concat.apply 和 concat對(duì)比
很多程序員喜歡直接使用Array構(gòu)造函數(shù)下的原型對(duì)象上的方法,以此縮短搜索函數(shù)的時(shí)間橡疼,這種方式是否能夠帶來(lái)性能的提升援所?
在這里只需要將第一個(gè)函數(shù)中的代碼改成
var aa = Array.prototype.concat.apply(testArray1, testArray2);
根據(jù)測(cè)試的結(jié)果,使用Array.prototype.concat.apply的方式還是比直接使用concat函數(shù)慢些欣除。之前我也沒(méi)有注意過(guò)住拭,這次測(cè)試,我感覺(jué)問(wèn)題大了。難道之前想錯(cuò)了滔岳,經(jīng)過(guò)又一輪的測(cè)試杠娱,證明了我的猜測(cè)。下一輪的對(duì)比您應(yīng)該想到了谱煤,就是call和apply的性能摊求。(這個(gè)對(duì)比大家自行研究,結(jié)論就是call的性能在chrome瀏覽上明顯比apply性能要高很多)
2.1.3 Array.prototype.concat.call 和 concat對(duì)比
將第一個(gè)函數(shù)中的代碼改成如下:
var aa = Array.prototype.concat.call(testArray1, testArray2);
最后的測(cè)試結(jié)果驗(yàn)證使用Array.prototype.concat.call比直接使用concat方法性能提升了一倍刘离。因此最后的得出的結(jié)論就是數(shù)據(jù)合并性能最高的方式就是使用Array.prototype.concat.call室叉。
各位兄弟姐妹,這只是我自己的測(cè)試結(jié)果硫惕,如果有出入茧痕,歡迎指正。至于去重的算法及其性能優(yōu)化放到算法一節(jié)說(shuō)吧疲憋。
2.2 說(shuō)說(shuō)你對(duì)原型鏈的理解凿渊?
這個(gè)問(wèn)題也是相當(dāng)有點(diǎn)難度的問(wèn)題梁只。首先要搞清楚什么是原型對(duì)象缚柳、什么是構(gòu)造函數(shù)、什么是實(shí)例化對(duì)象搪锣。如果和我一樣都清楚的童鞋秋忙,您只需看圖即可。
這張圖表明了如果數(shù)組實(shí)例化之后构舟,它原型的整個(gè)指向灰追。還有一種情況就是當(dāng)實(shí)例化對(duì)象時(shí),采用var a = {}或者new Object();它的指向如下:
2.3 說(shuō)說(shuō)你對(duì)js中面向?qū)ο缶幊痰睦斫猓?/h2>
在沒(méi)有學(xué)習(xí)面向?qū)ο缶幊痰臅r(shí)候狗超,大家更多的是函數(shù)(就是一些功能性代碼的集合)弹澎,而面向?qū)ο蟮乃枷胧菑牧硗庖粋€(gè)角度出發(fā)來(lái)解決函數(shù)的局限性。它把對(duì)象作為程序的基本單元努咐,其實(shí)對(duì)象就是對(duì)事物的一種抽象描述苦蒿。
人們發(fā)現(xiàn),現(xiàn)實(shí)世界中的事物渗稍,都可以用「數(shù)據(jù)」和「能力」來(lái)描述佩迟。比如我要描述一個(gè)人,「數(shù)據(jù)」就是他的年齡竿屹、性別报强、身高體重,「能力」就是他能做什么工作拱燃,承擔(dān)什么樣的責(zé)任秉溉。描述一臺(tái)電視,「數(shù)據(jù)」就是它的屏幕尺寸、亮度坚嗜,「能力」就是播放《葫蘆娃》夯膀。
面向?qū)ο蟮氖澜缋铮教幎际菍?duì)象苍蔬。對(duì)象不光有「數(shù)據(jù)」和「能力」诱建,還可以接受命令。例如你可以讓「狗」這個(gè)對(duì)象「吃狗糧」碟绑,就可以把「吃狗糧」的命令發(fā)給「狗」讓其執(zhí)行俺猿,然后我們就實(shí)現(xiàn)了「狗吃狗糧」的需求。
現(xiàn)在對(duì)象有了格仲,如何進(jìn)行面向?qū)ο蟮木幊棠?很簡(jiǎn)單押袍,依次向不同的對(duì)象發(fā)送命令就可以了。比如產(chǎn)品經(jīng)理說(shuō)要把大象裝進(jìn)冰箱里凯肋,用面向?qū)ο髞?lái)實(shí)現(xiàn)谊惭,我們會(huì)先定義一個(gè)「冰箱」對(duì)象,它的「數(shù)據(jù)」就是當(dāng)前的冷凍溫度侮东,或者該冰箱已經(jīng)有了多少頭大象圈盔,「能力」就是開(kāi)門(mén)、關(guān)門(mén)悄雅。還有一個(gè)「大象」對(duì)象驱敲,它的「數(shù)據(jù)」可以是大象的智商、體積宽闲,「能力」就是「自己跑到冰箱里去」众眨。然后我們依次:
向冰箱下達(dá)「開(kāi)門(mén)」的命令。
向大象下達(dá)「進(jìn)冰箱」的命令容诬。
向冰箱下達(dá)「關(guān)門(mén)」的命令娩梨。
大家好好理解一下就可以整明白,當(dāng)然還有其他的編程思想览徒。比如面向接口狈定、面向切面都是常用編程思想。(具體到后面再講解吧)
2.4 JavaScript(ES5)中封裝吱殉、多態(tài)掸冤、繼承的實(shí)現(xiàn)方式?
2.4.1 JavaScript實(shí)現(xiàn)封裝
→原始模式
var cat = {
name: '',
color: ''
}
這種方式缺點(diǎn)是: 1.如果生成的對(duì)象很多就會(huì)很麻煩。2.不能看出實(shí)例之間的聯(lián)系
→簡(jiǎn)單工廠模式
function Cat(name, color) {
var obj = {};
obj.name = name;
obj.color = color;
return obj;
}
var cat1 = Cat("金毛", "黃色");
var cat2 = Cat("泰迪", "棕色");
這種方式可以解決代碼重復(fù)的問(wèn)題友雳,但是依然不能反映出實(shí)例對(duì)象之間的關(guān)系稿湿。
→構(gòu)造函數(shù)模式
function Cat(name, color) {
this.name = name;
this.color = color;
}
var cat1 = new Cat("金毛", "黃色");
var cat2 = new Cat("泰迪", "棕色");
構(gòu)造函數(shù)的方式確實(shí)好用,但是存在一個(gè)浪費(fèi)內(nèi)存的問(wèn)題押赊。所以就要使用原型模式饺藤。
→原型模式
function Cat(name, color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "貓科動(dòng)物";
Cat.prototype.eat = function(){alert("吃老鼠")};
還有等等一些模式進(jìn)行封裝包斑,大家自行去查詢即可。
2.4.2 JavaScript中繼承的實(shí)現(xiàn)
→原型繼承
// 基類
var Person = function() {
this.name = '張三';
this.age = 20;
};
Person.prototype = {
say: function() {
console.log('Person.prototype');
}
};
// 子類
var Student = function() {
};
// 這樣就可以繼承了Person里面的所有的方法涕俗。
Student.prototype = new Person();
Student.prototype.getTeacher = function(){
console.log('Student.prototype.getTeacher');
};
這種繼承存在一些問(wèn)題罗丰,就是無(wú)法通過(guò)參數(shù)定義對(duì)象。
→構(gòu)造函數(shù)實(shí)現(xiàn)繼承
function Person(){
this.race = '人類';
}
Person.prototype={
eat:function(){
alert('123')
}
};
/*學(xué)生對(duì)象*/
function Student(name, skin) {
// People(),
Person.apply(this, arguments);
this.name = name;
this.skin = skin;
}
構(gòu)造函數(shù)這種方式的繼承利用apply這個(gè)方法改變this的指針來(lái)完成繼承的再姑。
→組合模式實(shí)現(xiàn)繼承
組合模式就是將上述的原型繼承和構(gòu)造函數(shù)繼承的組合萌抵。
function Person(name, age) {}
Person.prototype.say = function() {}
function Student(name, age, no) {
/*會(huì)自動(dòng)調(diào)用Person的方法,同時(shí)將name age傳遞過(guò)去*/
Person.call(this, name, age);
//自己的屬性
this.no = no;
}
Student.prototype = new Person();
通過(guò)這種方式進(jìn)行繼承會(huì)更加完善元镀。至于其他的繼承方式在這就不一一列舉了绍填,比如寄生蟲(chóng)組合繼承、拷貝繼承等等栖疑。
2.4.3 JavaScript中重載的實(shí)現(xiàn)
這里只說(shuō)一種方式實(shí)現(xiàn)重載(根據(jù)arguments個(gè)數(shù))
function add() {
var sum = 0 ;
for ( var i = 0 ; i < arguments.length; i ++ ) {
sum += arguments[i];
}
return sum;
}
alert(add());
alert(add( 1 , 2 ));
alert(add( 1 , 2 , 3 ));
內(nèi)容太多了讨永,請(qǐng)移步web前端面試寶典-基礎(chǔ)篇(二)
有問(wèn)題請(qǐng)聯(lián)系QQ:136062834,一直感覺(jué)良好的攻城獅遇革。