面試前的準備

2019-6-3 11:25:34

面試準備

  1. html語義化 — (不要全都是div) ===> html5 標籤
  2. 查看成熟ui組件庫源碼
  3. github上多星的相關項目 看他們用什麼
  4. 模擬數據mock.js
  5. 編寫易讀, 易維護的代碼
  6. 前端構建環境 gulp
  7. 基礎
  8. 算法
  9. 項目講述演練
html5 標籤
article - <h1>文本類 塊模型</h1>  => 類似body結構

aside - 側邊/左邊 內容 側邊欄是 aside,aside 不一定是側邊欄。

nav - 導航內容

section - 中間內容


body>header+aside+section+footer
article>header+aside+section+footer
section>article
性能優化

從輸入 URL 到頁面加載完成,發生了什麼?

瀏覽器進行DNS解析 -> TCP 網絡連接 -> HTTP 請求 -> HTTP 響應裏返回給客戶端 -> 瀏覽器渲染

 URL

  • 網絡傳輸性能檢測工具——chrome 網上應用商店 pagespeed

image
image

  • 雪碧圖生成插件webpack-spritesmith

參照
文檔

配置

image

知識體系

知識體系
image


javascript

  • 爲什麼有的編程規範要求用 void 0 代替 undefined?

因爲 JavaScript 的代碼 undefined 是一個變量,而並非是一個關鍵字,這是 JavaScript 語言公認的設計失誤之一,所以,我們爲了避免無意中被篡改,我建議使用 void 0 來獲取 undefined 值。

防止被重寫外,還可以減少字節

簡約寫法
//取整
parseInt(a,10); //Before
Math.floor(a); //Before
a>>0; //Before
~~a; //After
a|0; //After
 
//四捨五入
Math.round(a); //Before
a+.5|0; //After
 
//內置值
undefined; //Before
void 0; //After, 快
0[0]; //After, 略慢
 
//內置值
Infinity;
1/0;
 
//布爾值短寫法
true; //Before
!0; //After
 
//布爾值短寫法
false; //Before
!1; //After

  • 字符串有最大長度嗎?

最大長度是 2^53 - 1, 指的是 字符串的 UTF16 編碼,

  • 0.1 + 0.2 不是等於 0.3 麼?爲什麼 JavaScript 裏不是這樣的?

浮點數運算的精度問題導致等式左右的結果並不是嚴格相等,而是
相差了個微小的值。

ES6 新增 Number 屬性:

  1. EPSILON: 表示 1 和比最接近 1 且大於 1 的最小 Number 之間的差別
  2. isInteger(): 用來判斷給定的參數是否爲整數。
正確的比較方法是使用 JavaScript 提供的最小精度值:

 console.log( Math.abs(0.1 + 0.2 - 0.3) <= Number.EPSILON);
  • ES6 新加入的 Symbol 是個什麼東西?

一種新的原始數據類型Symbol,表示獨一無二的值

  • 爲什麼給對象添加的方法能用在基本類型上?

. 運算符提供了裝箱操作,它會根據基礎類型構造一個臨時對象,使得我們能在基礎類型上調用對應對象的方法。

JavaScript執行

1. Promise裏的代碼爲什麼比setTimeout先執行?

因爲 Promise 產生的是 JavaScript 引擎內部的微任務,而 setTimeout 是瀏覽器 API,它產生宏任務。

setTimeout 把整個代碼分割成了 2 個宏觀任務,這裏不論是 5 秒還是 0 秒,都是一樣的。

image

閉包

閉包是一個綁定了執行環境的函數,這個函數並不是印在書本里的一條簡單的表達式,閉包與普通函數的區別是,它攜帶了執行
的環境,就像人在外星中需要自帶吸氧的裝備一樣,這個函數也帶有在程序中生存的環境。

閉包詳解


css

CSS 支持一批特定的計算型函數:

  • calc()
  • max()
  • min()
  • toggle()
  • attr().

Dom

getElementById、getElementsByName、getElementsByTagName、getElementsByClassName,這幾個 API 的性能高於 querySelector。

而 getElementsByName、getElementsByTagName、getElementsByClassName 獲取的集合並非數組,而是一個能夠動態更新的集合。

  • 遍歷 NodeIterator || TreeWalker
var iterator = document.createNodeIterator(document.body, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT, null, false);
var node;
while(node = iterator.nextNode())
{
 console.log(node);
}

var walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, null, false)
var node;
while(node = walker.nextNode())
{
 if(node.tagName === "p")
 node.nextSibling();
 console.log(node);
}

鏈接

鏈接的家族中有 a 標籤、area 標籤和 link 標籤。今天,我會逐一對它們進行介紹。

link 標籤

  • 超鏈接類
  1. canonical 型 link => 會提示搜索引擎保留哪一個URL。

  2. alternate 型 link …

  • 外部資源類

外部資源型 link 標籤會被主動下載,並且根據 rel 類型做不同的處理。外部資源型的標籤包括:具有 icon 型的 link、預處理類 link、modulepreload 型的 link、
stylesheet、pingback。


瀏覽器:一個瀏覽器是如何工作的

  • 狀態碼
- 1xx:臨時迴應,表示客戶端請繼續。
- 2xx:請求成功。
    200:請求成功。
- 301&302:永久性與臨時性跳轉。
    304:跟客戶端緩存沒有更新。
- 4xx:客戶端請求錯誤。
    403:無權限。
    404:表示請求的頁面不存在。s
    418:It’s a teapot. 這是一個彩蛋,來自 ietf 的一個愚人節玩笑。(超文本咖啡壺控制協議)
- 5xx:服務端請求錯誤。
    500:服務端錯誤。
    503:服務端暫時性錯誤,可以一會再試。
    
對我們前端來說,1xx 系列的狀態碼是非常陌生的,原因是 1xx 的狀態被瀏覽器 http 庫直接處理掉了,不會讓上層應用知曉。

2xx 系列的狀態最熟悉的就是 200,這通常是網頁請求成功的標誌,也是大家最喜歡的狀態碼。

3xx 系列比較複雜,301 和 302 兩個狀態表示當前資源已經被轉移,只不過一個是永久性轉移,一個是臨時性轉移。實際上 301 更接近於一種報錯,提示客戶端下次
別來了。
304 又是一個每個前端必知必會的狀態,產生這個狀態的前提是:客戶端本地已經有緩存的版本,並且在 Request 中告訴了服務端,當服務端通過時間或者 tag,發
現沒有更新的時候,就會返回一個不含 body 的 304 狀態。

  • 請求頭

image

  • 響應頭

image

image

HTTPS 有兩個作用,一是確定請求的目標服務端身份,二是保證傳輸的數據不會被網絡中間節點竊聽或者篡改。

HTTPS 是使用加密通道來傳輸 HTTP 的內容。但是 HTTPS 首先與服務端建立一條 TLS 加密通道。TLS 構建於 TCP 協議之上,它實際上是對傳輸的內容做一次加
密,所以從傳輸內容上看,HTTPS 跟 HTTP 沒有任何區別。

HTTP 2.0 最大的改進有兩點,一是支持服務端推送,二是支持 TCP 連接複用。

瀏覽器CSSOM:如何獲取一個元素的準確位置

getComputedStyle(el)

el.getClientRects()

el.getBoundingClientRect()

職位jd分析

gulp

實際演練

  1. 怎麼讓雙核瀏覽器優先使用chrome內核

image

  1. 網站性能優化方法之一

image

相關鏈接

// <meta>信息告訴瀏覽器,當前頁面要做DNS預解析;https瀏覽器是默認不開啓的(a標籤)
 <meta http-equiv="x-dns-prefetch-control" content="on" />
 
// 使用<link>標籤來強制對DNS預解析;
 <!--如果不確定是http還是https連接的話建議如下寫法 -->
 <link rel="dns-prefetch" href="//renpengpeng.com" />
  1. javascript實現異步的方法

什麼是異步加載js?

使js文件脫離html解析的瀑布流加載,從而使js可以並行下載。

爲什麼要異步加載

一般寫法將js放在head中,而且默認方式是同步加載,這就會導致在進行js加載的過程中,無法在其加載完成前對後續的內容進行操作,造成頁面內阻塞,對用戶體驗很不友好。

相關鏈接

  • $(document).ready
  • 標籤的async=”async”屬性 async 屬性僅適用於外部腳本(只有在使用 src 屬性時)。
  • defer屬性
async和defer看起來差不多呀?而且經常一起出現!來辨析一下:

  (1)如果沒有async和defer屬性,那麼瀏覽器會立即執行當前的JS腳本,阻塞後面的腳本;

  (2)如果有async屬性,加載和渲染後續文檔的過程和當前JS的加載與執行並行進行(異步),它是亂序執行的,不管你聲明的順序如何,只要它加載完了就會執行;

  (3)如果有defer屬性,加載後續文檔元素的過程和JS的加載是並行進行(異步)的,但是JS的執行在所有元素解析完成之後進行,而且它是按照加載順序執行腳本的
  • 動態創建script

  • 原生的javascript 實現異步

 1、延遲類型:setTimeout(setInterval也是可以的)、requestAnimationFrame、setImmediate(IE10及以上)

 2、監聽事件實現的類型:監聽new Image加載狀態、監聽script加載狀態、監聽iframe加載狀態、Message

  3、帶有異步功能類型 Promise、ajax( XMLHttpRequest、ActiveXObject)、Worker;
常見異步加載(Script DOM Element)
(function() {
     var s = document.createElement('script');
     s.type = 'text/javascript';
     s.async = true;
     s.src = 'http://yourdomain.com/script.js';
     var x = document.getElementsByTagName('script')[0];
     x.parentNode.insertBefore(s, x);
 })();

這種加載方式在加載執行完之前會阻止 onload 事件的觸發,而現在很多頁面的代碼都在 onload 時還要執行額外的渲染工作等,所以還是會阻塞部分頁面的初始化處理

優化

// onload 時的異步加載
(function() {
     function async_load(){
         var s = document.createElement('script');
         s.type = 'text/javascript';
         s.async = true;
         s.src = 'http://yourdomain.com/script.js';
         var x = document.getElementsByTagName('script')[0];
         x.parentNode.insertBefore(s, x);
     }
     if (window.attachEvent)
         window.attachEvent('onload', async_load);
     else
         window.addEventListener('load', async_load, false);
 })();
 

這和前面的方式差不多,但關鍵是它不是立即開始異步加載 js ,而是在 onload 時纔開始異步加載。這樣就解決了阻塞 onload 事件觸發的問題。

自我介紹

自我陳述

  • 自如談興趣(前端方面) 巧妙示實例(提前瞭解公司的技術棧,優化點,功能如何實現) 適時討疑問(逐漸回答不上,含蓄地請教對方,討要點學習資料,不過以後補充了知識再來面試)
  • 節奏要適宜(謙虛,平穩地回答) 切忌小聰明(如實回答,不懂就適宜的問)
  • 方向要對,過程要細(實現方案要多,細,不怕錯,就怕不回答,)
  • 膽子要大,心態要和(要有追求新知識的積極,不要自卑,這次發現知識體系薄弱點,不足.下次再來面試)
B/S結構和C/S結構是什麼?它們之間有哪些區別和聯繫?
  • B/S結構

B是英文單詞“Browser”的首字母,即瀏覽器的意思;S是英文單詞“Server”的首字母,即服務器的意思。B/S就是“Browser/Server”的縮寫,即“瀏覽器/服務器”模式。

B/S結構是隨着互聯網的發展,web出現後興起的一種網絡結構模式。這種模式統一了客戶端,讓核心的業務處理在服務端完成。你只需要在自己電腦或手機上安裝一個瀏覽器,就可以通過web Server與數據庫進行數據交互

這種“B/S”結構有很多好處,維護和升級方式更簡單,客戶端是瀏覽器,基本不需要維護,只需要維護升級服務器端就可以

[外鏈圖片轉存失敗(img-ctIGU3Zw-1564816566398)(https://pics5.baidu.com/feed/58ee3d6d55fbb2fb1c40b6c3189885a04423dccb.png?token=bdda3bf161ef987975b5026a48d4e81c&s=192A7433836E690B4C54D4DE0300C0B1)]

  • C/S結構

“客戶端/服務器”模式。

C/S結構是一種軟件系統體系結構,也是生活中很常見的。這種結構是將需要處理的業務合理地分配到客戶端和服務器端,這樣可以大大降低通信成本,但是升級維護相對困難。比如我們手機中安裝的微信、qq、王者榮耀等應用程序就是C/S結構。

[外鏈圖片轉存失敗(img-ONptp6i1-1564816566398)(https://pics4.baidu.com/feed/9358d109b3de9c8267a6389b3453250e18d8433e.png?token=577184c0b3e27d4406e6240800dfe96a&s=98AA5C320B0A4C4B4C7464DE030080B1)]

  • B/S結構和C/S結構的區別
  1. 硬件環境不同,C/S通常是建立在專用的網絡上,小範圍的網絡環境。而B/S是建立在廣域網上的,適應範圍強,通常有操作系統和瀏覽器就行;
  2. C/結構比B/S結構更安全,因爲用戶羣相對固定,對信息的保護更強;
  3. B/S結構維護升級比較簡單,而C/S結構維護升級相對困難;

源碼解讀-分析

jQuery源碼解讀-事件分析

事件分析

慕課網


vue源碼

Object.defineProperty(obj, prop, descriptor)

obj
要在其上定義屬性的對象。

prop
要定義或修改的屬性的名稱。

descriptor
將被定義或修改的屬性描述符

返回值 被傳遞給函數的對象。

屬性描述符

對象裏目前存在的屬性描述符有兩種主要形式:數據描述符和存取描述符數據描述符是一個具有值的屬性,該值可能是可寫的,也可能不是可寫的。存取描述符是由getter-setter函數對描述的屬性。描述符必須是這兩種形式之一不能同時是兩者

可編輯

configurable: 當且僅當該屬性的 configurable 爲 true 時,該屬性描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false

可枚舉

enumberable: 當且僅當該屬性的enumerable爲true時,該屬性才能夠出現在對象的枚舉屬性中。默認爲 false。

數據描述符同時具有以下可選鍵值:

value: 該屬性對應的值。可以是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。

writable: 當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。

存取描述符同時具有以下可選鍵值:

get
一個給屬性提供 getter 的方法,如果沒有 getter 則爲 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,但是會傳入this對象(由於繼承關係,這裏的this並不一定是定義該屬性的對象)。
默認爲 undefined。
set

一個給屬性提供 setter 的方法,如果沒有 setter 則爲 undefined。當屬性值修改時,觸發執行該方法。該方法將接受唯一參數,即該屬性新的參數值。
默認爲 undefined。

var obj = {}

// Object.defineProperty(obj, prop, descriptor)


// obj.o = '123'
// ==
Object.defineProperty(obj, 'o', {
  value: '123',
  configurable: true,
  enumberable: true,
  Writable: true
})


// 在對象中添加一個屬性與存取描述符的示例
var bValue;
Object.defineProperty(obj, "b", {
  get : function(){
    console.log('get:' + bValue)
    return bValue;
  },
  set : function(newValue){
    console.log('set:' + newValue)
    bValue = newValue;
  },
  enumerable : true,
  configurable : true
});

obj.b = 38;
console.log(obj.o)
console.log(obj.b)

// 如果訪問者的屬性是被繼承的,它的 get 和set 方法會在子對象的屬性被訪問或者修改時被調用。如果這些方法用一個變量存值,該值會被所有對象共享。
// 在 get 和 set 方法中,this 指向某個被訪問和修改屬性的對象。
function myclass() {
}

Object.defineProperty(myclass.prototype, "x", {
  get() {
    return this.stored_x;
  },
  set(x) {
    this.stored_x = x;
  }
});

var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined

// 不像訪問者屬性,值屬性始終在對象自身上設置,而不是一個原型。然而,如果一個不可寫的屬性被繼承,它仍然可以防止修改對象的屬性。

myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
  writable: false,
  value: 1
});

var c = new myclass();
c.x = 2;
console.log(c.x); // 2
console.log(myclass.prototype.x); // 1
c.y = 2; // Ignored, throws in strict mode
console.log(c.y); // 1
console.log(myclass.prototype.y); // 1
雙向數據綁定原理分析

數據與視圖的綁定與同步,最終體現在對數據的讀寫處理過程中,也就是 Object.defineProperty() 定義的數據 set、get 函數中。Vue 中對於的函數爲 defineReactive

數據響應式原理

image

Vue 的響應式,核心機制是 觀察者模式。
數據是被觀察的一方,發生改變時,通知所有的觀察者,這樣觀察者可以做出響應,比如,重新渲染然後更新視圖

image

初始化,在new vue()之後,首先在內部執行了一個初始化方法,它做的就是一些最基礎的東西的初始化,比如說初始化生命週期,我們知道有很多生命週期的鉤子,還有一些props,還有我們一些數據data的響應化等,其中最重要的是通過object.defineProperty設置getter和setter函數,用來實現響應式以及依賴收集。

在初始化之後調用mountVuemount來執行掛載函數,我們知道Vue的初始化就是通過mount來實現的,mountdomvue西mount其實就是要指定一個掛載節點,可能會是一個目標節點,也有可能會是一個dom節點,最終就是告訴我們vue將把那些寫好的模板通過編譯以後達到更新以後這個最新的東西 我到底要顯示在什麼地方,就是mount最終指定的那個目標,然後$mount會啓動這個編譯器compile.

這個編譯器最重要的事情就是對我們的Template裏的東西進行一遍掃描,做parse optimize generate這三件事,compile在這個階段會生成一些渲染函數或者也可以叫更新函數,會生成一顆樹,我們叫虛擬節點樹,將來在做數據更新的時候,其實我們改變的數據並不是真正的dom操作,而是這個虛擬dom上的數值,當我們準備更新之前我們會做一個diff算法的比較,通過最新的值和之前的老值進行比較,從而計算出我們應該做的最小的dom更新,然後我們纔開始執行到這個patch步驟來打補丁做界面更新.

這樣兒做的目的是用js裏面的計算時間來換dom操作時間,我們知道瀏覽器的瓶頸在對頁面操作這一塊兒比較耗時間,Vue的核心在於減少頁面渲染的次數和數量,compile除了編譯渲染函數之外,還會做一個依賴收集的工作,通過這個依賴收集我們可以知道當頁面數據發生變化的時候我應該去更新頁面中的那一個dom節點,這也就是將來這個數據發生變化的時候,我們可以通過這個watcher觀察者來知道數據發生變化,這時候調用更新渲染函數來打補丁。

image

  • Vue的渲染邏輯——Render函數

三種渲染模式,自定義Render函數、template、el均可以渲染頁面

這三種渲染模式最終都是要得到Render函數。只不過用戶自定義的Render函數省去了程序分析的過程,等同於處理過的Render函數,而普通的template或者el只是字符串,需要解析成AST,再將AST轉化爲Render函數。

瀏覽器的事件循環(Event Loop)機制 ==> Vue 異步更新

image

上圖中,主線程運行的時候,產生堆(heap)和棧(stack),棧中的代碼調用各種外部API,它們在"任務隊列"中加入各種事件(click,load,done)。只要棧中的代碼執行完畢,主線程就會去讀取"任務隊列",依次執行那些事件所對應的回調函數。

執行棧中的代碼(同步任務),總是在讀取"任務隊列"(異步任務)之前執行。請看下面這個例子。

var req = new XMLHttpRequest();
req.open('GET', url);    
req.onload = function (){};    
req.onerror = function (){};    
req.send();

上面代碼中的req.send方法是Ajax操作向服務器發送數據,它是一個異步任務,意味着只有當前腳本的所有代碼執行完,系統纔會去讀取"任務隊列"。所以,它與下面的寫法等價。

var req = new XMLHttpRequest();
req.open('GET', url);
req.send();
req.onload = function (){};    
req.onerror = function (){};   

也就是說,指定回調函數的部分(onload和onerror),在send()方法的前面或後面無關緊要,因爲它們屬於執行棧的一部分,系統總是執行完它們,纔會去讀取"任務隊列"。

image

Worker多線程

js是基於單線程的,而這個線程就是瀏覽器的js引擎。

假如我們要執行一些耗時的操作,比如加載一張很大的圖片,我們可能需要一個進度條來讓用戶進行等待,在等待的過程中,整個js線程會被阻塞,後面的代碼不能正常運行,這可能大大的降低用戶體驗,這時候我們就期望擁有一個工作線程來處理這些耗時的操作。在傳統的html時代是基本不可能實現的,而現在,我們擁有一種叫做worker的東西。它是js裏的一個類,而我們只需要創建它的實例就可以使用它。

var worker = new Worker(js file path);

構造函數的參數填上你的js文件的路徑,這個js文件將會在瀏覽器新開的線程裏運行,而與原先的js引擎的線程並不影響。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <input type="text" name="ipt" id="ipt" value="" />
        <button id="start">start</button>
        <button id="stop">stop</button>
        <button id="ale">alert</button>
        <script type="text/javascript">
            var ipt = document.getElementById("ipt");
            var stop = document.getElementById("stop");
            var start = document.getElementById("start");
            var ale = document.getElementById("ale");
            var worker = new Worker("js/test22.js");
            worker.onmessage = function(){
                ipt.value = event.data;
            };
            stop.addEventListener("click",function(){
                //用於關閉worker線程
                worker.terminate();
            });
            start.addEventListener("click",function(){
                //開起worker線程
                worker = new Worker("js/test22.js");
            });
            ale.addEventListener("click",function(){
                alert("i'm a dialog");
            });
        </script>
    </body>
</html>

test22.js

var i = 0;
function mainFunc(){
    i++;
    //把i發送到瀏覽器的js引擎線程裏
    postMessage(i);
}
var id = setInterval(mainFunc,1000);

運行起來我們會發現

image

雖然dialog的彈出會阻塞js引擎線程,但是並不影響worker線程的運行,所以,在我們點擊確定後,只是在js引擎線程上更新了新的內容,而數值是一直在跑動的,這就說明worker線程和原本的js線程互不影響.

那麼既然互不影響,兩個線程之間要怎麼來聯繫呢,答案其實已經在代碼裏了,那就是onPostMessage 和 onmessage這兩個函數,其中onPostMessage(data)的參數是你要傳遞的數據,而onmessage是一個回調函數,只有在接受到數據時,onmessage會被回調,onmessage有一個隱藏的參數,那就是event,我們可以用event.data獲取到傳遞過來的數據來更新主線程。

使用worker線程應注意的是,所有js裏集成的對象都在js線程裏,而並非worker線程。

var a = document.getElementById("a"); // Error

儘量把需要的東西都寫到主線程裏,而只把耗時的操作寫到worker線程裏。

開發環境

git

網絡git服務器 codeing.net

js模塊化

打包工具

上線回滾的流程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章