1. 程式人生 > >前端面試題(每天10個)

前端面試題(每天10個)

說不定哪天就要重新找工作了,作為知識的儲備和鞏固學習,每天記一點東西總歸是好的。(儘可能的每天更新一點)

目錄

HTML

Doctype 有什麼用?

HTML 中用來區分標準模式和怪異模式的宣告,用來告知瀏覽器使用標準模式渲染頁面。

什麼是 data- 屬性?

在 JavaScript 框架流行之前,前端開發者經常使用 data- 屬性,把額外的資料儲存在 DOM 自身中。當時沒有其他的 Hack 手段(比如使用非標準屬性或 DOM 上額外屬性)。這樣做是為了將自定義資料儲存到頁面或應用中,對此沒有其他更適當的屬性或元素。
而現在,不鼓勵使用 data-

屬性。原因之一資料模型可以儲存在 JavaScript 本身中,並利用框架提供的資料繫結,使之與 DOM 保持更新。

請描述 script、 script async 和 script defer 的區別
  • <script>:瀏覽器會立即載入並執行相應的指令碼。也就是說在渲染script標籤之後的文件之前,不等待後續載入的文件元素,讀到就開始載入和執行,此舉會阻塞後續文件的載入。
  • <script async>:表示後續文件的載入和渲染與js指令碼的載入和執行是並行進行的,即非同步執行。
  • <script defer>:載入後續文件的過程和js指令碼的載入(此時僅載入不執行)是並行進行的(非同步),js指令碼的執行需要等到文件所有元素解析完成之後,DOMContentLoaded事件觸發執行之前。如果存在多個有defer屬性的指令碼,那麼它們是按照載入順序執行指令碼的。
什麼是漸進式渲染(progressive rendering)?

漸進式渲染適用於提高網頁效能,以儘快呈現頁面的額技術。例如:

  • 圖片懶載入—頁面上圖片不會一次性全部載入,當用戶滾動頁面到影象部分時,JavaScript 將載入冰心啊是影象。
  • 分層次渲染(確認顯示內容的優先順序)—為了儘快將頁面呈現給使用者,頁面只包含基本的最少量的 css、指令碼和內容,可以使用延遲載入指令碼或者監聽 DOMContentLoaded/load 事件載入其他資源和內容。
  • 非同步載入 HTML 片段—當頁面通過後臺渲染時,把 HTML 拆分,通過非同步請求,分塊傳送給瀏覽器。
HTML5 的新特性,語義化

HTML5 中誕生了一些特殊的標籤,見名知意,使頁面更清晰,方便維護和開發。

  1. <section></section>:定義文件中的主體部分的節、段。
  2. <article></article>:定義來自外部的一個獨立的、完整的內容塊,例如什麼論壇的文章,部落格的文字。
  3. <aside></aside>:用來裝載頁面中非正文的內容,獨立於其他模組。例如廣告、成組的連結、側邊欄。
  4. <header></header>:定義文件、頁面的頁首。
  5. <footer></footer>:定義了文件、頁面的頁尾。
  6. <nav></nav>:定義了一個連結組組成的導航部分。
  7. <hgroup></hgroup>:用於對網頁或區段(section)的標題元素(h1~h6)進行組合。
  8. <figure></figure>:用於對元素進行組合。
  9. <canvas></canvas>:用來進行canvas繪圖。
  10. <video></video>:定義視訊。
  11. <audio></audio>:定義音訊。
meta 標籤

<meta> 標籤提供關於 HTML 文件的元資料。可用於瀏覽器(如何顯示內容或重新載入頁面),搜尋引擎(關鍵詞),或其他 web 服務。
<meta> 標籤的屬性有四個:namehttp-equivcontentcharset

CSS

盒模型,box-sizing
  • 盒模型:當設定元素的大小時,width 和 height 屬性確定元素的內容框的寬度和高度。新增到元素上任意的 padding 都將增加元素的總計算寬度和(或)高度 —— 這是預設的盒模型在調整元素大小時的工作原理。
  • box-sizing:使用 box-sizing 屬性,你可以告訴瀏覽器在元素的寬度中包括 padding 的寬度和(或) border 寬度,而不是增加該寬度。
偽類,偽元素
  • 偽類:用於向某些選擇器新增特殊的效果
  • 偽元素:用於向某些選擇器設定特殊效果

偽類

屬性 描述 css版本
:active 向被啟用的元素新增樣式 1
:focus 向擁有鍵盤輸入焦點的元素新增樣式 2
:hover 當滑鼠懸浮在元素上方時,想元素新增樣式 1
:link 向未被訪問的連結新增樣式 1
:visited 向已被訪問的連結新增樣式 1
:first-child 向元素的第一個子元素 2
:lang 向帶有指定 lang 屬性的元素新增樣式 2

提示:在 CSS 定義中,a:hover 必須被置於 a:link 和 a:visited 之後,才是有效的。
提示:在 CSS 定義中,a:active 必須被置於 a:hover 之後,才是有效的。
提示:偽類名稱對大小寫不敏感。

偽元素

屬性 描述 css版本
:first-letter 向文字的第一個字母新增特殊樣式 1
:first-line 想文字首行新增特殊樣式 1
:before 在元素之前新增內容 2
:after 在元素之後新增內容 2
CSS實現隱藏頁面的方式

你可以將 opacity 設為 0、將 visibility 設為 hidden、將 display 設為 none 或者將 position 設為 absolute 然後將位置設到不可見區域。

css屬性是否區分大小寫?

不區分。HTML 、CSS 都對大小寫不敏感,但為了更好的可讀性和團隊協作一般都小寫,而在 XHTML 中元素名稱和屬性必須小寫

行內(inline)元素,設定 margin-top 和 margin-bottom 是否起作用?

答案是起作用,個人覺得不對。
討論這個問題,應該對行內替換元素和行內非替換元素分別討論。對於行內非替換元素,是不起作用的,原因在於行內非替換元素的外邊距不會改變一個元素的行高,但是對其左右邊距則不是這樣的,是有影響的。而對於替換元素則是都有影響的。

對內聯元素設定 padding-top 和 padding-bottom 是否會增加它的高度?

答案是不會

設定 p 的 font-size:10rem,當用戶重置或拖曳瀏覽器視窗時,文字大小是否會隨著變化?

不會。 rem 是以 html 根元素中的 font-size 的大小為基準的相對度量單位,文字大小不會對視窗大小改變而變化。

偽類選擇器:checked 將作用在與 input 型別為 radio 或者 checkbox ,不會作用於 option

不對。

在 HTML 文字中,偽類:root 總是指向html元素?

不是。單建立的根。這個可能不是html。

translate()方法能移動一個元素在 z 軸上的位置?

不能,該方法只能改變 x 軸,y 軸上的位移。

only選擇器的作用是?

停止舊版本瀏覽器解析選擇器的其餘部分。

overflow:hidden 是否形成新的塊級格式化上下文?

會觸發 BFC 的條件有:

  • float 值不為 none。
  • overflow 的值不為 visible。
  • display 的值為 table-cell、table-caption、inline-block 中的任何一個。
  • positon 的值不為 relative 和 static。
screen 關鍵詞是指裝置物理螢幕的大小還是指瀏覽器的視窗?

瀏覽器視窗。

浮動元素引起的問題和解決辦法?
  1. 在浮動元素的最後加一個兄弟元素設定css樣式:{ clear:both }
  2. 使用父元素的偽類元素 ::after,設定樣式:{ clear:both }

JavaScript

window.onload和document.ready的區別
window.onload是在頁面中包含圖片在內的素有元素全部載入完成;
document.ready是文件結構載入完成,但不包含圖片,其他媒體檔案;
在jQuery中會看到$(function(){})和$(document).ready(function(){}),是在DOM樹載入完成之後執行;
window.onload是在DOM樹載入完以及所有檔案載入完成才執行,因此慢於document.ready。
陣列去重
var arr = ['a','bb','22','a','yuci','haha','22']; 

# es6的set()方法

var unique = new Set(arr);  
console.log(Array.from(unique)); 

#使用push()

var arr2 = [];  
for(var i = 0; i < arr.length; i++) {  
    (function(i) {  
        if(arr2.indexOf(arr[i]) == -1) { //不包含某個值則返回-1  
            arr2.push(arr[i]);  
        }  
    }(i))  
}  
console.log(arr2); 
//如果當前陣列的第i項在當前陣列中第一次出現的位置不是i,那麼表示第i項是重複的,忽略掉。否則存入結果陣列  
var arr3 = [arr[0]];  
for(var i = 1; i < arr.length; i++) {  
    (function(i) {  
        if(arr.indexOf(arr[i]) == i) {  
            arr3.push(arr[i]);  
        }  
    }(i))  
}  
console.log(arr3);  

#排序去除相鄰重複元素

var arrSort = arr.sort();  
var arr4 = [];  
for(let i = 0; i< arrSort.length; i++) {  
    if(arrSort[i] != arrSort[i+1]) {  
        arr4.push(arrSort[i]);  
    }  
}  
console.log(arr4);  

#使用splice()

var len = arr.length;  
for(let i = 0; i < len; i++) {  
    for(let j = i + 1; j < len; j++) {  
        if(arr[i] === arr[j]) {  
            arr.splice(i,1);  
            len--;  
            j--;  
        }  
    }  
}  
console.log(arr); 
事件委託

得益於事件冒泡,當多個元素有相同的事件,將事件繫結在父元素

var oUl = document.getElementById('oul');  
oUl.addEventListener('click', function(e) {  
    var e = e||window.event;  
    var tar = e.target;  
    if(tar.nodeName === 'LI') {  
        alert(tar.innerHTML);  
    }  
}) 
判斷變數型別

typeof()用於判斷簡單資料;

判斷一個變數是物件還是陣列使用instanceof,constructor或Object.prototype.toString.call();
同步和非同步

同步:由於js單執行緒,同步任務都在主執行緒上排隊執行,前面任務沒執行完成,後面的任務會一直等待;
非同步:不進入主執行緒,進入任務佇列,等待主執行緒任務執行完成,開始執行。最基礎的非同步操作setTimeout和setInterval,等待主執行緒任務執行完,在開始執行裡面的函式;

返回false的幾種情況

false,null,0,“”,undefined,NaN

js型別值的區別
**儲存地**:

簡單資料型別:儲存在棧中;

引用資料型別:儲存在堆中,在棧中儲存了指標,指向儲存在堆中的地址,直譯器會先檢索在棧中的地址,從堆中獲得實體;

**大小**:

簡單資料型別:大小固定,佔用空間小,頻繁使用,所以儲存在棧中;

引用資料型別:大小不固定,佔用空間大;
閉包

何為閉包:有權訪問另一個作用域中變數的函式
閉包特性:可實現函式外訪問函式內變數,外層變數可以不被垃圾回收機制回收

為什麼?怎麼解決?

for(var i = 0; i < 10; i++) {  
    setTimeout(function() {  
        console.log(i);    
    }, 1000);  
}
// 使用閉包,自執行匿名函式包裹:
for(var i = 0; i < 10; i++) {  
    (function(j) {  
        setTimeout(function() {  
            console.log(j);    
        }, 1000);  
    })(i);  
} 
this的指向
全域性範圍:指向window(嚴格模式下不存在全域性變數,指向undefined);

普通函式呼叫:指向window;

物件方法呼叫:指向最後呼叫它的物件;

建構函式呼叫:指向new出來的物件;

顯示設定this:call,apply方法顯示將this指向第一個引數指明的物件
new具體做了些什麼
建立一個新物件foo;

並將它的__proto__指向其建構函式的prototype,foo.__proto__ = Foo.prototype;

動態將this指向新物件,Foo.apply(foo,arguments);

執行函式體中的程式碼;

放回新物件foo;
原型和原型鏈

建立一個函式就會為其建立一個prototype屬性,指向這個函式的原型物件,原型物件會自動獲得constructor屬性,指向prototype屬性所在函式。

Function.prototype.a = "a";    
Object.prototype.b = "b";    
function Person(){}    
console.log(Person);    //function Person()    
let p = new Person();    
console.log(p);         //Person {} 物件    
console.log(p.a);       //undefined    
console.log(p.b);       //b 

p.__proto__ === Person.prototype;Person.prototype.constructor === Person

當呼叫某種方法或查詢某種屬性時,首先會在自身呼叫和查詢,如果自身並沒有該屬性或方法,則會去它的proto屬性中呼叫查詢,也就是它建構函式的prototype中呼叫查詢,如果建構函式中也沒有該屬性方法,則會去建構函式的隱式原型中查詢,一直到null,就這樣形成原型鏈。

陣列常用方法
  • 尾部刪除pop()
  • 尾部新增push()
  • 頭部刪除shift()
  • 頭部新增unshift()
  • 排序sort()
  • 顛倒陣列元素reverse()
  • 刪除或插入元素splice()
資料儲存
方法名稱 屬性 大小 失效時間
Cookie 用於客戶端與服務端通訊,也具有本地儲存的功能 4K 在瀏覽器關閉時刪除,除非主動設定刪除時間
localStorage 專門用於儲存 5M 一直都在直到使用者主動刪除或清除瀏覽器快取
sessionStorage 專門用於儲存 5M 瀏覽器關閉時刪除
繼承方式

原型鏈繼承:
Child()的原型作為Parent()的例項來繼承Parent()的方法屬性
因為所有例項都繼承原型方法屬性,其中一個例項對原型屬性值更改後,所有例項呼叫該屬性的值全部更改

function Parent() {}  
Parent.prototype.parentSay = function() {  
    return 'i am parent';  
}  
function Child() {}  
Child.prototype.childSay = function() {  
    return 'i am child';  
}  
Child.prototype = new Parent();  
var par = new Parent();  
var kid = new Child();  

console.log(kid.parentSay());           //i am parent 

建構函式繼承:
在子類的建構函式內部通過callapply來呼叫父類建構函式
無法實現函式的複用

function People() {  
    this.name = ['zhangsan','lisi','wangwu'];  
}  
function Person() {  
    People.call(this);  
}  
var per1 = new Person();  
per1.name.push('zhanliu');  
console.log(per1.name);     //["zhangsan", "lisi", "wangwu", "zhanliu"]  

var per2 = new Person();  
console.log(per2.name);     //["zhangsan", "lisi", "wangwu"]  

組合繼承:
將原型鏈繼承和建構函式繼承結合,最常用的繼承模式
原型鏈繼承共享的屬性和方法,建構函式繼承例項屬性

function People(num) {  
    this.num = num;  
    this.name = ['zhangsan','lisi','wangwu'];  
}  
People.prototype.numCount = function() {  
    console.log(this.num);  
}  
function Person(num) {  
    People.call(this, num);  
}  
//繼承方式  
Person.prototype = new People();  
Person.prototype.constructor = Person;  

var per1 = new Person(10);  
per1.name.push('zhaoliu');  
console.log(per1.name);     //["zhangsan", "lisi", "wangwu", "zhanliu"]  
per1.numCount();            //10  

var per2 = new Person(20);  
console.log(per2.name);     //["zhangsan", "lisi", "wangwu"]  
per2.numCount();            //20