寒冬面試小總結

面試題總結

開篇小囉嗦

2019年是互聯網最難受的一年。可是同時也是最好的一年。可是市場不管怎麼變,本身若是能時刻保持學習,即可以以不變應萬變。下面整理一下最新鮮的面試題。你確定看上去就很熟悉。可是又以爲沒那麼熟悉,下面就一塊兒覆盤一下。(大神略過)css

答案部分並非所有詳細的回答,畢竟面試的時候不可能給你太長時間去細講,主要是寫一下核心的死裏以及主要代碼。若是要想仔細瞭解,查一下資料,每一個答案都有不少的詳細答案。html

下面的題目是各類公衆號,朋友面試,整理出來的問題,答案是本身整理的,不免有紕漏。望指正vue

CSS類

1.盒模型

在一個文檔中,每一個元素都被表示爲一個矩形的盒子,不一樣的瀏覽器顯示不一樣的盒子模型,node

盒模型是有兩種標準的,react

一個是標準模型webpack

標準和模型中,寬高就是你本身的內容寬高css3

標準盒模型中,總width = 你設置的width+2margin+2padding+2bordernginx

一個塊的總寬度= width + margin(左右) + padding(左右) + border(左右)es6

一個是IE模型(怪異盒模型)。web

IE模型中盒模型的寬高是內容(content)+填充(padding)+邊框(border)的總寬高。

在IE的盒子模型中,width表示content+padding+border這三部分的寬度。

一個塊的總寬度= width + margin(左右)(即width已經包含了padding和border值)

兩個盒子展現圖

標準模型

css如何設置兩種模型
這裏用到了CSS3 的屬性 box-sizing

/* 標準模型 */
box-sizing:content-box;

 /*IE模型*/
box-sizing:border-box;
複製代碼

好比說兩個盒子並列排布,寬各爲50%,可是此時有個新需求,盒子加上邊框,用標準的你就會發現問題,會掉下來。若是用怪異的。由於border是計算在width裏面的,不會撐開,完美解決。

2.不設寬高水平垂直居中方法

第一種:transform:translate(-50%,-50%)

.parent{
    position:relative
}
.son{
    position:absolute;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%);
}
複製代碼

第二種:彈性盒模型

.parent{
    display:flex;
    justify-content:center;定義項目在主軸(水平方向)上居中對齊
    align-items:center;定義項目在交叉軸(垂直方向)上居中對齊
}
.son{
    裏面隨便寫。寬高愛寫不寫。都是居中的
}
複製代碼

3.三欄佈局

三欄佈局,顧名思義就是兩邊固定,中間自適應。三欄佈局在實際的開發十分常見,好比淘寶網的首頁,就是個典型的三欄佈局:即左邊商品導航和右邊導航固定寬度,中間的主要內容隨瀏覽器寬度自適應。

第一種: 浮動佈局

.left{
    float: left;
    width: 300px;
    height: 100px;
    background: #631D9F;
}
.right{
    float: right;
    width: 300px;
    height: 100px;
    background: red;
}

如今兩側的樣式寫好了,那麼咱們來寫中間的樣式,

.center{
    margin-left: 300px;
    margin-right: 300px;
    background-color: #4990E2;
}

清除一下浮動

.main::after{
    content:'';
    display: block;
    clear: both;
}
複製代碼

第二種:Position佈局

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>position</title>
    <style type="text/css"> *{ margin: 0; padding: 0; } </head> <body> <article class="main"> <div class="left"></div> <div class="center"><h2>絕對定位</h2> </div> <div class="right"></div> </article> </body> </html> <script> .left{ position: absolute; left: 0; width: 300px; background-color: red; } .center{ position: absolute; left: 300px; right: 300px; background-color: blue; } .right{ position: absolute; right: 0; width: 300px; background-color: #3A2CAC; } </script> 複製代碼

第三種: flex彈性盒佈局

.main {
    display: flex;
    justify-content:center;
    align-items:center;
}
.left{
    width: 400px;
    background-color: red;
}
.center{
    flex:1
    background-color: blue;
    word-break: break-word;
}
.right{
    background-color: red;
    width: 400px;
}

複製代碼

4.選擇器權重計算方式

選擇器 栗子
ID #id
class .class
標籤 p
屬性 [type='text']
僞類 :hover
僞元素 ::first-line
相鄰選擇器、子代選擇器 > +
  • 內聯樣式,如: style="...",權值爲1000。
  • ID選擇器,如:#content,權值爲0100。
  • 類,僞類、屬性選擇器,如.content,權值爲0010。
  • 類型選擇器、僞元素選擇器,如div p,權值爲0001。
  • 通配符、子選擇器、相鄰選擇器等。如* > +,權值爲0000。
  • 繼承的樣式沒有權值

5.清除浮動的方法

浮動產生的緣由:

當一個內層元素是浮動的時候,若是沒有關閉浮動,其父元素也就不會再包含這個浮動的內層元素,由於此時浮動元素已經脫離了文檔流。也就是爲何外層不能被撐開了

1、:after的3行代碼

原理:利用:after和:before在元素內插入兩個元素塊(其實就是在節點自己構造出兩個存在於Render Tree的節點),從而達到清除浮動的效果。

.box:after{
    clear: both;
    content: '';
    display: block;
}
複製代碼

2、添加新的節點,使用clear:both方法

原理:在父節點中插入元素塊,清除浮動

<div class="box">
    <div class="d1">1</div>
    <div class="d2">2</div>
    <div class="clc"></div>
</div>
<style> .clc{ clear: both; } </style>
複製代碼

3、在父節點上設置一個新類名,而後在類名css中設置

原理:這樣也能夠清除浮動,其原理是使用overflow屬性來清除浮動,overflow有三個值:auto| hidden | visible,

咱們可使用 hidden和 auto來清除浮動,

但絕不能夠使用 visible 清除浮動,使用這個值達不到效果

<div class="box over-flow">
    <div class="d1">1</div>
    <div class="d2">2</div>
</div>   
<style> .over-flow{ overflow: auto; } </style>
複製代碼

6.flex

flex是css3的彈性盒模型。在解決一個佈局的時候,很是方便,

flex彈性盒主要是要區分什麼是偶寫在父元素,何時寫在子元素。

分不清,父子元素寫這些屬性,就會很難用。或各類不生效

父元素屬性

子元素屬性

這一塊就是各類屬性多用。都嘗試一遍,就知道屬性怎麼使用了。

7.什麼是BFC、能夠解決哪些問題

BFC 全稱爲 塊格式化上下文 (Block Formatting Context) 。

????

沒有深刻研究的話誰一看都一臉懵逼,啥意思。

MDN講那麼多定義,最後仍是不知道幹嗎的

僅僅知道它是一種功能,針對於 HTML文檔 起做用。

既然這樣,就直接上例子。少說定義,就知道幹嗎的了

  • 造成 BFC 的條件

    一、浮動元素,float 除 none 之外的值;

    二、絕對定位元素,position(absolute,fixed);

    三、display 爲如下其中之一的值 inline-blocks,table-cells,table-captions;

    四、overflow 除了 visible 之外的值(hidden,auto,scroll)。

  • bfc的特性(功能)

(1).使 BFC 內部浮動元素不會處處亂跑;

父元素包含子元素,子元素若是浮動了,就脫離了文檔流, 那麼父元素就會高度塌陷。沒法包含子元素,這時候把父元素造成一個塊級別格式化一下,就能夠了。父元素 ovelflow:hidden 就是這個原理

(2).和浮動元素產生邊界

一半狀況下,兩個元素,其中一個元素浮動。另外一個元素,想要跟浮動元素,產生邊距,須要設置margin-left:浮動元素寬度+margin值 可是把非浮動元素塊級格式化一下,就不用這麼麻煩了

(3)上代碼

/*若是沒有塊級格式化產生邊距20px*/
    <body>
        <div class="e"></div>
        <div class="m"></div>
    </body>
    <style> .e{ border:1px solid #0f0; width:100px; height:100px; float:left; } .m{ border:1px solid #f00; width:100px; height:100px; margin-left:120px; 這塊要設置成120px才能造成 } </style>
複製代碼
/*若是有塊級格式化產生邊距20px*/
    <body>
        <div class="e"></div>
        <div class="m"></div>
    </body>
    <style> .e{ border:1px solid #0f0; width:100px; height:100px; margin-right:20px; 本身設置邊距就能夠 float:left; } .m{ border:1px solid #f00; width:100px; height:100px; overflow:hidden; 把本身變成塊級格式化元素 } </style>
複製代碼

8.position屬性

absolute: 生成絕對定位的元素,相對於 static 定位之外的第一個父元素進行定位。

元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。

fixed:生成絕對定位的元素,相對於瀏覽器窗口進行定位。

元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。

relative:生成相對定位的元素,相對於其正常位置進行定位。

所以,"left:20" 會向元素的 LEFT 位置添加 20 像素。

static:默認值。沒有定位,元素出如今正常的流中(忽略 top, bottom, left, right 或者 z-index 聲明)。

手寫題

手寫題是每一個公司都會有考試。,範圍也比較固定,若是能大概準備一下,八九不離十就這幾道題,固然基礎選擇題就忽略了

防抖和節流

防抖是將屢次執行變爲最後一次執行,節流是將屢次執行變爲在規定時間內只執行一次 咱們在操做的js的時候,有不少根據窗口尺寸,或者滾動加載事件來執行方法的。可是這種操做會及其頻繁的佔用瀏覽器性能

因此咱們設置一下,避免頻繁調用方法,增長瀏覽器的負擔

(1)防抖

防抖是在單位時間內。只要觸發事件,調用方法的時間就會從新計算延遲。只有單位時間再也不操做。纔會調用一次方法。

好比 持續觸發scroll事件時,並不執行handle函數,當1000毫秒內沒有觸發scroll事件時,纔會延時觸發scroll事件。

簡單的防抖函數實現

function debounce(fn, delay) {
  let timer
  return function() {
    let _this = this
    let args = arguments
    // 防抖事件,只要定時器存在。還一直頻繁操做事件,我就一直給你清空,直到你中止
    if (timer !== null) {
      clearTimeout(timer)
      timer = setTimeout(()=> {
        fn.apply(context, args)
      },delay) 
    }
  }
}
function handle() {
  console.log(90909201902190)
}

window.addEventListener('scroll', debounce(handle, 1000))
複製代碼

應用場景: 兩個條件:

1,若是客戶連續的操做會致使頻繁的事件回調(可能引發頁面卡頓).

2,客戶只關心"最後一次"操做(也能夠理解爲中止連續操做後)所返回的結果.

例如:

輸入搜索聯想,用戶在不斷輸入值時,用防抖來節約請求資源。

按鈕點擊:收藏,點贊,心標等
複製代碼

(2) 節流

當用戶操做持續出發事件的時候,保證必定時間內,只執行一次方法

// 定時器版本的節流
function throttle(fn, delay) {
  let timer
  return function () {
    let args = arguments
    let context = this
    // 若是頻繁操做事件,定時器還在,什麼都不執行,若是定時器不在了,設置一個定時器。
    if(!timer) {
      timer = setTimeout(() => {
        fn.apply(context,args)
        timer = null
      },delay)
    }
  }
}

複製代碼

(3) 總結

函數防抖:將幾回操做合併爲一此操做進行。原理是維護一個計時器,規定在delay時間後觸發函數,可是在delay時間內再次觸發的話,就會取消以前的計時器而從新設置。這樣一來,只有最後一次操做能被觸發。

函數節流:使得必定時間內只觸發一次函數。原理是經過判斷是否到達必定時間來觸發函數。

區別: 函數節流無論事件觸發有多頻繁,都會保證在規定時間內必定會執行一次真正的事件處理函數,而函數防抖只是在最後一次事件後才觸發一次函數。 好比在頁面的無限加載場景下,咱們須要用戶在滾動頁面時,每隔一段時間發一次 Ajax 請求,而不是在用戶停下滾動頁面操做時纔去請求數據。這樣的場景,就適合用節流技術來實現。

數組去重、數組扁平化

1、ES6 set去重

function unique (arr) {
  return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
 //[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
複製代碼

2、利用indexOf去重

function unique(arr) {
    var array = [];
    for (var i = 0; i < arr.length; i++) {
        if (array .indexOf(arr[i]) === -1) {
            array .push(arr[i])
        }
    }
    return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
複製代碼

3、利用filter

function unique(arr) {
  return arr.filter(function(item, index, arr) {
    //indexOf老是返回第一個元素的位置,後續的重複元素位置與indexOf返回的位置不相等,所以被filter濾掉了。
    return arr.indexOf(item, 0) === index;
  });
}
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
        console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
複製代碼

手寫call、apply、bind

1、手寫實現call

/*強調一下,通常來講,對象調用了那個方法,這個方法的this就是指向這個對象的*/

/* 其實call方法就是在方法(Function)的原型上添加了一個方法(call)。 這個添加的方法(call)。有個參數(隨便都行)就是你要指向的那個對象(foo1)。 方法裏面的this(bar)就是你要改變指向的方法。原理就是: 在這個call方法裏面把要改變方向的方法(bar)複製一份給被指向的對象(foo1), 而後被指向的對象調用這個方法。這不就是把bar方法的this指向foo1對象了啊 */

// 手動實現一個call
    Function.prototype.call2 = function(context = window) {
      context.fn = this 
      // 打印一下this,就是 方法bar
      // context是傳入的對象,this是指須要改變指向的那個函數,在目標對象上覆制一個須要改變指向的方法
      let args = [...arguments].slice(1)   // //解析參數,第一個參數不要。由於是指向的對象。從第二個參數開始纔是須要的
      let result = context.fn(...args)// //目標對象上新複製的函數,執行一下,記得把處理的參數放進去。
      delete context.fn // // //執行完。把添加的方法刪了。要否則無緣無故就會多出一個函數。上面已經改變
      return result // 把結果返回啊
    }

    var foo1 = {
      value:5
    }

    function bar(name,age) {
      console.log(name)
      console.log(age)
      console.log(this.value)
    }
    
    bar.call2(foo1,'back',12)
複製代碼

1、手寫實現apply

/*apply和call的惟一區別就是傳的參數不一樣。call是一個個傳進去,apply是傳一個數組進去。因此兩個的原理寫法是差很少的。區別就是處理參數的時候不一樣*/

Function.prototype.apply1 = function(context=window) {
  context.fn = this
  let result
  // 若是第二個傳參了,apply 要求第二個參數是數組。就把數組一個個拓展開。
  if (arguments[1]) {
    result = context.fn(...arguments[1])
  } else {
    result = context.fn()
  }
  delete context.fn
  return result
}

const bar = {
  m:1,
  c:2,
}

function test() {
  console.log(this.m)
}

test.apply1(bar)
複製代碼

3、手寫實現bind

bind和apply的區別在於,bind是返回一個綁定好的函數,apply是直接調用.

就是返回一個函數,裏面執行了apply上述的操做而已.
不過有一個須要判斷的點,由於返回新的函數,要考慮到使用new去調用,
而且new的優先級比較高,因此須要判斷new的調用,
/* 1.綁定this指向 2.返回一個綁定後的函數(高階函數原理) 3.若是綁定的函數被new執行 ,當前函數的this就是當前的實例 new出來的結果能夠找到原有類的原型 */
Function.prototype.myBind = function (context, ...args) {
    // 傳件來的須要改變指向的函數
    const fn = this
    // 傳的參數是單個仍是數組
    args = args ? args : []
    // 返回一個新的函數
    return function newFn(...newFnArgs) {
        // 傳件來的函數是是當前返回函數的實例。而且new出來的也要能夠傳參
        if (this instanceof newFn) {
            return new fn(...args, ...newFnArgs)
        }
        return fn.apply(context, [...args,...newFnArgs])
    }
}
複製代碼

繼承(ES5/ES6)

sleep函數

實現promise

eventEmitter(emit,on,off,once)

實現new

懶加載的原理,大概實現思路

圖片懶加載技術主要經過監聽圖片資源容器是否出如今視口區域內,來決定圖片資源是否被加載。 那麼實現圖片懶加載技術的核心就是如何判斷元素處於視口區域以內。

之前

之前的懶加載核心技術原理就是經過js提供的elemenr.getBoundingClientRect()

  1. 給圖片容器自定義屬性,不賦值真實圖片鏈接,
  2. 利用scroll事件, Element.getBoundingClientRect() 方法判斷目標容器是否給跟可視區域交叉了
  3. 判斷交叉了 就 把真實連接賦值給圖片容器,顯示內容

注意使用的時候 scroll事件記得使用節流,避免一直觸發操做事件,影響性能

如今

Web爲開發者提供了 IntersectionObserver 接口它 能夠異步監聽目標元素與其祖先或視窗的交叉狀態, 注意這個接口是異步的,它不隨着目標元素的滾動同步觸發,因此它並不會影響頁面的滾動性能。

var io = new IntersectionObserver(callback, options)


// 用來指定交叉比例,決定何時觸發回調函數,是一個數組,默認是[0]。

// 咱們指定了交叉比例爲0,0.5,1,當觀察元素img0%、50%、100%時候就會觸發回調函數
const options = {
    root: null,
    threshold: [0, 0.5, 1]
}
var io = new IntersectionObserver(callback, options)
io.observe(document.querySelector('img'))
複製代碼

函數currying

1、柯里化的概念

在數學和計算機科學中,柯里化是一種將使用多個參數的一個函數轉換成一系列使用一個參數的函數的技術。

舉例來講,一個接收3個參數的普通函數,在進行柯里化後, 柯里化版本的函數接收一個參數並返回接收下一個參數的函數, 該函數返回一個接收第三個參數的函數。 最後一個函數在接收第三個參數後, 將以前接收到的三個參數應用於原普通函數中,並返回最終結果。

// 舉個例子
// 數學和計算科學中的柯里化:

//一個接收三個參數的普通函數
function sum(a,b,c) {
    console.log(a+b+c)
}

//用於將普通函數轉化爲柯里化版本的工具函數
function curry(fn) {
  //...內部實現省略,返回一個新函數
}

//獲取一個柯里化後的函數
let _sum = curry(sum);

//返回一個接收第二個參數的函數
let A = _sum(1);
//返回一個接收第三個參數的函數
let B = A(2);
//接收到最後一個參數,將以前全部的參數應用到原函數中,並運行
B(3)    // print : 6
複製代碼

這裏大概就是講一下什麼是函數柯里化的概念,下面大概講一下柯里化的應用

2、柯里化的用途

柯里化本質上是下降通用性,提升適用性。來看一個例子:

咱們開發工做中會遇到不少的校驗工做,封裝一個函數,傳入正則驗證參數,傳入待驗證參數進行驗證,

function checkByRegExp(regExp,string) {
    return regExp.test(string);  
}

checkByRegExp(/^1\d{10}$/, '18642838455'); // 校驗電話號碼
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com'); // 校驗郵箱

複製代碼

若是驗證少沒問題,若是不少的話,就不行了,很繁瑣。向下面這樣

checkByRegExp(/^1\d{10}$/, '18642838455'); // 校驗電話號碼
checkByRegExp(/^1\d{10}$/, '13109840560'); // 校驗電話號碼
checkByRegExp(/^1\d{10}$/, '13204061212'); // 校驗電話號碼

checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@163.com'); // 校驗郵箱
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@qq.com'); // 校驗郵箱
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@gmail.com'); // 
複製代碼

極度繁瑣,第一個驗證參數,很長,不少,很不優雅

咱們經常使用的工具庫loadsh就有這個功能,若是使用柯里化之後

//進行柯里化
let _check = curry(checkByRegExp);
//生成工具函數,驗證電話號碼
let checkCellPhone = _check(/^1\d{10}$/);
//生成工具函數,驗證郵箱
let checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);

checkCellPhone('18642838455'); // 校驗電話號碼
checkCellPhone('13109840560'); // 校驗電話號碼
checkCellPhone('13204061212'); // 校驗電話號碼

checkEmail('test@163.com'); // 校驗郵箱
checkEmail('test@qq.com'); // 校驗郵箱
checkEmail('test@gmail.com'); // 校驗郵箱
複製代碼

就會很簡潔優雅,

其實就是能夠理解爲:參數複用

ES6

es6 不用說了。面試必問。必問,並且你回答一下還不行,還會針對你的問題進行深層次問,大都會給一個業務場景,讓你說。可是隻要基礎說好了。業務按着功能講一下思路就行了

let、const、var區別

var 聲明的變量能夠掛載在window上,const let不行

var存在變量提高,const let沒有

let const 存在塊級做用域,var不存在

同一做用域下let和const不能聲明同名變量,而var能夠

const 聲明的變量必須有值,不能爲空,let能夠

let,const 存在暫時性死區

箭頭函數與普通函數的區別

箭頭函數已是老生長談了,所謂的箭頭函數,寫法不少種,在這裏不作詳細解釋了,

  1. 箭頭函數是匿名函數,不能做爲構造函數,不能使用new
  2. 箭頭函數不綁定arguments,取而代之用rest參數...解決
let B = (b)=>{
  console.log(arguments);
}
B(2,92,32,32);   // Uncaught ReferenceError: arguments is not defined


let C = (...c) => {
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]
複製代碼
  1. 箭頭函數不綁定this,會捕獲其所在的上下文的this值,做爲本身的this值
  2. 箭頭函數沒有原型屬性
var a = ()=>{
  return 1;
}

function b(){
  return 2;
}

console.log(a.prototype);  // undefined
console.log(b.prototype);   // {constructor: ƒ}
複製代碼

5.總結一下,箭頭函數,任何方法沒有辦法修改指向的

promise、async await、Generator的區別

咱們知道JavaScript是單線程語言,若是沒有異步編程非得卡死。 這仨個具體的詳細用法最好百度查找相關資料。這裏對其詳細用法不作闡述。 由於每個的用法,一篇長文章都不必定能夠解釋完。。。。

異步編程之前通用的是回調函數來解決,少許回調還好,若是不少層的話,解讀要瘋掉,很不直觀,

promise

因此promise能夠解決回調的地獄,將原來的用 回調函數 的 異步編程 方法轉成用relsove和reject觸發事件, 用 then 和 catch 捕獲成功或者失敗的狀態執行相應代碼的異步編程的方法

Generator

Generator是ES6的實現,最大的特色就是能夠交出函數的執行權, 普通函數的寫法,可是不會返回執行結果,須要手動執行next來執行結果,這樣若是不少的話,你手動也不太能分清楚誰先執行,誰後執行

async await

這個方案就很厲害了,是Generator的語法糖,整合了裏面的功能,不須要手動執行阻塞通行,執行執行完方法,自動執行接下來的方法,並且只須要一行代碼。

在 await 的部分等待返回, 返回後自動執行下一步。並且相較於Promise,async 的優越性就是把每次異步返回的結果從 then 中拿到最外層的方法中,不須要鏈式調用,只要用同步的寫法就能夠了。

ES6的繼承與ES5相比有什麼不一樣

繼承的目的是方法或者屬性公用,不要重複建立使用,

核心是ES5是經過原型或者構造函數進行繼承的,ES6是經過class關鍵字進行繼承的

ES5繼承

es5繼承有不少方式,最經常使用的就是原型繼承

function Parent(name) {
   this.name = name;
   this.n = 2222;
   this.color = ["red", "blue"];
}
Parent.prototype.sayName = function() {
 console.log('父類定義的一堆邏輯')
}
function child(name) {
 console.log('子類方法')
}
child.prototype = new Parent();   // 核心地方

var s1 = new child();
s1.sayName(); //也能夠調用父函數的方法
console.log(s1.color); //也能夠調用父函數的屬性 ["red","color"]
console.log(s1.n);// 222
// 此時能夠繼承父函數的屬性
複製代碼

實質上就是將子類的原型設置爲父類的實例。

ES6繼承

ES6繼承是經過class丶extends 關鍵字來實現繼承 Parent是父類,child 是子類 經過 class 新建子類 extends繼承父類的方式實現繼承,方式比ES5簡單的多。

class Parent {
   constructor(name) {
       this.name = name;
       this.color = ["red", "blue"];
   }
   sayName() {
       alert(this.name);
   }
}
class child extends Parent {
   constructor(name, age) {
   // 至關於SuperType.call(this, name);
       super(name);
       this.age = age;
   }
}
var s1 = new child('ren', 19);
console.log(s1);
複製代碼

ES5 :子類的原型設置爲父類的實例。(es5繼承有太多種了,須要那個搜一下,不用所有記住)

ES6:先創造父類的實例對象 this,子類調用super方法,而後再用子類的構造函數修改this

js模塊化(commonjs/AMD/CMD/ES6)

1、CommonJS

CommonJS主要用在Node開發上,每一個文件就是一個模塊 CommonJS經過require()引入模塊依賴,require函數能夠引入Node的內置模塊、自定義模塊和npm等第三方模塊。

require函數在加載模塊是同步的

2、AMD和CMD

區別於CommonJS,AMD規範的被依賴模塊是異步加載的

AMD 推崇依賴前置,CMD 推崇依賴就近。

CMD集成了CommonJS和AMD的的特色,支持同步和異步加載模塊。CMD加載完某個依賴模塊後並不執行,只是下載而已,在全部依賴模塊加載完成後進入主邏輯,遇到require語句的時候才執行對應的模塊

從輸入URL到呈現頁面過程

瀏覽器的緩存,強緩存、協商緩存

咱們在開發的時候,會常常遇到304緩存信息,這就涉及到瀏覽器的緩存問題了

瀏覽器分爲強緩存和協商緩存:

1)瀏覽器在加載資源時,先根據這個資源的一些http header判斷它是否命中強緩存,強緩存若是命中,瀏覽器直接從本身的緩存中讀取資源,不會發請求到服務器。好比某個css文件,若是瀏覽器在加載它所在的網頁時,這個css文件的緩存配置命中了強緩存,瀏覽器就直接從緩存中加載這個css,連請求都不會發送到網頁所在服務器;

2)當強緩存沒有命中的時候,瀏覽器必定會發送一個請求到服務器,經過服務器端依據資源的另一些http header驗證這個資源是否命中協商緩存,若是協商緩存命中,服務器會將這個請求返回,可是不會返回這個資源的數據,而是告訴客戶端能夠直接從緩存中加載這個資源,因而瀏覽器就又會從本身的緩存中去加載這個資源;

3)強緩存與協商緩存的共同點是:若是命中,都是從客戶端緩存中加載資源,而不是從服務器加載資源數據;區別是:強緩存不發請求到服務器,協商緩存會發請求到服務器。

4)當協商緩存也沒有命中的時候,瀏覽器直接從服務器加載資源數據。

強緩存

強緩存是利用Expires或者Cache-Control這兩個http response header實現的,它們都用來表示資源在客戶端緩存的有效期。

這兩個header能夠只啓用一個,也能夠同時啓用,當response header中,Expires和Cache-Control同時存在時,Cache-Control優先級高於Expires:

弱緩存

弱緩存【ETag、If-None-Match】兩個字段實現的

瀏覽器第一次跟服務器請求一個資源,服務器在返回這個資源的同時,在respone的header加上ETag的header,這個header是服務器根據當前請求的資源生成的一個惟一標識

Response Headers
date: Tue, 02 Jul 2019 09:47:48 GMT
ETag: "17df-adasdascae242vsd"
複製代碼

瀏覽器再次跟服務器請求這個資源時,在request的header上加上If-None-Match的header,這個header的值就是上一次請求時返回的ETag的值

Response Headers
date: Tue, 02 Jul 2019 09:47:48 GMT
If-None-Match: "17df-adasdascae242vsd"
複製代碼

服務器再次收到資源請求時,根據瀏覽器傳過來If-None-Match和資源生成一個新的ETag,若是這兩個值相同就說明資源沒有變化,不然就是有變化;若是沒有變化則返回304 Not Modified,可是不會返回資源內容;若是有變化,就正常返回資源內容

若是資源已經被瀏覽器緩存下來,在緩存失效以前,再次請求時,默認會先檢查是否命中強緩存,若是強緩存命中則直接讀取緩存,若是強緩存沒有命中則發請求到服務器檢查是否命中協商緩存,若是協商緩存命中,則告訴瀏覽器仍是能夠從緩存讀取,不然才從服務器返回最新的資源。這是默認的處理方式,這個方式可能被瀏覽器的行爲改變:

1)當ctrl+f5強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存;

2)當f5刷新網頁時,跳過強緩存,可是會檢查協商緩存

HTTP2

Https加密原理

三次握手與四次揮手

跨域有哪幾種(JSONP/CORS)

1、jsonp

jsopn是由於script標籤不受同源策略限制。 可是隻能get 還不安全,可能被攔截,發送病毒

2、cors

cors跨域後端, 只能攜帶一個請求頭或者* , 若是用* 就不能攜帶cookie(瀏覽器保證安全)

3、proxy代理

vue或者react框架的代理轉發,原理是利用node的express模擬服務器請求目標服務器數據,服務器不存在跨域問題。

4、nginx配置

後端護着運維配置,由於服務器請求服務器不存在跨域,因此nginx代理服務器請求數據

web安全問題

這個不是特別大的重點,並非全部的公司都會詢問。可是通常只要問了,總要說點什麼吧

https和http的區別

什麼是xss,如何預防

什麼是csrf,如何預防

爲何會形成csrf攻擊

框架(vue)

目前市場上,主流就是vue和react框架。這兩個都不會的話,就很難混下去,此次就主要是vue的問題,重點問的,無非就是響應式原理,虛擬dom,nextTick的原理,通訊。。。。

watch與computed的區別

vue生命週期及對應的行爲

(1)beforeCreate中拿不到任何數據,它在實例初始化以後,數據觀測 (data observer) 和 event/watcher 事件配置以前被調用。

(2)created中已經能夠拿到data中的數據了,可是dom尚未掛載。會判斷有無el,若是沒有el則中止後面的模板掛載。 在實例建立完成後被當即調用。在這一步,實例已完成如下的配置:數據觀測 (data observer),屬性和方法的運算,watch/event 事件回調。

(3)beforeMount 和 created 拿到的數據相同 在掛載開始以前被調用:相關的 render 函數首次被調用。

(4)mounted中el被建立dom已經更新,vue實例對象中有template參數選項,則將其做爲模板編譯成render函數,編譯優先級render函數選項 > template選項

使用場景:經常使用於獲取VNode信息和操做,ajax請求
複製代碼

(5)因爲beforeUpdate更新以前,和updated更新以後

(6)beforeDestroyed 和 destroyed 銷燬以前 銷燬以後

vue父子組件生命週期執行順序

父beforeCreate->

父created->

父beforeMount->

子beforeCreate->

子created->

子beforeMount->

子mounted->

父mounted。

組件間通信方法

父子組件 props

非父子組件 eventBus

vuex

路由傳參

vue.nextTick實現原理

diff算法大概思路

vue的響應式原理

虛擬dom的基本原理

如何設計一個組件

路由守衛怎麼用

不一樣權限顯示不一樣的菜單,怎麼實現

1.路由設置兩個對象,一個普通普通路由(沒有任何權限),一個動態路由,

2.路由守衛,監聽全部的路由走向,根據接口返回的路由name,遍歷動態路由的全部信息

3.一旦信息能匹配上,就使用addRouter動態添加異步路由。實現不一樣菜單權限展現

webpack

webpack必然會問,可是不會太深究,但是最基本的仍是要掌握的,好比什麼提升性能了,打包分割,loader做用,之類的

用過哪些loader和plugin

webpack的loader和plugin有上萬個,所有記住而且會使用是不可能的事情,因此就說說本身經常使用的幾個

  1. css-loader:負責解析 CSS 代碼,主要是爲了處理 CSS 中的依賴,例如 @import 和 url() 等引用外部文件的聲明

  2. style-loader 會將 css-loader 解析的結果轉變成 JS 代碼,運行時動態插入 style 標籤來讓 CSS 代碼生效。

  3. vue-loader 處理後綴vue文件,使其能夠正常解析使用

loader的執行順序爲何是後寫的先執行

先下後上,先右後左

webpack配置優化

webpack代碼分割怎麼實現

每次面試都會問,你是怎麼進行代碼分割的,如今終於能夠說出來了。

其實代碼分割跟webpack 並無實質聯繫。只是webpack 如今內置的插件能夠幫咱們進行代碼分割,全部就綁在一塊了。

webpack的代碼分割就是自帶的屬性optimization中的splitChunks各類屬性配置

Code Splitting 的核心是把很大的文件,分離成更小的塊,讓瀏覽器進行並行加載。

假如打包一個2m的文件。用戶加載就是2m的資源,若是是兩個1m的,瀏覽器能夠並行加載,速度就會很快

通常分割有三種:

手動進行分割:例如項目若是用到lodash,則把lodash單獨打包成一個文件。

同步導入的代碼:使用 Webpack 配置進行代碼分割。

異步導入的代碼:經過模塊中的內聯函數調用來分割代碼。
複製代碼

1.手動分割

module.exports = { entry: { main: './src/index.js', lodash: 'lodash' } 
複製代碼

本質就是多入口打包,

它輸出了兩個模塊,也能在必定程度上進行代碼分割,不過這種分割是十分脆弱的,若是兩個模塊共同引用了第三個模塊,那麼第三個模塊會被同時打包進這兩個入口文件中,而不是分離出來。(別用這個)

2.同步分割

有時候的代碼是同步方法,不存在異步方法的話,使用這個,可是誰的代碼裏面沒有異步的啊,這個用的也不是不少

module.exports = {
  // 其它配置
  optimization: {
    splitChunks: {
      chunks: 'initial'
    }
  }
}
複製代碼

3.異步分割

若是咱們只須要針對異步代碼進行代碼分割的話,咱們只須要進行異步導入,Webpack會自動幫咱們進行代碼分割,異步代碼分割它的配置以下:

module.exports = {
  // 其它配置
  optimization: {
    splitChunks: {
      chunks: 'async'
    }
  }
}
複製代碼

最後講解一下splitChunks屬性的用法

module.exports = {
 // 其它配置項
 optimization: {
   splitChunks: {
     chunks: 'async', // 異步仍是同步分割代碼
     minSize: 30000, // 若是模塊大於30k就開始分割。不然就不分割
     minChunks: 1, // 改模塊必須引用一次以上才分割
     maxAsyncRequests: 5, // 默認就好了
     maxInitialRequests: 3,// 默認就好了
     automaticNameDelimiter: '~',// 默認就好了
     name: true,
     cacheGroups: { 
       vendors: { //分組,若是模塊知足在module包裏面,就打包成vender.js形式
         test: /[\\/]node_modules[\\/]/,
         priority: -10// 值越大。越服從誰,好比一個loadsh的包,符合第一個組,也符合默認,就看priority的值,越大就打包到哪一個組
       },
       default: { //分組,若是模塊不在module包裏面,打包成default.js形式
         minChunks: 2,
         priority: -20,
         reuseExistingChunk: true // 若是一個模塊已經被打包了,在遇到的時候,就忽略掉,直接使用之前的包
       }
     }
   }
 }
};
複製代碼

sourceMap怎麼使用

1.什麼是sourcemap, 當你文件裏面的代碼出錯了,若是不配置sourceMap,會把報錯的信息體如今,壓縮完的代碼裏,這樣就很很差,找不到錯在哪裏了。 可是配置之後,會提示你錯在哪一個文件夾的哪一行,方便快速找到錯誤,映射錯誤文件

2.在module.exports裏面直接加上devtools:'sourceMap',能夠開啓這個功能,若是配置了sourcemap.打包的速度會變慢的。

3.使用sourcemap之後,你會發現,打包好的文件裏面,有個.js.map的映射文件

4.官方文檔 配置 裏面, 有個選項 devtool.裏面有很詳細的使用方法,

(1)sourceMap.打包出一個xx.js.map的文件

(2)inline-source-map,會把map的文件取消,轉換成一個base64的行字符串加在打包的js文件裏面.

(3)inline-cheap-source-map,上面的兩個會把哪一行,那一列錯的位置告訴咱們,可是這個會把那一列去到,提升性能。

(4)cheap-module-eval-source-map,開發使用這個最好,全面,速度還快一點 開發環境

(5)cheap-module-source-map,生產使用這個比較好,mode:producton 生產環境

webpack打包優化(happypack、dll)

plugin與loader的區別

  1. loader 用於加載某些資源文件。

    由於 webpack 只能理解 JavaScript 和 JSON 文件,對於其餘資源例如 css,圖片,或者其餘的語法集,好比 jsx, coffee,是沒有辦法加載的。 這就須要對應的loader將資源轉化,加載進來。從字面意思也能看出,loader是用於加載的,它做用於一個個文件上。

  2. plugin 用於擴展webpack的功能。

    它直接做用於 webpack,擴展了它的功能。固然loader也是變相的擴展了 webpack ,可是它只專一於轉化文件(transform)這一個領域。而plugin的功能更加的豐富,而不只侷限於資源的加載。

webpack執行的過程

如何編寫一個loader、plugin

tree-shaking做用,如何才能生效

開發中有這種問題,我在一個模塊裏面創建了是幾個方法,在其餘模塊裏面引入了其中一個方法,打包的時候咱們會發現模塊裏面的方法所有都在打包文件裏面,這樣沒有必要,

tree shaking 翻譯成漢語的意思是 搖樹的意思,意思是把我不須要引入的模塊去掉或者吧不須要模塊裏面的其餘方法去掉

webpack裏面寫入就能使用

optimization: {
    usedExports: true
},
複製代碼

可是會有一些問題,

例如import './style.css' 時,會起到反作用,css整個不引入

這個時候在package.json裏面設置,過濾掉全部的css。不被搖掉,polyfill也不被搖掉

"sideEffects": [ ".css", "@babel/polyfill" ],
複製代碼

框架不用腳手架,怎麼用webpack搭建一個基礎腳手架

相關文章
相關標籤/搜索