前端工程師面試必備(持續更新中)

css內容

響應式佈局

當前主流的三種預編譯器比較

  • CSS預處理器用一種專門的編程語言,進行Web頁面樣式設計,而後再編譯成正常的CSS文件,以供項目使用;
  • 讓你的CSS更加簡潔、適應性更強、可讀性更佳,更易於代碼的維護等諸多好處。

less,sass,stylus三者的區別

  • 1.變量:javascript

    • Sass聲明變量必須是『$』開頭,後面緊跟變量名和變量值,並且變量名和變量值須要使用冒號:分隔開。
    • Less 聲明變量用『@』開頭,其他等同 Sass。
    • Stylus 中聲明變量沒有任何限定,結尾的分號無關緊要,但變量名和變量值之間必需要有『等號』。
  • 2.做用域php

    • Sass:三者最差,不存在全局變量的概念。也就是說在 Sass 中定義了相同名字的變量時你就要當心蛋疼了。
    • Less:最近的一次更新的變量有效,而且會做用於所有的引用!
    • Stylus:Sass 的處理方式和 Stylus 相同,變量值輸出時根據以前最近的一次定義計算,每次引用最近的定義有效;
  • 3.嵌套:css

    • 三種 css 預編譯器的「選擇器嵌套」在使用上來講沒有任何區別,甚至連引用父級選擇器的標記 & 也相同。
  • 4.繼承:html

    • Sass和Stylus的繼承很是像,能把一個選擇器的全部樣式繼承到另外一個選擇器上。使用『@extend』開始,後面接被繼承的選擇器。Stylus 的繼承方式來自 Sass,二者一模一樣。
    • Less 則又「獨樹一幟」地用僞類來描述繼承關係;
  • 5.導入@Import:前端

    • Sass 中只能在使用 url() 表達式引入時進行變量插值:
    $device: mobile;
    @import url(styles.#{$device}.css);
    複製代碼
    • Less 中能夠在字符串中進行插值:
    @device: mobile;
    @import "styles.@{device}.css";
    複製代碼
    • Stylus 中在這裏插值無論用,可是能夠利用其字符串拼接的功能實現:
    device = "mobile"
    @import "styles." + device + ".css"
    複製代碼
  • 總結vue

    • 1.Sass和Less語法嚴謹、Stylus相對自由。由於Less長得更像 css,因此它可能學習起來更容易。
    • 2.Sass 和 Compass、Stylus 和 Nib 都是好基友。
    • 3.Sass 和 Stylus 都具備類語言的邏輯方式處理:條件、循環等,而 Less 須要經過When等關鍵詞模擬這些功能,這方面 Less 比不上 Sass 和 Stylus。
    • 4.Less 在豐富性以及特點上都不及 Sass 和 Stylus,若不是由於 Bootstrap 引入了 Less,可能它不會像如今這樣被普遍應用(我的愚見)。

link與@import區別與選擇

<style type="text/css">
	@import url(CSS文件路徑地址);
</style>
<link href="CSSurl路徑" rel="stylesheet" type="text/css" /
複製代碼
  • link功能較多,能夠定義 RSS,定義 Rel 等做用,而@import只能用於加載 css;
  • 當解析到link時,頁面會同步加載所引的 css,而@import所引用的 css 會等到頁面加載完才被加載;
  • @import須要 IE5 以上才能使用;
  • link可使用 js 動態引入,@import不行;

垂直居中佈局

css經典佈局系列一——垂直居中佈局java

css3的高級特性舉例

h5新增了哪些內容或者API,使用過哪些?

1像素邊框問題

什麼是BFC

BFC是什麼

  • BFC 英文解釋: block formatting context。中文意思:塊級格式化上下文;
  • formatting context 意思是:頁面中一個渲染區域,有本身的一套渲染規則,決定其子元素如何定位,以及和其餘兄弟元素的關係和做用。
  • BEC有以下特性
    • 內部的box會在垂直方向,從頂部開始一個接一個地放置;
    • box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰的box的margin會發生摺疊;
    • 每個元素的margin box的左遍,與包含塊border box的左邊相接觸。即便浮動元素也是如此;
    • BFC區域不會與float box疊加;
    • 計算 BFC 的高度時,浮動子元素也參與計算;
    • 文字層不會被浮動層覆蓋,環繞於周圍

產生BFC 做用的css 屬性

  • float 除了none之外的值;
  • overflow 除了visible 之外的值(hidden,auto,scroll );
  • display (table-cell,table-caption,inline-block, flex, inline-flex);
  • position值爲(absolute,fixed) 這些屬性值得元素都會自動建立 BFC;

BFC做用

  • BFC 最大的一個做用就是:在頁面上有一個獨立隔離容器,容器內的元素 和 容器 外的元素佈局不會相互影響。
    • 解決上外邊距重疊;重疊的兩個box都開啓bfc;
    • 解決浮動引發高度塌陷;容器盒子開啓bfc;
    • 解決文字環繞圖片;左邊圖片div,右邊文本容器p,將p容器開啓bfc;

js基礎

for...in和for...of區別

  • for...in
    • 1.循環出來的是index索引,是字符串型的數字;
    • 2.遍歷順序有可能不是按照實際數組的內部順序;
    • 3.使用for in會遍歷數組全部的可枚舉屬性,包括原型上的以及數組自定義的屬性;
    • 因此for in更適合遍歷對象,不要使用for in遍歷數組。
  • 推薦在循環對象屬性的時候,使用for...in,在遍歷數組的時候的時候使用for...of;
  • for...in循環出的是key,for...of循環出的是value;
  • 注意,for...of是ES6新引入的特性。修復了ES5引入的for...in的不足;
  • for...of不能循環普通的對象,須要經過和Object.keys()搭配使用;
Object.prototype.objCustom = function () {}; 
Array.prototype.arrCustom = function () {};

let iterable = [3, 5, 7];
iterable.foo = "hello";

for (let i in iterable) {
  console.log(i); // logs 0, 1, 2, "foo", "arrCustom", "objCustom"
}

for (let i of iterable) {
  console.log(i); // logs 3, 5, 7
}
複製代碼

script 引入方式:

  • html 靜態',則只是在dom中插入了一行字符串,就更不會管字符串裏引入的js了,因此不能用這個方法插入script!!!
  • 2.各個js文件的加載時機(script標籤插入文檔的時機順序)
    • 好比: 1.js 依賴 2.js,2.js 依賴 3.js;實際的加載順序是爲 1.js,2.js,3.js
    • 注意: 而實際模塊運行的順序,纔是 3.js,2.js,1.js。因此,文件的加載、加載後文件的運行、模塊的運行,這是 3 個東西啊,別混了。
  • 3.文件模塊的執行時機
    // 1.js 中的代碼
    require([], functionA() {
        // 主要邏輯代碼
    })
    複製代碼
    • 文件的加載:將<script src='1.js'>節點插入dom中,以後,下載 1.js 文件;
    • 加載後文件的運行:1.js 文件加載完後,執行 1.js 中的代碼,即執行 require() 函數!!!
    • 模塊的運行: require回調函數,上方的,主要邏輯代碼,所在的函數,functionA,的運行!!!
    • 文件加載/文件運行 順序: 1.js , 2.js , 3.js;
    • 模塊運行 順序:3.js , 2.js , 1.js;
  • webpack對比requirejs

    • webpack在管理模塊的時候不須要再封裝一層像requireJS以下的東西
    define(['jquery'], function(jquery){})  
    複製代碼
    • 它實現了前端代碼模塊化,提升了代碼的複用性,從而提供公共模塊的緩存功能。
      • webpack經過打包,不一樣頁面單獨加載本身的模塊的javascript 和 common javascript,而requireJS將全部的javascript文件打包成一個文件,使得一個站點中多個頁面之間公用的JS模塊沒法緩存。
      • Webpack 引入了切分點(split point)與代碼塊(Chunk),切分點定義了全部依賴的模塊,合起來就是一個代碼塊,從而實現一個頁面引用一個代碼塊。

    主流框架Vue

    vue2中的diff算法是怎樣實現的?

    虛擬dom過程

    diff流程

    • patch函數接收兩個參數oldVnode和Vnode分別表明新的節點和以前的舊節點
      • 判斷兩節點是否值得比較,值得比較則執行patchVnode;
      • 不值得比較則用Vnode替換oldVnode;
    • patchVnode:當咱們肯定兩個節點值得比較以後咱們會對兩個節點指定patchVnode方法;
      • 找到對應的真實dom,稱爲el;
      • 判斷Vnode和oldVnode是否指向同一個對象,若是是,那麼直接return;
      • 若是他們都有文本節點而且不相等,那麼將el的文本節點設置爲Vnode的文本節點;
      • 若是oldVnode有子節點而Vnode沒有,則刪除el的子節點;
      • 若是oldVnode沒有子節點而Vnode有,則將Vnode的子節點真實化以後添加到el;
      • 若是二者都有子節點,則執行updateChildren函數比較子節點,這一步很重要;
    • updateChildren函數圖解

    圖示

    • 如今分別對oldS、oldE、S、E兩兩作sameVnode比較,有四種比較方式,當其中兩個能匹配上那麼真實dom中的相應節點會移到Vnode相應的位置,這句話有點繞,打個比方:
      • 若是是oldS和E匹配上了,那麼真實dom中的第一個節點會移到最後;
      • 若是是oldE和S匹配上了,那麼真實dom中的最後一個節點會移到最前,匹配上的兩個指針向中間移動;
      • 若是四種匹配沒有一對是成功的,那麼遍歷oldChild,S挨個和他們匹配,匹配成功就在真實dom中將成功的節點移到最前面,若是依舊沒有成功的,那麼將S對應的節點插入到dom中對應的oldS位置,oldS和S指針向中間移動。

    vue雙向數據綁定

    • vue.js 是採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。
    • 第一步:須要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter。這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化;
    • 第二步:compile解析模板指令,將模板中的變量替換成數據,而後初始化渲染頁面視圖,並將每一個指令對應的節點綁定更新函數,添加監聽數據的訂閱者,一旦數據有變更,收到通知,更新視圖;
    • 第三步:Watcher訂閱者是Observer和Compile之間通訊的橋樑,主要作的事情是:
      • 一、在自身實例化時往屬性訂閱器(dep)裏面添加本身
      • 二、自身必須有一個update()方法
      • 三、待屬性變更dep.notice()通知時,能調用自身的update()方法,並觸發Compile中綁定的回調,則功成身退。
    • 第四步:MVVM做爲數據綁定的入口,整合Observer、Compile和Watcher三者,經過Observer來監聽本身的model數據變化,經過Compile來解析編譯模板指令,最終利用Watcher搭起Observer和Compile之間的通訊橋樑,達到數據變化 -> 視圖更新;視圖交互變化(input) -> 數據model變動的雙向綁定效果。

    細節點詢問

    • 基於vue數據綁定,若是data中的數據進行了一秒1000次的改變,每次改變會所有顯示在頁面中嗎?

    vue生命週期的執行過程

    • 首先建立一個vue實例,Vue();
    • 在建立Vue實例的時候,執行了init(),在init過程當中首先調用了beforeCreate。
    • Created以前,對data內的數據進行了數據監聽,而且初始化了Vue內部事件。具體以下:
      • 完成了數據觀測;
      • 完成了屬性和方法的運算;
      • 完成了watch/event事件的回調;
      • 可是此時還未掛載dom上,$el屬性是不可見的;
    • beforeMount以前,完成了模板的編譯。把data對象裏面的數據和vue的語法寫的模板編譯成了html,可是此時尚未將編譯出來的html渲染到頁面;
      • 一、在實例內部有template屬性的時候,直接用內部的,而後調用render函數去渲染。
      • 二、在實例內部沒有找到template,就調用外部的html(「el」option(選項))。實例內部的template屬性比外部的優先級高。 render函數 > template屬性 > 外部html;
      • 三、要是前二者都不知足,那麼就拋出錯誤。
    • Mounted以前執行了render函數,將渲染出來的內容掛載到了DOM節點上。mounted是將html掛載到頁面完成後觸發的鉤子函數;當mounted執行完畢,整個實例算是走完了流程;在整個實例過程當中,mounted僅執行一次;
    • beforeUpdate:數據發生變化時,會調用beforeUpdate,而後經歷virtual DOM,最後updated更新完成;
    • beforeDestory是實例銷燬前鉤子函數,銷燬了全部觀察者,子組件以及事件監聽;
    • destoryed實例銷燬執行的鉤子函數;

    總結

    • beforeCreate:初始化了部分參數,若是有相同的參數,作了參數合併,執行 beforeCreate;el和數據對象都爲undefined,還未初始化;
    • created :初始化了 Inject 、Provide 、 props 、methods 、data 、computed 和 watch,執行 created ;data有了,el尚未;
    • beforeMount :檢查是否存在 el 屬性,存在的話進行渲染 dom 操做,執行 beforeMount;$el和data都初始化了,可是dom仍是虛擬節點,dom中對應的數據尚未替換;
    • mounted :實例化 Watcher ,渲染 dom,執行 mounted ;vue實例掛載完成,dom中對應的數據成功渲染;
    • beforeUpdate :在渲染 dom 後,執行了 mounted 鉤子後,在數據更新的時候,執行 beforeUpdate ;
    • updated :檢查當前的 watcher 列表中,是否存在當前要更新數據的 watcher ,若是存在就執行 updated ;
    • beforeDestroy :檢查是否已經被卸載,若是已經被卸載,就直接 return 出去,不然執行 beforeDestroy ;
    • destroyed :把全部有關本身痕跡的地方,都給刪除掉;

    Vue.js的template編譯

    const ast = parse(template.trim(), options) // 構建抽象語法樹
    optimize(ast, options) // 優化
    const code = generate(ast, options) // 生成代碼
    return {
        ast,
        render: code.render,
        staticRenderFns: code.staticRenderFns
    }
    複製代碼
    • 能夠分紅三部分
      • 將模板轉化爲抽象語法樹;
      • 優化抽象語法樹;
      • 根據抽象語法樹生成代碼;
    • 具體作了什麼
      • 第一部分其實就是各類正則了,對左右開閉標籤的匹配以及屬性的收集,經過棧的形式,不斷出棧入棧去匹配以及更換父節點,最後生成一個對象,包含children,children又包含children的對象;
      • 第二部分則是以第一部分爲基礎,根據節點類型找出一些靜態的節點並標記;
      • 第三部分就是生成render函數代碼了
    • 簡言之,就是先轉化成AST樹,再獲得的render函數返回VNode(Vue的虛擬DOM節點);
    • 回答:
      • 首先,經過compile編譯器把template編譯成AST語法樹(abstract syntax tree 即 源代碼的抽象語法結構的樹狀表現形式),compile是createCompiler的返回值,createCompiler是用以建立編譯器的。另外compile還負責合併option。
      • 而後,AST會通過generate(將AST語法樹轉化成render funtion字符串的過程)獲得render函數,render的返回值是VNode,VNode是Vue的虛擬DOM節點,裏面有(標籤名、子節點、文本等等);

    數據到視圖的總體流程

    • 在組件級別,vue會執行一個new Watcher;
    • new Watcher首先會有一個求值的操做,它的求值就是執行一個函數,這個函數會執行render,其中可能會有編譯模板成render函數的操做,而後生成vnode(virtual dom),再將virtual dom應用到視圖中;
    • 其中將virtual dom應用到視圖中(這裏涉及到diff後文會講),必定會對其中的表達式求值(好比{{message}},咱們確定會取到它的值再去渲染的),這裏會觸發到相應的getter操做完成依賴的收集;
    • 當數據變化的時候,就會notify到這個組件級別的Watcher,而後它還會去求值,從而從新收集依賴,而且從新渲染視圖;

    vue的computed和watch區別

    • computed 是計算一個新的屬性,並將該屬性掛載到 vm(Vue 實例)上,而 watch 是監聽已經存在且已掛載到 vm 上的數據,因此用 watch 一樣能夠監聽 computed 計算屬性的變化(其它還有 data、props)
    • computed 本質是一個惰性求值的觀察者,具備緩存性,只有當依賴變化後,第一次訪問 computed 屬性,纔會計算新的值,而 watch 則是當數據發生變化便會調用執行函數
    • 從使用場景上說,computed 適用一個數據被多個數據影響,而 watch 適用一個數據影響多個數據;

    computed的原理,是如何和被計算的數據聯繫起來的

    • 須要考慮
      • 如何與其餘的屬性創建聯繫的;
      • 屬性改變後,如何通知計算屬性從新計算的;
    • 初始化data時,會使用Object.defineProperty 對全部的屬性數據劫持;
    • 初始化computed,會遍歷全部的computed,對每個計算屬性會調用initComputed函數,生成watcher實例;
    • watcher實例中會進行依賴收集;
    • computed計算時:
      • 會將當前的watcher實例賦給 Dep.target;
      • 執行計算屬性的getter方法;
      • 去讀取被計算的屬性時,就會觸發這些被計算屬性的相應getter方法。當斷定被計算的屬性是計算屬性的相關依賴時,就會去創建依賴關係,既將計算屬性的watcher添加到這些被計算屬性的watcher內的消息訂閱器dep中。
    • 完成以後將Dep.target 賦爲 null 並返回求值函數結果。

    vue組件間的七種交互

    • 1.props和$emit
      • 父組件向子組件傳遞數據是經過prop傳遞的,子組件傳遞數據給父組件是經過$emit觸發事件來作到的。
    • 2.特性綁定$attrs和$listeners
      • 若是父組件A下面有子組件B,組件B下面有組件C,這時若是組件A想傳遞數據給組件C怎麼辦呢? 若是繼續用上面的方法,會變得很是複雜,不利於維護;Vue 2.4開始提供了$attrs和$listeners來解決這個問題,可以讓組件A之間傳遞消息給組件C。
    • 3.中央事件總線 Events Bus
      • 新建一個Vue事件bus對象,而後經過bus.$emit觸發事件,bus.$on監聽觸發的事件。
    • 4.依賴注入:provide和inject
      • 父組件中經過provider來提供變量,而後在子組件中經過inject來注入變量。
      • 不論子組件有多深,只要調用了inject那麼就能夠注入provider中的數據。而不是侷限於只能從當前父組件的prop屬性來獲取數據,只要在父組件的生命週期內,子組件均可以調用。
      // 父組件
      name: "Parent",
      provide: {
      for: "demo"
      },
      components:{
      childOne
      }
      // 子組件
      name: "childOne",
      inject: ['for'],
      data() {
      return {
        demo: this.for
      }
      },
      components: {
      childtwo
      }
      複製代碼
    • 5.v-model
      • 父組件經過v-model傳遞值給子組件時,會自動傳遞一個value的prop屬性,在子組件中經過this.$emit(‘input’,val)自動修改v-model綁定的值
    • 子組件引用:ref和$refs
    • 7.父鏈和子索引:$parent和$children
    • 8.vue1中boradcast和dispatch
      • vue1.0中提供了這種方式,但vue2.0中沒有,但不少開源軟件都本身封裝了這種方式,好比min ui、element ui和iview等。
    • 9.vuex
      圖示

    組件之間通訊使用的設計模式?

    • 目前尚未答案~~~~(阿里電話面試的一個問題)

    vuex原理

    • vuex的state是藉助vue的響應式data實現的。
    // 使用 this.$store.getters.xxx 獲取 xxx 屬性時,其實是獲取的store._vm.data.$$state 對象上的同名屬性
    get state () {
    	return this._vm._data.$$state
    }
    // 處理state 和 getter的核心函數resetStoreVM(this, state)
    store._vm = new Vue({
    	data: {
    	  $$state: state
    	}
    })
    // 因爲vue的data是響應式的,因此,$$state也是響應式的,那麼當咱們 在一個組件實例中 對state.xxx進行 更新時,基於vue的data的響應式機制,全部相關組件的state.xxx的值都會自動更新,UI天然也會自動更新
    複製代碼
    • getter是藉助vue的計算屬性computed特性實現的。
    // wrappedGetters方法
    const computed = {};
    // 處理getters
    forEachValue(wrappedGetters, (fn, key) => {
        computed[key] = () => fn(store) // 將getter存儲在computed上
        //this.$store.getters.XXX的時候獲取的是store._vm.XXX
        Object.defineProperty(store.getters, key, {
          get: () => store._vm[key], 
          enumerable: true
        })
    })
    複製代碼
    • 其設計思想與vue中央事件總線一模一樣。中央事件總線的實現,簡單講就是新建了一個vue對象,藉助vue對象的特性(emit 與on) 做爲其餘組件的通訊橋樑,實現組件間的通訊 以及數據共享!

    Vue-router 中hash模式和history模式的區別

    • hash模式url裏面永遠帶着#號,咱們在開發當中默認使用這個模式。那麼何時要用history模式呢?若是用戶考慮url的規範那麼就須要使用history模式,由於history模式沒有#號,是個正常的url適合推廣宣傳。
    • 固然其功能也有區別,好比咱們在開發app的時候有分享頁面,那麼這個分享出去的頁面就是用vue或是react作的,我們把這個頁面分享到第三方的app裏,有的app裏面url是不容許帶有#號的,因此要將#號去除那麼就要使用history模式,可是使用history模式還有一個問題就是,在訪問二級頁面的時候,作刷新操做,會出現404錯誤,那麼就須要和後端人配合讓他配置一下apache或是nginx的url重定向,重定向到你的首頁路由上就ok啦。
    • 路由的哈希模式實際上是利用了window能夠監聽onhashchange事件,也就是說你的url中的哈希值(#後面的值)若是有變化,前端是能夠作到監聽並作一些響應(搞點事情),這麼一來,即便前端並無發起http請求他也可以找到對應頁面的代碼塊進行按需加載。
    • pushState與replaceState,這兩個神器的做用就是能夠將url替換而且不刷新頁面,比如掛羊頭賣狗肉,http並無去請求服務器該路徑下的資源,一旦刷新就會暴露這個實際不存在的「羊頭」,顯示404。這就須要服務器端作點手腳,將不存在的路徑請求重定向到入口文件(index.html)。

    自定義組件

    • index.js:index.js文件幫咱們把全部自定義的組件都經過Vue.component註冊了,最後export一個包含install方法的對象給Vue.use()使用。

    • 統一導入
    import global from './components/global/index.js'
    Vue.use(global)
    複製代碼

    計算機網絡

    http 狀態碼的分類?什麼是無狀態?

    • http無狀態
      • 服務器中沒有保存客戶端的狀態,客戶端必須每次帶上本身的狀態去請求服務器;
      • 每次的請求都是獨立的,<它的執行狀況和結果>與<前面的請求>和<以後的請求>是無直接關係的
    • 狀態碼分類
      • 1XX指示信息,表示信息已接收,繼續處理;
      • 2XX成功-表示請求已被成功接收;
      • 3XX重定向,表示要完成請求進行更進一步操做;
      • 4XX客戶端錯誤,請求依法錯誤或請求沒法實現;
      • 5XX服務器端錯誤,服務器未能實現合法請求;
      • 舉例:
        • 200,請求成功;
        • 302:重定向;
        • 304:上次請求後頁面未修改;
        • 400:客戶端請求語法錯誤;
        • 401:權限問題;
        • 403,服務器接受請求,但拒絕提供服務;
        • 404,請求資源未存在;
        • 500,服務器內部錯誤;

    http 1.1 與 http 2 的區別

    • HTTP/2採用二進制格式而非文本格式
      • 比起像HTTP/1.x這樣的文本協議,二進制協議解析起來更高效、「線上」更緊湊,更重要的是錯誤更少。
    • HTTP/2是徹底多路複用的,而非有序並阻塞的——只需一個鏈接便可實現並行
      • HTTP/1.x 有個問題叫線端阻塞(head-of-line blocking), 它是指一個鏈接(connection)一次只提交一個請求的效率比較高, 多了就會變慢。 HTTP/1.1 試過用流水線(pipelining)來解決這個問題, 可是效果並不理想(數據量較大或者速度較慢的響應, 會阻礙排在他後面的請求). 此外, 因爲網絡媒介(intermediary )和服務器不能很好的支持流水線, 致使部署起來困難重重。而多路傳輸(Multiplexing)能很好的解決這些問題, 由於它能同時處理多個消息的請求和響應; 甚至能夠在傳輸過程當中將一個消息跟另一個摻雜在一塊兒。因此客戶端只須要一個鏈接就能加載一個頁面。
    • 使用報頭壓縮,HTTP/2下降了開銷
      • HTTP2經過gzip和compress壓縮頭部而後再發送,同時客戶端和服務器端同時維護一張頭信息表,全部字段都記錄在這張表中,這樣後面每次傳輸只須要傳輸表裏面的索引Id就行,經過索引ID就能夠知道表頭的值了
    • HTTP/2讓服務器能夠將響應主動「推送」到客戶端緩存中
      • HTTP2支持在客戶端未經請求許可的狀況下,主動向客戶端推送內容

    post和get請求的區別

    基本區別

    • 應用:表單的method屬性設置post時發送的是post請求,其他都是get請求(沒有考慮AJAX);
    • 傳參方式:get請求經過url地址發送請求參數,post請求經過請求體發送請求參數;
    • 安全性:get請求直接經過url地址發送請求參數,參數在地址欄可見,不太安全;post請求經過請求體發送請求參數,參數在地址欄不可見,相對安全;
    • 大小限制:get請求直接經過url地址發送請求參數,url地址的長度限制在255字節內,因此get請求不能發送過多的參數,post請求經過請求體發送參數,長度沒有限制。
      • Get方法提交的數據大小長度並無限制,而是IE瀏覽器自己對地址欄URL長度(5.7備註:是瀏覽器對請求頭有限制,不能超過多少~~~)有最大長度限制:2048個字符。

    高級區別

    • GET 的本質是「得」,而 POST 的本質是「給」。GET 的內容能夠被瀏覽器緩存,而 POST 的數據不能夠。
    • 1.get產生一個TCP數據包,一個是請求頭,一個請求體的;post產生兩個TCP數據包;
    • 2.在一次請求中,get一次性完成,post在部分瀏覽器(除了火狐)須要發送兩次信息,因此get比post更快,更有效率。

    什麼是跨域,解決跨域的方法及原理是什麼?

    • 1.不一樣源就是跨域
    • 2.同源策略是瀏覽器的一種安全策略
    • 3.協議,域名,端口號徹底相同就是同源,只要有一處不同就是跨域
    • 4.特例: ajax在判斷域名的時候只能解析字符串,致使(localhost和127.0.0.1)在它看來也是跨域請求
    • 5.解決跨域的方式一般用cors和jsonp
    • 6.JSONP
      • 1.JSONP是一種技巧,不是一門新的技術
      • 2.利用scirpt標籤的src屬性不受跨域的限制的特色
      • 3.解決跨域:
        • 1.瀏覽器端:動態生成script標籤,提早定義好回調函數,在合適的時機添加src屬性指定請求的地址。
        • 2.服務器端:後臺接收到回調函數,將數據包括在回調函數調用的句柄中,一塊兒返回。
        • 3.只支持get請求
    function jsonp({url,params,callback}){
      return new Promise((resolve,reject)=>{
        // 建立srcipt
        let script = document.createElement("script")
        window[callback] = function(data){
          resolve(data)
          document.body.removeChild(script)
        }
        // 參數從新格式化
        params = {...params,callback} // wd=b&callback=show
        let arrs = []
        for(let key in params){
          arrs.push(`${key}=${params[key]}`)
        }
        // 後臺獲取數據的接口拼接上參數
        script.src = `${url}?${arrs.join('&')}`
        // srcipt插入
        document.body.appendChild(script)
      })
    }
    jsonp({
      url: 'http://localhost:3000/say',
      params: { wd: 'Iloveyou' },
      callback: 'show'
    }).then(data=>{
      console.log(databufen)
    })
    複製代碼
    • 7.CORS
      • 1.瀏覽器端什麼也不用幹;
      • 2.服務器端設置響應頭:Access-Control-Allow-Origin
      • 3.cors是一門技術,在本質上讓ajax引擎容許跨域
      • 4.get和post請求都支持

    爲何cros能解決跨域?// TODO

    • 和第一次發送的option請求有關;
    • 跨域時,瀏覽器會攔截Ajax請求,並在http頭中加Origin。

    瀏覽器問題

    瀏覽器緩存

    客戶端兩種存儲

    sessionStorage用法和localStorage區別

    • 生命週期:
      • localStorage(本地存儲)生命週期是永久,這意味着除非用戶顯示在瀏覽器提供的UI上清除localStorage信息,不然這些信息將永遠存在。
      • sessionStorage(會話存儲)生命週期爲當前窗口或標籤頁,一旦窗口或標籤頁被關閉了,那麼全部經過sessionStorage存儲的數據也就被清空了。
    • 做用域不一樣:不一樣瀏覽器沒法共享localStorage或sessionStorage中的信息。
    • 相同瀏覽器的不一樣頁面間能夠共享相同的 localStorage(頁面屬於相同域名和協議,主機和端口);
      • 不一樣頁面或標籤頁間沒法共享sessionStorage的信息。
      • localStorage只要在相同的協議、相同的主機名、相同的端口下,就能讀取/修改到同一份localStorage數據。
      • sessionStorage比localStorage更嚴苛一點,除了協議、主機名、端口外,還要求在同一窗口(也就是瀏覽器的標籤頁)下。
    • 存儲大小:localStorage和sessionStorage的存儲數據大小通常都是:5MB;
    • 存儲位置:localStorage和sessionStorage都保存在客戶端,不與服務器進行交互通訊。
    • 存儲內容類型:localStorage和sessionStorage只能存儲字符串類型,對於複雜的對象可使用ECMAScript提供的JSON對象的stringify和parse來處理;
    • 獲取方式:localStorage:window.localStorage;sessionStorage:window.sessionStorage;
    • 應用場景:localStoragese:經常使用於長期登陸(+判斷用戶是否已登陸),適合長期保存在本地的數據;sessionStorage:敏感帳號一次性登陸。

    localStorage和cookie選擇使用的標準是什麼

    • 應該是和服務端有關,
    • cookie每次的發送請求是被默認帶上的,可是東西存在localstorage是沒有帶上的,須要寫進去;

    session的生命週期爲何只在一次會話中?

    • 至今沒有詳細的答案~~當時的回答以下:
    • session是服務端的;它用來和客戶端的cookie進行匹配,說它一次會話保存的意思是sessionID每次會話都是一個新的,可是session一直是有的。

    Cookie存儲和Web Storage存儲區別

    • localStorage與sessionStorage做爲新時代的產物,相比舊時代的cookie有其巨大的優越性。優越性有三:
      • 其一在能存儲的數據量,cookie最大能存儲4kb的數據,而localStorage與sessionStorage最大能存儲5Mb,目前各大瀏覽器支持的標準都是如此;
      • 其二在功能上,cookie只能存儲String類型的數據,以往要將用戶數據存儲在本地,須要將數據拼接成字符串,再存進cookie,取數據的時候一樣麻煩,先將整個cookie對象拿到(String對象),再按拼接的規則拆分,再拿須要的數據,存取都很麻煩! localStorage與sessionStorage不只支持傳統的String類型,還能夠將json對象存儲進去,存取數據都方便很多,json的優越性就不贅述,localStorage與sessionStorage無疑更現代化;
      • 其三是cookie是不可或缺的,cookie的做用是與服務器進行交互,做爲http規範的一部分而存在;而web storage僅僅是爲了在本地‘存儲’而生;
      • 其四在語義層面上,localStorage與sessionStorage語法更優雅、簡便。
      //cookie的操做
      設置cookie: document.cookie = 'key=value';
      獲取cookie: document.cookie;
      刪除cookie: document.cookie = "key=value;max-age=0";
      設置max-age存儲期限: document.cookie = "key=value;max-age=1000"; // 1000秒
      
      //web storage操做
      保存數據 setItem(key,value)
      讀取數據 getItem(key)
      刪除單個數據 removeItem(key)
      清空所有數據 clearItem()
      獲取數據索引 key(index)
      複製代碼

    瀏覽器內核?以及常見的瀏覽器兼容問題

    • 瀏覽器內核
      • Trident(IE內核):以IE爲表明,IE六、IE七、IE8(Trident 4.0)、IE9(Trident 5.0)、IE10(Trident 6.0)。
      • Gecko(Firefox內核): Gecko 內核的瀏覽器仍是Firefox (火狐) 用戶最多,因此有時也會被稱爲Firefox內核。
      • webkit(Safari內核,Chrome內核原型,開源):它是蘋果公司本身的內核,也是蘋果的Safari瀏覽器使用的內核。 Apple Safari也會用。
      • presto(Opera前內核) (已廢棄): Opera12.17及更早版本曾經採用的內核,現已中止開發並廢棄。Opera現已改用Google Chrome的Blink內核。

    常見的瀏覽器兼容問題

    HTML中的兼容問題
    • 不一樣瀏覽器的標籤默認的外補丁和內補丁不一樣;
      • 場景:隨便寫幾個標籤,不加樣式控制的狀況下,各自的margin 和padding差別較大。
      • 解決方法:上來先消除默認樣式*{margin:0;padding:0;};
    • 塊屬性標籤float後,又有橫行的margin狀況下,在IE6顯示margin比設置的大(即雙倍邊距bug);
      • 場景:常見症狀是IE6中後面的一塊被頂到下一行;
      • 解決方法:在float的標籤樣式控制中加入 display:inline;將其轉化爲行內屬性
    • IE6中 z-index失效
      • 場景:元素的父級元素設置的z-index爲1,那麼其子級元素再設置z-index時會失效,其層級會繼承父級元素的設置,形成某些層級調整上的BUG;
      • 緣由:z-index起做用有個小小前提,就是元素的position屬性要 是relative,absolute或是fixed。
      • 解決方案:1.position:relative改成position:absolute;2.去除浮動;3.浮動元素添加position屬性(如relative,absolute等)。
    • 在寫a標籤的樣式,寫的樣式沒有效果,其實只是寫的樣式被覆蓋了
      • 正確的a標籤順序應該:link/ visited/hover/active
    • 24位的png圖片,ie6中不兼容透明底兒
      • 解決方式:使用png透明圖片唄,可是須要注意的是24位的PNG圖片在IE6是不支持的,解決方案有兩種:
        • 使用8位的PNG圖片;
        • 爲IE6準備一套特殊的圖片
    js在不一樣瀏覽器中的兼容問題
    • 事件監聽的兼容;
      • IE不支持addEventListener;
      • 解決:給IE使用attachEvent
    var addHandler = function(el, type, handler, args) {
        if (el.addEventListener) {
            el.addEventListener(type, handler, false);
        } else if (el.attachEvent) {
            el.attachEvent('on' + type, handler);
        } else {
            el['on' + type] = handler;
        }
    };
    var removeHandler = function(el, type, handler, args) {
        if (el.removeEventListener) {
            el.removeEventListener(type, handler, false);
        } else if (el.detachEvent) {
            el.detachEvent('on' + type, handler);
        } else {
            el['on' + type] = null;
        }
    };
    複製代碼
    • event.target的兼容,引起事件的DOM元素。
      • IE6789不支持event.target;
      • 解決方法:event.srcElement;
    // 如下爲兼容寫法
    target = event.target || event.srcElement;
    複製代碼
    • 阻止系統默認的兼容
      • IE6789不支持event.preventDefault;
    // 如下爲兼容寫法
    event.preventDefault ? event.preventDefault() : (event.returnValue = false);
    複製代碼
    • 阻止事件冒泡的兼容
      • IE6789不支持event.stopPropagation;
    // 如下爲兼容寫法
    event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = false);
    複製代碼

    業務問題

    360搜索圖片這種的瀑布流佈局

    圖片懶加載

    • 高逼格方法:getBoundingClientRect()直接獲取元素到頂部的距離。
    • 緣由:在頁面中咱們每每須要放上不少張圖,性能是個大問題,一次性加載全部圖片通常都會卡好久,所以,在須要預覽的時候再加載,是一個很好的解決方案。
    • 思路:當圖片出如今瀏覽器可視區域中時,再把圖片的url傳給它,也能夠在這個時候建立圖片,而圖片被包裹在一個容器中,好比li或div,圖片的url放在其容器的自定義屬性data-src中;
    • 過程:
      • 給img標籤的元素添加一個自定義屬性,好比data-src,而真正的src設置爲空;
      • 判斷圖片距離頁面頂端的距離小於瀏覽器滾動距離加上可視區域高度,即它出如今可視區域時就加載他;
      // h = window.innerHeight——可視區域高度
      // s = document.documentElement.scrollTop || document.body.scrollTop——滾動距離;
      // getTop(imgs[i])經過getBoundingClientRect()獲取當前圖片距離頂端的高度
      if (h + s > getTop(imgs[i]) && !imgs[i].getAttribute('src'))
      複製代碼
      • 加載圖片imgs[i].src = imgs[i].getAttribute('data-src');
      • 最後在把頁面滾動函數賦值給元素window.onload,在全部元素加載完之後再進行操做,這一步很重要!
      window.onload = window.onscroll = function () {
      	 // 懶加載的函數
       lazyLoad(imgs);
      }
      複製代碼

    項目中碰見的問題

    ajax中使用get的問題

    • 問題一. 緩存:當每次訪問的url相同,客戶端直接讀取本地緩存裏面的內容,即便後臺數據變化前臺也不會有變化;
      • 解決方法:在?後面連接一個num=【隨機數Math.random()】或者num=【時間戳new Date().getTime()】,'1.php?username="May"&'+num(這裏沒有變量名,避免和後臺參數衝突)

    性能優化

    • 雪碧圖
    • 減小dom操做:事件代理,fragment;
    • 壓縮js和css,html;

    主流框架問題

    vue、react和angular區別

    • 借鑑angular的模板和數據綁定技術;
    • 借鑑react的組件化和虛擬DOM技術;
    • 體積下, 運行效率高, 編碼簡潔, PC/移動端開發都合適;
    • 它自己只關注UI, 能夠輕鬆引入vue插件和其它第三庫開發項目;

    編碼題(字節跳動的視頻面試)

    • 第一題:定義一個Queue類,第一次調用能夠隔1000秒輸出1,,第二次調用能夠隔2000秒輸出2...最後能夠調用run();
    new Queue()
    .task(() => {
        console.log(1)
    }, 1000) .task(() => {
    console.log(2)
    }, 2000) .task(() => {
    console.log(3)
    }, 3000) .run()
    複製代碼
    • 第二題:定義一個函數,求和函數,能夠無數次調用,而且在最後調用valueOf顯示最終求和結果;
    sum(1)(2)(3)(4).valueOf() 
    複製代碼
    • 第三題:第一步Promise+axios實現併發請求;寫完以後,要求再在此基礎上實現每次都併發5個請求(不會~~~);
    //  Promise+axios實現併發請求
    // 實現併發5次請求
    
    // 第一個答案
    function getRequest(){
        return axios.get(url)
    };
    function postrequest(){
        return axios.post(url)
    };
    axios.all([getRequest(),postrequest()])
    .then() 
    複製代碼
    • 最近面試的一個整理狀況,有些是面試中被問到的,有些是看文章時遇到感受頗有可能會問到的。有的有答案,有的尚未答案,沒答案的緣由有兩種的:一種是常見的問題,但願能閒下來以後詳細整理一下更高逼格的答案;另外一種是目前尚未解決,可是會在面試告一段落以後再研究研究給出答案,也特別歡迎你們在留言上給出這些題的答案或者思路。
    • 有同窗在評論中說了感受題比較簡單,我想說,看到好多題的時候我也是這麼感受得,可是,可能後面就會往深層次問你了。
    • 好比:new或者instanceof的實現原理?第二問就是:請手寫一個new或者instanceof;再好比,cookie和session區別,第二問就是:從服務端的角度來講一下cookie和session區別把?而後:爲何session只在一次回話有效,他是服務器的一個字段嗎?仍是服務器的什麼?再來,瞭解vue組件通訊嗎?第二問就是:請說出這些組件通訊的設計模式用了哪些?最後,用過npm和yarn嗎?第二問:大家是如何解決npm包的版本依賴的?package-lock的原理是什麼?
    • 我想說的是,文字能呈現的東西很簡單,可是想深究的話,深無底線~~~ 這些很大的目的是做個記錄,能夠在面試上樓前再瞜一眼~~~ 工程師們在工做中必定要時刻保持能夠離開的資本啊,知其然而且知其因此然!另外,面試前必定必定要準備,至少一週啦~~~~
    相關文章
    相關標籤/搜索