前端面試題總結
寫在前面的話:
- 寫文目的:總結前端面試過程中沒回答上來的點,深化印象,也方便日后溫習。
- 寫文方法:寫之前先自己看相關知識,理解好后過段時間根據記憶來寫,最后對比糾正。
准備面試流程:
1.更新簡歷,多參考其他的優秀簡歷
2.復習面試題
筆者就是因為只更新了簡歷沒有復習導致基礎不過關,錯過兩家心儀的公司。
順便說下,平時工作中的確很多時候用不到也不會去背某些面試中的問題,不過面試題中基礎部分很重要,理解好基礎才更輕松掌握新框架新知識。時不時去看看面試題也不失為一種鞏固基礎的方法。一般一面面基礎,二面面項目,項目經驗再多,一面過不了,什么戲也不會有。
被面過的面試題:
css
css優先級,屬性選擇器的優先級在哪
0.類型選擇器(如, h1)和偽元素(如, ::before)
1.類選擇器,屬性選擇器,偽類(如,:hover)
3.ID選擇器
通用選擇器(universal selector)(*), 組合子(combinators) (+, >, ~, ' ') 和 否定偽類(negation pseudo-class)(:not()) 對特異性沒有影響。(但是,在 :not() 內部聲明的選擇器是會影響優先級,在計算選擇器數量時還是會把其中的選擇器當做普通選擇器進行計數)。
4.給元素添加的內聯樣式總會覆蓋外部樣式表的任何樣式 ,因此可看作是具有最高的優先級。
權重記憶口訣。一個元素名,或者偽元素+1,一個屬性選擇器/class或者偽類+10,一個id+100,一個行內樣式+1000。
**!important 規則例外
當在一個樣式聲明中使用一個!important 規則時,此聲明將覆蓋任何其他聲明。**
直接定位的樣式權重大於繼承的樣式,無論繼承的規則的特異性(優先級)如何。
Styles for a directly targeted element will always take precedence over inherited styles, regardless of the specificity of the inherited rule.
h1 {
color: purple;
}
#parent {
color: green;
}
當它應用在下面的HTML時:
<html>
<body id="parent">
<h1>Here is a title!</h1>
</body>
</html>
瀏覽器會將h1渲染成紫色。
因為h1選擇器清晰地定位了元素。
~ 組合器
A + B 匹配任意元素,滿足條件:B是A的下一個兄弟節點(AB有相同的父結點,並且B緊跟在A的后面)
A ~ B 滿足條件:B是A之后的兄弟節點中的任意一個(AB有相同的父節點,B在A之后,但不一定是緊挨着A)(會盡可能多匹配)
js基礎
什么是閉包
閉包是由函數與創建該函數的環境所組成的
優點:減少全局變量污染
缺點:影響腳本性能
3==true 打印出什么
會打印出false,這里會將true轉變成1
Number 和 String 或者 Bool 類型比較,會對String 或者 Bool 類型進行ToNumber()轉換
Number(true) // 1
Number(false) // 0
1==true //true
1===true //false
3==true //false
變量聲明提升
變量聲明無論出現在代碼的任何位置,都會在代碼執行前處理。所以在代碼的任何位置聲明變量就好像在代碼開頭聲明一樣。
var a = 100;
function fn() {
alert(a);
var a = 200;
alert(a);
}
fn();
alert(a);
var a;
alert(a); //這里alert出100
var a = 300;
alert(a);
not defined 與 undefined
console.log(a) //報錯 Uncaught ReferenceError: a is not defined
var b;
console.log(b) //undefined
判斷變量是不是數組的幾個方法
var a=[];
a.constructor===Array //true
a instanceof Array === true //true
⚠️ 注意:以上方法在跨frame時會有問題,跨frame實例化的對象不共享原型
var iframe = document.createElement('iframe'); //創建iframe
document.body.appendChild(iframe); //添加到body中
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // 聲明數組[1,2,3]
alert(arr instanceof Array); // false
alert(arr.constructor === Array); // false
解決:
Object.prototype.toString.call(a) // "[object Array]"
Array.isArray(a) //true
bind,call,apply用法與區別
用法:都是改變函數內this指向
bind:返回一個新的函數,調用新的函數才執行,新函數里this永久地被綁定到了bind的第一個參數上
而call與apply能直接執行
fuc.call(thisObj,a,b,c)
fuc.apply(thisObj,[a,b,c]) // apply 傳數組
原型 與 prototype屬性
- 原型:
JavaScript的對象中都包含了一個" [[Prototype]]"內部屬性,這個屬性所對應的就是該對象的原型。對象從原型繼承方法與屬性。原型可能也有原型,這種關系被稱為原型鏈。
"[[Prototype]]"作為對象的內部屬性,是不能被直接訪問的。所以為了方便查看一個對象的原型,大多數現代瀏覽器還是提供了一個名為"__proto__"這個非標准(不是所有瀏覽器都支持)的訪問器(ECMA引入了標准對象原型訪問"Object.getPrototype(object)")。
原型是由構造器函數創建的。從原型繼承的方法與屬性是在構造器函數中定義的。
- prototype屬性:
prototype屬性並不指向當前對象的原型對象(原型對象是一個內部對象,應當使用 __proto__ 訪問)。prototype屬性是繼承成員被定義的地方。
常見的對象定義模式是,在構造器(函數體)中定義屬性、在 prototype 屬性上定義方法。(在prototype屬性中定義屬性會不夠靈活)
發現的比較奇異的點:一個變量不是函數的話默認沒有 prototype屬性,是函數的話默認就有 prototype屬性,並且prototype對象中的constructor屬性就是它本身
var a = {};
console.log(a.__proto__) //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
console.log(a.__proto__ === Object.prototype) //true
console.log(a.constructor) //ƒ Object() { [native code] }
console.log(a.constructor === Object) //true
//******不是函數的話默認沒有 prototype屬性
console.log(a.prototype) //undefined
console.log('b:')
var b = function c() { };
console.log(b.__proto__) //ƒ () { [native code] }
console.log(b.__proto__ === Function.prototype) //true
console.log(b.constructor) //ƒ Function() { [native code] }
console.log(b.constructor === Function) //true
//******函數默認就有 prototype屬性,並且prototype對象中的constructor屬性就是它本身
console.log(b.prototype) //{constructor: ƒ}
console.log(b.prototype.constructor) //ƒ c() { }
console.log(b.prototype.constructor===b) //true
constructor
每個對象實例都具有 constructor 屬性,它指向創建該實例的構造器函數。
可以將此屬性作為構造器使用:
var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
獲得某個對象實例的構造器的名字,可以這么用:
person1.constructor.name
該屬性的值是那個函數本身,而不是一個包含函數名稱的字符串。對於原始值(js中有5種:null undefined number boolean string),該屬性為只讀。
var a = 1;
console.log(a.prototype) //undefined
console.log(a.constructor) //ƒ Number() { [native code] }
var b = [];
console.log(b.prototype) //undefined
console.log(b.constructor) //ƒ Array() { [native code] }
//改變 a b 的constructor為 {}
a.constructor = {}
b.constructor = {}
console.log(a.constructor) //沒有變,還是 ƒ Number() { [native code] }
console.log(b.constructor) //{}
new
class
函數堆棧
ECMAScript中變量的兩種類型
原始值:
引用值:
js三大組成部分
1.ECMAScript
2.dom
3.bom
http協議
除了 GET POST,還有哪些方法
keep-alive
http返回碼100 200 300 400分別代表什么,即響應的5種類型
100:信息響應
200:成功
300:重定向
400:客戶端錯誤
500:服務端錯誤
理解重定向
http無狀態含義
解釋三次握手,四次揮手
三次握手
1.客戶端發syn包給服務端,等待服務器確認(syn:同步序列編號(Synchronize Sequence Numbers))
2.服務端發syn+ack包給客戶端
3.客戶端發確認包ack給服務端
四次揮手
中斷連接端可以是Client端,也可以是Server端。
1.關閉主動方發送fin包
2.被動方發送ack包
3.被動方關閉連接,發送fin包
4.主動方發送ack包確認
數據結構與算法
鏈表和數組的區別
了解過哪些排序算法
js代碼實現
自己實現個jQuery,可以傳選擇器進去,然后實現css()與height()方法
var myJquery4 = function (selector) {
//console.log(this) //window
return new jqNodes(selector) //new會創造一個對象實例,對象實例繼承自構造函數的prototype,這里是jqNodes.prototype
}
var jqNodes = function (selector) {
console.log(this)
//1.以new調用時this指向即將創建的新對象
//2.直接調用則指向 window
this._items = document.querySelectorAll(selector)
return this
}
var myJqueryCore = {
//放核心方法
css: function () {
console.log(this) //myJquery4('li').css('color') 這樣調用時是作為new出來的對象原型里的方法調用的,this指向new出來的對象
var prop = arguments[0],
val = arguments[1]
if (!val) return getComputedStyle(this._items[0]).getPropertyValue(prop);
Array.prototype.map.call(this._items, function (c) {
return c.setAttribute('style', prop + ':' + val)
})
return this
}
}
jqNodes.prototype = myJqueryCore //關鍵
寫個輪播圖
之前感覺比較困擾的是從最后一頁到第一頁如何無縫滑動。無縫滑動的關鍵在於在第一頁前放上最后一頁,在最后一頁后面再放上第一頁。在最后一頁點擊后一頁時,先滑動到放置在后邊的第一頁,滑動完成后立刻改變父元素的left值到排列在第二個的第一頁。
html結構:
<div id="list" style="left: -600px;">
<div>5</div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
<div>5</div>
<div>1</div>
</div>
關鍵js:
$('#list').animate({ left: newLeft }, function () {
if (newLeft < -3000) {
list.style.left = -600 + 'px';
} else if (newLeft > -600) {
list.style.left = -3000 + 'px';
}
})
菜單高亮滾動監聽
主要參考了 http://blog.csdn.net/sinrryzh...
我修改成了可以有多個固定導航的
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
.fix-menu {
position: fixed;
right: 30px;
top: 30px;
width: 160px;
list-style-type: none;
font-size: 14px;
padding: 0;
}
.fix-menu ul {
list-style-type: none;
padding: 0;
}
._h2 a{
padding-left: 20px;
}
._h3 a{
padding-left: 40px;
}
.fix-menu a {
color: #333;
text-decoration: none;
line-height: 28px;
display: block;
width: 100%;
}
.fix-menu .active {
background: #f4f6fb;
color: green;
border-left: 4px solid green;
}
.fix-menu .active a {
color: green;
}
</style>
</head>
<body>
<div class="main" id="main1">
<div class="m-cloumn" id="c1">
<h2>欄目1內容</h2>
</div>
<div class="m-cloumn" id="c2">
<h2>欄目2內容</h2>
</div>
<div class="m-cloumn" id="c3">
<h2>欄目3內容</h2>
</div>
<div class="m-cloumn" id="c4">
<h2>欄目4內容</h2>
</div>
<div class="m-cloumn" id="c5">
<h2>欄目5內容</h2>
</div>
<div class="m-cloumn" id="c6">
<h2>欄目6內容</h2>
</div>
<div class="m-cloumn" id="c7">
<h2>欄目7內容</h2>
</div>
</div>
<div class="right-cloumn" id="menu1">
<a href="#c1" class="curr">欄目1</a>
<a href="#c2">欄目2</a>
<a href="#c3">欄目3</a>
<a href="#c4">欄目4</a>
<a href="#c5">欄目5</a>
<a href="#c6">欄目6</a>
<a href="#c7">欄目7</a>
</div>
<div class="main" id="main2">
<div class="m-cloumn" id="c2-1">
<h2>欄目2-1內容</h2>
</div>
<div class="m-cloumn" id="c2-2">
<h2>欄目2-2內容</h2>
</div>
<div class="m-cloumn" id="c2-3">
<h2>欄目2-3內容</h2>
</div>
<div class="m-cloumn" id="c2-4">
<h2>欄目2-4內容</h2>
</div>
<div class="m-cloumn" id="c2-5">
<h2>欄目2-5內容</h2>
</div>
<div class="m-cloumn" id="c2-6">
<h2>欄目2-6內容</h2>
</div>
<div class="m-cloumn" id="c2-7">
<h2>欄目2-7內容</h2>
</div>
</div>
<div class="right-cloumn" id="menu2">
<a href="#c2-1">欄目2-1</a>
<a href="#c2-2">欄目2-2</a>
<a href="#c2-3">欄目2-3</a>
<a href="#c2-4">欄目2-4</a>
<a href="#c2-5">欄目2-5</a>
<a href="#c2-6">欄目2-6</a>
<a href="#c2-7">欄目2-7</a>
</div>
<script src="../jquery.min.js" type="text/javascript"></script>
<script>
(function ($, win, doc) {
var scroll_highlight = function (obj) {
return new scroll_rsilder(obj)
}
var scroll_rsilder = function (obj) {
this.init(obj)
}
scroll_rsilder.prototype = {
win_evet: function () {
var _this = this._this
$(win).on("scroll", function () {
var scrollTop = $(this).scrollTop();
_this.ele_evet(scrollTop);
})
},
ele_evet: function (scrollTop) {
var _this = this._this
$(this.cloumn).each(function (index) {
var offsetTop = $(this).offset().top;
var xd = parseInt(offsetTop - scrollTop);
//console.log(index, offsetTop, scrollTop, xd, _this)
if (xd < _this.spacing) {
$(_this.silder).eq(index).addClass(_this.curr).siblings().removeClass();
}
})
},
init: function (obj) {
this._this = this,
this.cloumn = obj.cloumn,
this.silder = obj.silder,
this.spacing = obj.spacing || 100,
this.curr = obj.curr || "curr";
if (!this.cloumn) return;
this.win_evet();
}
}
win.scroll_highlight = scroll_highlight;
})(jQuery, window, document)
</script>
<script>
$(function () {
scroll_highlight({
cloumn: "#main1 .m-cloumn",
silder: "#menu1 a",
spacing: 80,
curr: "curr"
})
scroll_highlight({
cloumn: "#main2 .m-cloumn",
silder: "#menu2 a",
spacing: 80,
curr: "curr"
})
})
</script>
</body>
</html>
網上看的面試題&自己發現的面試知識點
注:自己發現的面試知識點一般是在工作學習中發現的基礎重要但之前被自己忽略的知識點。
js基礎
全等號優先級大於邏輯與
var a=1===2&&3?4:5
逗號操作符
逗號操作符 對它的每個操作數求值(從左到右),並返回最后一個操作數的值。
var x=(0,1) //x=1
比較對象
兩個獨立聲明的對象永遠也不會相等,即使他們有相同的屬性,只有在比較一個對象和這個對象的引用時,才會返回true.
encodeURI encodeURIComponent
- encodeURI
encodeURI 會替換所有的字符,但不包括以下字符,即使它們具有適當的UTF-8轉義序列:
類型 包含
保留字符 ; , / ? : @ & = + $
非轉義的字符 字母 數字 - _ . ! ~ * ' ( )
數字符號 #
encodeURI自身無法產生能適用於HTTP GET 或 POST 請求的URI,例如對於 XMLHTTPRequests, 因為 "&", "+", 和 "=" 不會被編碼,然而在 GET 和 POST 請求中它們是特殊字符。然而encodeURIComponent這個方法會對這些字符編碼。
- encodeURIComponent
轉義除了字母、數字、(、)、.、!、~、*、'、-和_之外的所有字符。
dangerouslysethtml會過濾掉__html屬性里的 ,是因為用了encodeURI函數來避免xss攻擊
encodeURI('/\/\//') -->”////“
encodeURI('\') --> Uncaught SyntaxError: Invalid or unexpected token
encodeURIComponent('/\/\//') -->"%2F%2F%2F%2F"
encodeURIComponent('/') --> "%2F"
encodeURIComponent('\') --> Uncaught SyntaxError: Invalid or unexpected token
http協議
xss
cross-site scripting,跨站腳本,屬於代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了html以及用戶端腳本語言。
攻擊實例:用戶A提交表單事加入類似以下代碼,如果提交表單時沒有做檢測,而之后的結果頁面是其他用戶也能看到的,那么其他頁面看到的結果頁就會受到影響。
<script>
document.write('...')
</script>
解決辦法:不信賴用戶輸入,對特殊字符如”<”,”>”轉義。
uri url urn
uri:統一資源標識符
url:統一資源定位符
urn:統一資源名稱
url與urn是uri的子集。
讓uri能成為url的是那個“訪問機制”,“網絡位置”。e.g. http:// or ftp://.。
urn是唯一標識的一部分,就是一個特殊的名字。
etag是什么
ETag(entity tag)唯一地表示一份資源的實體標簽。
標簽是由 ASCII 字符組成的字符串,用雙引號括起來(如 "675af34563dc-tr34")。前面可以加上 W/ 前綴表示應該采用弱比較算法。
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
ETag: W/"0815"
ETag由Web服務器根據URL上的資源的特定版本而指定。如果那個URL上的資源內容改變,一個新的不一樣的ETag就會被分配。ETag的比較只對同一個URL有意義——不同URL上的資源的ETag值可能相同也可能不同,從他們的ETag的比較中無從推斷。
用法:
1.檢測"空中碰撞"(資源同步更新而相互覆蓋):
在ETag和 If-Match 頭部的幫助下,可以檢測到"空中碰撞"的編輯沖突。
2.緩存未更改的資源
如果用戶再次訪問給定的URL(設有ETag字段),顯示資源過期了且不可用,客戶端就發送值為ETag的If-None-Match header字段:
If-None-Match: "33a64df551425fcc55e4d42a148795d9f25f89d4"
服務器將客戶端的ETag(作為If-None-Match字段的值一起發送)與其當前版本的資源的ETag進行比較,如果兩個值匹配(即資源未更改),服務器將返回不帶任何內容的304未修改狀態,告訴客戶端緩存版本可用(新鮮)。
If-Match 頭部
請求首部 If-Match 的使用表示這是一個條件請求。在請求方法為 GET 和 HEAD 的情況下,服務器僅在請求的資源滿足此首部列出的 ETag 之一時才會返回資源。而對於 PUT 或其他非安全方法來說,只有在滿足條件的情況下才可以將資源上傳。
應用:
- GET 和 HEAD 方法,搭配 Range首部使用,可以用來保證新請求的范圍與之前請求的范圍是對同一份資源的請求。如果 ETag 無法匹配,那么需要返回 416 (Range Not Satisfiable,范圍請求無法滿足) 響應。
2.對於其他方法來說,尤其是 PUT, If-Match 首部可以用來檢測用戶想要上傳的不會覆蓋獲取原始資源之后做出的更新。如果請求的條件不滿足,那么需要返回 412 (Precondition Failed,先決條件失敗) 響應。
語法:
If-Match: <etag_value>, <etag_value>, …
樂觀並發控制
ASCII字符串
ASCII (發音: /ˈæski/ ,American Standard Code for Information Interchange,美國信息交換標准碼) 是計算機中最常用的編碼方式,用於將字母,數字,標點符號和控制字符轉換為計算機可以理解的數字形式。
ASCII的局限在於只能顯示26個基本拉丁字母、阿拉伯數目字和英式標點符號,因此只能用於顯示現代美國英語(而且在處理英語當中的外來詞如naïve、café、élite等等時,所有重音符號都不得不去掉,即使這樣做會違反拼寫規則)。而ASCII雖然解決了部分西歐語言的顯示問題,但對更多其他語言依然無能為力。因此現在的軟件系統大多采用Unicode。
ASCII主要用於顯示現代英語和其他西歐語言。從2007年開始逐漸被UTF-8 代替。
Unicode
Unicode(中文:萬國碼、國際碼、統一碼、單一碼)是計算機科學領域里的一項業界標准。它對世界上大部分的文字系統進行了整理、編碼,使得電腦可以用更為簡單的方式來呈現和處理文字。
UTF-8
UTF-8(8-bit Unicode Transformation Format)是一種針對Unicode的可變長度字符編碼,也是一種前綴碼。它可以用來表示Unicode標准中的任何字符,且其編碼中的第一個字節仍與ASCII兼容,這使得原來處理ASCII字符的軟件無須或只須做少部分修改,即可繼續使用。因此,它逐漸成為電子郵件、網頁及其他存儲或發送文字的應用中,優先采用的編碼。
Range首部
Range 是一個請求首部,告知服務器返回文件的哪一部分。在一個 Range 首部中,可以一次性請求多個部分,服務器會以 multipart 文件的形式將其返回。如果服務器返回的是范圍響應,需要使用 206 Partial Content 狀態碼。假如所請求的范圍不合法,那么服務器會返回 416 Range Not Satisfiable 狀態碼,表示客戶端錯誤。服務器允許忽略 Range 首部,從而返回整個文件,狀態碼用 200 。
語法:
Range: <unit>=<range-start>-
Range: <unit>=<range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>
Range: bytes=200-1000, 2000-6576, 19000-
一級域名,二級域名
以www.baidu.com為例子
最右邊一個點右邊的為頂級域名(一級域名)com
一級域名左邊是二級域名 baidu
主域,子域
子域名域名系統等級中,屬於更高一層域的域。比如,mail.example.com
和calendar.example.com是example.com的兩個子域,而example.com
則是頂級域.com的子域
非技術問題
為什么換工作
不要說是因為錢少。上一家的薪資不要做假,因為公司可能會查。期望薪資可以要高點,說明。
<script src="../jquery.min.js"></script>
<script src="../scroll-highlight.js"></script>
<script src="../fix-menu.js"></script>
