30秒系列之面試

容易

圖片標籤 imgalt 屬性有什麼用?

當圖片加載失敗沒法看到時,頁面會顯示alt 屬性提供的信息。alt 屬性是用於描述圖片信息的,那些裝飾性的圖片除外,這些圖片的 alt 信息應該置空。css

善意:html

  • 修飾性的圖片的alt應該爲 ''
  • Web crawlers網絡爬蟲使用 alt 標籤識別圖片內容,所以這些屬性對 Search Engine Optimization (SEO) 搜索引擎優化很重要
  • alt 標籤後加. 提升可訪問性

CSS BEM 是什麼?

BEM 方法是CSS類名的命名約定,目的是經過定義命名空間,使 CSS 更易於維護,解決類(class)的範圍問題 。BEMBlock Element Modifier —— 塊元素修飾符Block 是一個獨立的部分,它能夠在項目裏重複利用併爲子元素(Element)充當命名空間。當一個塊或元素在某個狀態或者結構樣式不一樣時,Modifier能夠用做標識符區別這些狀態或差別。數據庫

/* block component */
.block {
}

/* element */
.block__element {
}

/* modifier */
.block__element--modifier {
}

這是一個類名標記的例子:編程

<nav class="navbar">
  <a href="/" class="navbar__link navbar__link--active"></a>
  <a href="/" class="navbar__link"></a>
  <a href="/" class="navbar__link"></a>
</nav>

在上例中,navbarBlocknavbar__link 元素 除了是 navbar 組件外沒任何意義, navbar__link--active 是一個修飾符, 表示 navbar————link 元素的一種不一樣的狀態。數組

因爲修飾符過於冗長,更多狀況下是使用 is-* 標識promise

<a href="/" class="navbar__link is-active"></a>

這些必須與元素連接不能獨立使用,不然就會有範圍問題。瀏覽器

.navbar__link.is-active {
}

善意:緩存

  • 另外一個解決範圍問題的方案是 CSS-in-JS
範圍問題: CSS只有一個全局命名空間。 在非平凡的應用程序中不可能避免選擇器衝突。

cache busting 的用途以及如何實現

cache busting ——我暫時不知道如何翻譯,大體就是解決緩存文件不刷新問題服務器

瀏覽器有一個緩存機制來臨時存儲網站上的文件,因此在頁面之間切換或從新加載相同的頁面時,這些文件不須要被從新下載。服務器被設置爲發送報頭,報頭告訴瀏覽器在給定的時間內存儲文件。這大大提升了網站的速度,並保持了帶寬。網絡

可是,當開發人員更改了網站,由於用戶的緩存仍然引用舊文件,這可能會致使問題。若是緩存的CSS和JavaScript文件引用的元素已不復存在、已移動或已重命名,則會使它們保留原有功能,或破壞網站。

cache busting是一種強制瀏覽器下載新文件的方式,經過將文件命名爲與舊文件不一樣的名稱來實現。

有一種強制瀏覽器從新下載文件的常見的方式是在文件名稱末尾添加一個索引字符串

src="js/script.js" => src="js/script.js?v=2"

這種方式瀏覽器會將它視做不一樣的文件,而且不用重命名文件。

CSS 預處理器的好處是什麼?

CSS預處理程序添加了本地CSS沒有的有用功能,一般經過啓用DRY(不要重複)原則使CSS更整潔、更易於維護。它們用於嵌套選擇器的簡潔語法減小了重複代碼。它們爲一致的主題化提供了變量(然而,CSS變量已經在很大程度上取代了這個功能),並提供了額外的工具,如color函數(變亮、變暗、透明等)、mixin和循環,這些工具使CSS更像一種真正的編程語言,並使開發人員有更多的能力生成複雜的CSS。

善意:

  • 容許咱們書寫更易於維護和擴展的css代碼
  • 一些使用CSS預處理器的缺點: 安裝,從新編譯耗時等

===== 的區別

(===)檢查嚴格的相等性,這意味着類型和值必須相同。另外一方面,(==)首先執行類型強制轉換,使兩個操做數具備相同的類型,而後應用嚴格的比較。

善意:

  • 只要可能,使用===來測試等式,由於鬆散等式==可能會獲得不直觀的結果。
  • 類型強制轉換表示將值轉換爲相同的類型。
  • 假值以及這些值的比較。

使用彈性盒子模型建立一個三列布局,每一列佔據容器col-{n} / 12的比例

<div class="row">
  <div class="col-2"></div>
  <div class="col-7"></div>
  <div class="col-3"></div>
</div>

設置 .row的父元素display: flex;使用flex的 簡寫屬性 給列類設置一個 與它的比例對應的 flex-grow

.row {
  display: flex;
}

.col-2 {
  flex: 2;
}

.col-7 {
  flex: 7;
}

.col-3 {
  flex: 3;
}

網頁能包含多個 <header>元素麼? <footer>呢?

二者均可以。W3文檔聲明標記表示其最近祖先「部分」的頁眉(<header>)和頁腳(<footer>)區域。所以,不只頁面<body>能夠包含頁眉和頁腳,並且每一個<article><section>元素也能夠包含頁眉和頁腳。

善意:

  • W3建議你想要多少就有多少,可是對於你頁面的每個「部分」,好比正文、部分等,每一個部分只能有一個。

簡要描述如下HTML5語義元素的正確用法:<header><article><section><footer>

  • <header>用於包含關於頁面某個部分的介紹和導航信息。這能夠包括章節標題、做者姓名、出版時間和日期、目錄或其餘導航信息。
  • <article>是一個自包含的組合,邏輯上能夠在頁面以外獨立地從新建立,而不會失去它的意義。我的博客文章或新聞故事就是很好的例子。
  • <section>是一個靈活的容器,用於保存具備相同信息主題或目的的內容。
  • <footer>用於保存應該出如今內容部分末尾的信息,幷包含關於該部分的附加信息。做者姓名、版權信息和相關連接就是此類內容的典型例子。

善意:

  • 其餘語義元素是<form><table>

你能說出 @media 屬性的四種類型嗎?

  • all 適用於全部媒體類型的設備
  • print 它只適用於打印機
  • screen 僅適用於屏幕(臺式機、平板電腦、手機等)
  • speech 這隻適用於屏幕閱讀器

中級

值比較(下列代碼輸出?)

const a = [1, 2, 3]
const b = [1, 2, 3]
const c = "1,2,3"

console.log(a == c)
console.log(a == b)

第一個console.log輸出true,由於JavaScript的編譯器執行類型轉換,所以它根據字符串的值與字符串進行比較。另外一方面,第二個console.log輸出false,由於數組是對象,對象經過引用進行比較(比較的是內存地址)。

善意之言:

  • JavaScript執行自動類型轉換
  • 經過引用來比較對象
  • 按值比較基本類型(null, undefined, number, string, boolean)數據的值

rel="noopener"的使用情景和使用目的

rel="noopener"<a>元素(超連接)中使用的一個屬性。它防止頁面擁有window.opener屬性,這個屬性指向原來的的頁面,並容許從超連接打開的頁面操做超連接所在的頁面,即新打開的頁面控制原來跳轉頁。務必在target='_blank'後加上此屬性,兼容火狐寫法rel="noopener norefferrer"

善意之言

  • rel=「noopener」應用於超連接。
  • rel="noopener"防止打開的連接操做源頁面。

JavaScript 的自動分號插入(ASI)

下列代碼輸出什麼?

function greet() {
  return
  {
    message: "hello"
  }
}
undefined

因爲 JavaScript的自動分號插入機制 automatic semicolon insertion (ASI), 編譯器在return關鍵字後放置分號,所以它返回undefined,不會拋出錯誤。

善意之言:

  • 自動分號插入機制會致使一些耗時難纏的bug

nullundefined之間的區別是什麼?

JavaScript中,兩個值分別表示——undefinednull。它們之間的具體區別是null是顯式的,而undefined是隱式的。當屬性不存在或變量沒有被賦予值時,該值是undefined。設置值null是顯式地指示「no value」。在本質上,undefined用於未知的狀況,null用於已知的狀況。也就是說,變量只聲明不知道它指代什麼時,也就是說它是未知的,是undefined,若變量已知,但在一些時候是沒有內容的,則用null賦值

善意之言:

  • typeof undefined的值爲「undefined」
  • typeof null計算「object」。然而,它仍然是一個原始值,這在JavaScript中被認爲是一個實現錯誤。
  • undefined == null的值爲true。

MIME類型是什麼?它的用途是什麼?

MIMEMulti-purpose Internet Mail Extensions的縮寫。它是用做在Internet上對文件類型進行分類的標準方法。

善意之言:

  • MIME type實際上有兩個部分:一個類型和一個用斜槓(/)分隔的子類型。例如,Microsoft Word文件的MIME類型是application/msword(類型爲application,子類型爲msword)。

typeof 的運算結果

求下列代碼的值

typeof typeof 0

輸出: "string"

先獲得 0的類型"number", 而後 typeof "number" 得出 "string"

typeof 操做符返回一個 字符串表示未鑑定的操做數的類型

JavaScript 的數據類型

最新的 ECMAScript 標準定義了種數據類型,六種基本/原始數據類型:Boolean, Null, Undefined, Number, String, Symbol ,以及一種非原始數據類型: Object.

對以上數據類型使用 typeof(結果都是小寫): boolean, object, undefined, number, string, symbol, object

善意之言

  • 新補充的基本數據類型 Symbol
  • Array, Date and Function 都是 object 對象類型(typeof 函數的出來function)
  • JavaScript中的函數是能被調用的對象
判斷類型:
object instanceof constructor
instanceof 運算符用來檢測 constructor.prototype 是否存在於參數 object 的原型鏈上。

參數parameterarguments 的區別

參數Parameter 是函數定義時形參的變量名,而arguments 是函數調用時給定的值

function myFunction(parameter1, parameter2) {
  console.log(arguments[0]) // "argument1"
}
myFunction("argument1", "argument2")

友情提示

  • arguments 是一個類數組對象,包含了函數觸發調用時獲得的參數信息
  • myFunction.length 只表示函數的參數數量(本例中爲2),不管函數調用時傳入多少參數

示例以下

function myFunction(parameter1, parameter2) {
   console.log(myFunction.length) //2
   console.log(arguments[2]) // "3"  這裏雖然函數只接受兩個參數,但調用時傳了多的兩個`3,4`在arguments中也取到了
}
console.log(myFunction.length) // 2
myFunction("argument1", "argument2", 3, 4)

建立一個函數,使用指定符號maskCahr屏蔽除最後count爲以外的字符

mask("123456789") // "#####6789"

有不少方法解決:

使用 String.prototype.slice() 傳入參數-4 獲取字符串最後 4 位字符 ,而後用 String.prototype.padStart() 傳入字符串長度和 替換符號 把字符串用 指定符號填充至 指定長度.

const mask = (str, maskChar = "#") =>
  str.slice(-4).padStart(str.length, maskChar)

善意之言

  • 若是問題的解決方案是有效的,那麼應該首選簡短、單行的功能性解決方案

困難

遞歸recursion 是什麼 ? 何時用?

遞歸是一個過程的重複應用。在JavaScript中,遞歸涉及不斷調用自身的函數,直到它們達到一個基本條件。基本條件打破遞歸循環,不然函數將無限遞歸循環下去。當處理嵌套若干層的數據時遞歸很是有用。

例如,有一個數據庫返回的一系列評論,它存在於一個平面數組中,可是須要嵌套以在UI中顯示。每一個註釋要麼是頂級註釋(沒有父註釋),要麼是對父註釋的回覆。評論能夠是回覆的回覆,回覆的回覆…咱們事先不知道一個評論可能有多少層深度。這就是遞歸能夠提供幫助的地方。

const nest = (items, id = null, link = "parent_id") =>
  items
    .filter(item => item[link] === id)
    .map(item => ({ ...item, children: nest(items, item.id) }))

const comments = [
  { id: 1, parent_id: null, text: "First reply to post." },
  { id: 2, parent_id: 1, text: "First reply to comment #1." },
  { id: 3, parent_id: 1, text: "Second reply to comment #1." },
  { id: 4, parent_id: 3, text: "First reply to comment #3." },
  { id: 5, parent_id: 4, text: "First reply to comment #4." },
  { id: 6, parent_id: null, text: "Second reply to post." }
]

nest(comments)
/*
[
  { id: 1, parent_id: null, text: "First reply to post.", children: [...] },
  { id: 6, parent_id: null, text: "Second reply to post.", children: [] }
]
*/

在上例中,基礎條件是filter()返回空數組。鏈式的map() 不會觸發遞歸調用的回調函數,進而跳出遞歸循環。

善意提醒:

  • 遞歸在處理包含未知層數的結構的數據時很是有用
  • 遞歸必須有一個跳出遞歸循環避免無限回調的基本條件

JavaScript中惟一不等於自身的值是什麼?

當與任何比較運算符比較時,NaN (not -a- number) 是惟一不等於自身的值。NaN一般是沒有意義的數學計算的結果,因此兩個NaN值被認爲相等沒有意義。

善意提醒

  • isNaN()Number.isNaN()的區別

    //isNaN
                console.log(isNaN(null));            //false
                console.log(isNaN(true));            //false
                console.log(isNaN(false));           //false
                console.log(isNaN(0));               //false
                console.log(isNaN(undefined));       //true
                console.log(isNaN("AB"));            //true
                console.log(isNaN({a: 1}));          //true
                console.log(isNaN(NaN));             //true
                
                //Number.isNaN
                console.log(Number.isNaN(null));      //false
                console.log(Number.isNaN(true));      //false
                console.log(Number.isNaN(false));     //false
                console.log(Number.isNaN(0));         //false
                console.log(Number.isNaN(undefined)); //false
                console.log(Number.isNaN("AB"));      //false
                console.log(Number.isNaN({a: 1}));    //false
                console.log(Number.isNaN(NaN));       //true
  • const isNaN = x => x !== x

Node.js中的事件循環是什麼?

事件循環處理全部異步回調。回調將在循環中排隊,而其餘代碼將運行,並將在收到每一個代碼的響應後逐個運行。

善意提醒

  • 事件循環容許Node.js執行非阻塞I/O操做,儘管JavaScript是單線程的

如何避免回調地獄?

getData(function(a) {
  getMoreData(a, function(b) {
    getMoreData(b, function(c) {
      getMoreData(c, function(d) {
        getMoreData(d, function(e) {
          // ...
        })
      })
    })
  })
})

重構使用返回promise或者使用 async/await的函數一般是最好的選擇。 它們沒有爲函數提供致使深度嵌套的回調,而是返回一個能夠等待的promise,而且在數據到達後將被解析,從而容許以相似於同步的方式計算下一行代碼。

以上代碼能夠被重構成這樣:

async function asyncAwaitVersion() {
  const a = await getData()
  const b = await getMoreData(a)
  const c = await getMoreData(b)
  const d = await getMoreData(c)
  const e = await getMoreData(d)
  // ...
}

有許多方式解決回調地獄的問題:

  • 模塊化: 把回調分解成獨立的函數
  • 使用控制流庫,好比async
  • 使用Promise的生成器
  • 使用async/await (>es7)

善意提醒

  • 做爲一個高效的JavaScript開發人員,您必須避免不斷增加的縮進級別,生成乾淨且可讀的代碼,並可以處理複雜的流。

什麼是閉包?你能舉一個有用的例子嗎?

閉包是在另外一個函數中定義的函數,即便在其詞法做用域以外執行,也能夠訪問其詞法做用域。

閉包能夠訪問三個範圍內的變量:

  • 在它本身的做用域中聲明的變量
  • 在父函數範圍內聲明的變量
  • 在全局範圍中聲明的變量

JavaScript中,全部函數都是閉包,由於它們能夠訪問外部範圍,可是大多數函數沒有利用閉包的有用性:狀態的持久性。閉包有時也所以被稱爲有狀態函數
此外,閉包是存儲沒法從JavaScript外部訪問的私有數據的惟一方法。它們是UMD (Universal Module Definition)模式的關鍵,UMD模式常常用於只公開公共API但保持實現細節私有的庫中,以防止與其餘庫或用戶本身的代碼發生名稱衝突。

友情提醒:

  • 閉包很是有用,由於它們容許您將數據與操做該數據的函數關聯起來。
  • 閉包只能用一個方法替換對象。
  • 閉包能夠用來模擬私有屬性和方法。
MDN的閉包解釋,也很清晰
相關文章
相關標籤/搜索