前端知識點梳理

1、HTML + CSS

選擇器

  1. 分組選擇器
  2. 派生選擇器
  3. id 選擇器
  4. 類選擇器
  5. 屬性選擇器

選擇器優先級

!important > 行內樣式 > id > class > tag > * >父元素繼承 從右往左解析css

px,em,rem、vw、vh

px

px 是一個虛擬長度單位,是計算機系統的數字化圖像長度單位,若是px要換算成物理長度,須要指定精度DPI

em

em 是一個相對長度單位,相對於其父元素的字體大小html

rem

rem 相對根元素(html)的字體大小前端

vw、vh

vw表示相對於視圖窗口的寬度,vh表示相對於視圖窗口高度vue

盒模型

頁面渲染時,dom採用的渲染模型,能夠經過box-sizing設置,
  1. content-box(W3C 標準盒模型):寬度爲content
  2. border-box(ie盒模型):寬度爲content+padding+border

浮動

浮動的框能夠向左或向右移動,直到它的外邊緣碰到包含框或另外一個浮動框的邊框爲止。因爲浮動框不在文檔的普通流中,因此文檔的普通流中的塊框表現得就像浮動框不存在同樣。java

float:left | rightnode

定位 position

  1. static 元素框正常生成。塊級元素生成一個矩形框,做爲文檔流的一部分,行內元素則會建立一個或多個行框,置於其父元素中。react

  2. relative 元素框偏移某個距離。元素仍保持其未定位前的形狀,它本來所佔的空間仍保留。webpack

  3. absolute 元素框從文檔流徹底刪除,並相對於其包含塊定位。包含塊多是文檔中的另外一個元素或者是初始包含塊。元素原先在正常文檔流中所佔的空間會關閉,就好像元素原來不存在同樣。元素定位後生成一個塊級框,而不論原來它在正常流中生成何種類型的框。css3

  4. fixed 元素框的表現相似於將 position 設置爲 absolute,不過其包含塊是視窗自己。es6

文本

color 設置文本顏色

line-height 設置行高

text-align 對齊元素中的文本。

white-space 設置元素中空白的處理方式。

BFC

塊級格式化上下文,是一個獨立渲染的區域,讓處於 BFC 內部元素和外部元素相互不干擾

觸發條件

  1. position:absolute | fixed
  2. float: 不爲none
  3. display: inline-block / table
  4. overflow: hidden

應用

  1. 阻止margin重疊
  2. 能夠包含浮動元素 —— 清除內部浮動(清除浮動的原理是兩個div都位於同一個 BFC 區域之中)

居中佈局

水平居中

  1. 行內元素:text-align:center
  2. 塊級元素:margin:0 auto
  3. absolute+transform
  4. flex justify-content:center

垂直居中

  1. line-height
  2. absolute+transform
  3. flex align-items:center

水平垂直居中

  • absolute+transform
  • flex justify-content:center align-items:center
  • 清除浮動

    1. flex inline-block
    2. :after: clear: both
    3. BFC
    4. float

    預處理器

    ...

    語義化標籤

    語義化的HTML就是寫出的HTML代碼,符合內容的結構化(內容語義化),選擇合適的標籤(代碼語義化),可以便於開發者閱讀和寫出更優雅的代碼的同時讓瀏覽器的爬蟲和機器很好地解析。

    常見的標籤 nav header footer title main article

    塊級標籤 div p ul li h1-h6

    行內標籤 span button i a img

    flex佈局

    Flex 是 Flexible Box 的縮寫,意爲"彈性佈局",用來爲盒狀模型提供最大的靈活性。

    注意,設爲 Flex 佈局之後,子元素的float、clear和vertical-align屬性將失效。

    採用 Flex 佈局的元素,稱爲 Flex 容器(flex container),簡稱"容器"。它的全部子元素自動成爲容器成員,稱爲 Flex 項目(flex item),簡稱"項目"。

    容器的屬性

    1. flex-direction
    2. 屬性決定主軸的方向(即項目的排列方向) flex-direction: row | row-reverse | column | column-reverse;

    3. flex-wrap
    4. 默認狀況下,項目都排在一條線(又稱"軸線")上。flex-wrap屬性定義,若是一條軸線排不下,如何換行。 flex-wrap: nowrap | wrap | wrap-reverse;

    5. flex-flow
    6. 屬性是flex-direction屬性和flex-wrap屬性的簡寫形式,默認值爲row nowrap。 justify-content: flex-start | flex-end | center | space-between | space-around;

    7. justify-content
    8. 屬性定義了項目在主軸上的對齊方式。 justify-content: flex-start | flex-end | center | space-between | space-around;

    9. align-items
    10. 屬性定義項目在交叉軸上如何對齊。align-items: flex-start | flex-end | center | baseline | stretch;

    11. align-content
    12. 屬性定義了多根軸線的對齊方式。若是項目只有一根軸線,該屬性不起做用。align-content: flex-start | flex-end | center | space-between | space-around | stretch;

    項目的屬性

    1. order
    2. 屬性定義項目的排列順序。數值越小,排列越靠前,默認爲0。order: ;

    3. flex-grow
    4. 屬性定義項目的放大比例,默認爲0,即若是存在剩餘空間,也不放大。flex-grow: ; /* default 0 */

    5. flex-shrink
    6. 屬性定義了項目的縮小比例,默認爲1,即若是空間不足,該項目將縮小。flex-shrink: ; /* default 1 */

    7. flex-basis
    8. 屬性定義了在分配多餘空間以前,項目佔據的主軸空間(main size)。瀏覽器根據這個屬性,計算主軸是否有多餘空間。它的默認值爲auto,即項目的原本大小 flex-basis: length | auto; /* default auto */

    9. flex
    10. 屬性是flex-grow, flex-shrink 和 flex-basis的簡寫,默認值爲0 1 auto。後兩個屬性可選。flex: none | 'flex-grow' 'flex-shrink' || 'flex-basis' 該屬性有兩個快捷值:auto (1 1 auto) 和 none (0 0 auto)。 建議優先使用這個屬性,而不是單獨寫三個分離的屬性,由於瀏覽器會推算相關值。

    11. align-self
    12. 屬性容許單個項目有與其餘項目不同的對齊方式,可覆蓋align-items屬性。默認值爲auto,表示繼承父元素的align-items屬性,若是沒有父元素,則等同於stretch。align-self: auto | flex-start | flex-end | center | baseline | stretch;

    css3

    1. 邊框 border-radius border-shadow
    2. 文本 text-shadow word-wrap
    3. 2D transform: translate | rotate | scale | skew | matrix
    4. 3D transform: rotateX | rotateY

    transition過渡

    transition :css屬性名稱 過渡時間 時間曲線 延遲時間

    animation動畫

    @keyframes

    1. animation 全部動畫屬性的簡寫屬性,除了 animation-play-state 屬性
    2. animation-name 規定 @keyframes 動畫的名稱
    3. animation-duration 規定動畫完成一個週期所花費的秒或毫秒。
    4. animation-timing-function 規定動畫的速度曲線。默認是 "ease"
    5. animation-delay 規定動畫什麼時候開始。默認是 0。
    6. animation-iteration-count 規定動畫被播放的次數。默認是 1
    7. animation-direction 規定動畫是否在下一週期逆向地播放。默認是 "normal"。
    8. animation-play-state 規定動畫是否正在運行或暫停。默認是 "running"。
    9. animation-fill-mode 規定對象動畫時間以外的狀態。

    transition 和 animation 區別

    1. transition 是用在過渡的常見,只能規定動畫的初始狀態和結束狀態
    2. animation 是能使動畫階段性變化,而且動畫能中止,能無限循環

    2、Javascript

    this

    this指向誰,要看怎麼調用,常見的三種方式

    1. 函數直接調用,this指向全局global,瀏覽器端也就是window對象
    2. 做爲對象方法去調用,this指向調用方法的對象
    3. 構造器new this指向new生成的對象 new方式調用 call,bind,apply沒法改變this
    其餘的方式如:apply,bind,call this指向傳入的對象,如箭頭函數this指向定義時的this,與調用方式無關

    手寫call

    Function.prototype.myCall = function (context) {
        if (typeof this !== "function") {
          throw new TypeError()
        }
        context = context || window
        context.fn = this
        const query = [...arguments].slice(1)
        const result = context.fn(...query)
        delete context.fn
        return result
      }
      
    複製代碼

    手寫bind

    Function.prototype.myBind = function (context) {
        if (typeof this !== "function") {
          throw new TypeError('bound is not callable')
        }
    
        var _this = this,
          args = [...arguments].slice(1),
          fNOP = function () {},
          fBound = function () {
            return _this.apply(this instanceof fBound ? this : context, [...args, ...arguments])
          }
    
        if (this.prototype) {
          fNOP.prototype = this.prototype
        }
    
        fBound.prototype = new fNOP()
    
        return fBound
      }
      
    複製代碼

    做用域

    es5中做用域分爲 全局做用域、局部做用域、eval做用域。局部做用域能向上訪問到全局做用域,因此函數內部可以訪問到函數外部的變量,反之不能。

    1. 全局做用域:定義在函數最外層的變量
    2. 局部做用域:定義在函數內部的變量
    3. eval做用域:定義在eval的變量
    var a = 10 // 全局做用域
    
    (function(){
        var b = 20 // 局部做用域
    }())
    
    eval("var c = 30") // eval做用域
    
    複製代碼

    做用域鏈

    除了全局做用域, 每個做用域都是存在於某個做用域中的,在試圖訪問一個變量時JS引擎會從當前做用域開始向上查找直到Global全局做用域中止,變造成一條做用域鏈

    執行環境(Execution Context)

    執行環境定義了變量和函數有權訪問的其餘數據,每一個執行環境都有一個與之關聯的變量對象(Variable Object)簡稱 VO,環境中定義的全部變量和函數都存儲在這個變量對象中,全局執行環境是最外圍的執行環境,在 web 瀏覽器中全局執行環境被認爲 window 對象,函數都有本身的執行環境,當函數執行完成以後,執行環境隨之銷燬。當代碼在環境中執行時,會建立一個變量對象的做用域鏈,做用域鏈的用途,是保證對執行環境有權訪問的變量和函數的有序訪問。做用域鏈的前端始終是當前代碼執行的環境的變量對象,若是是函數,則將其活動對象(activation object)做爲變量對象,下一個變量對象則是包含當前環境的外圍環境,直到最後一個最外圍的 window,標識符的解析是沿着做用域鏈一級一級的查找直到 window,這也是爲何在函數內部能訪問到函數外部的變量,而外部訪問不到函數內部的緣由

    當程序執行前,會建立全局環境以及全局VO對象,執行過程分爲兩個階段:

    1. 變量初始化階段
    2. 代碼執行階段

    變量初始化階段

    在VO對象中存儲對應的函數參數、函數聲明、變量聲明

    1. 函數參數(若未傳入,則初始化爲undefined)
    2. 函數聲明(若命名衝突,會覆蓋)
    3. 變量聲明(若命名衝突,忽略)

    代碼執行階段

    將聲明後的變量賦值

    簡單的測試以下代碼

    alert(x)    // function
    var x = 10
    alert(x)    // 10
    x= 20
    function x(){}
    alert(x)    // 20
    if(true) {
        var a = 1
    }else{
        var b = 1
    }
    
    複製代碼
    1. 第一步先看是否有函數參數傳入,由於是全局環境,因此不會有函數參數

    2. 第二步看有沒有函數聲明,有則在 VO 對象中存儲,值爲 function

    VO = {
            x:function
        }
        
    複製代碼
    1. 第三步看有沒有變量聲明,有就在VO對象中存儲,值爲 undefined
    VO = {
            x:function,
            a:undefined,
            b:undefined
        }
        
    複製代碼

    由於變量聲明發生命名衝突會忽略,因此 x 仍是 function ,而後到了代碼執行階段,第一個 alert 能在 VO 中找到 x,因此是 function,然後 x=10 ,VO 中 x 的賦值爲10,因此第二個 alert 爲10,然後函數聲明忽略,if 爲 true,VO 中的 a 賦值爲1,b 執行不到仍是 undefined

    閉包

    閉包是指有權訪問另外一個函數做用域中的變量的函數,建立閉包的常見方式是,在一個函數內部建立另外一個函數。利用閉包技巧便可以訪問到函數內部的變量,在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。

    function f1(){
        var n=999;
        function f2(){
            alert(n); // 999
        }
        return f2
    }
    
    var func = f1()
    func()
    
    複製代碼

    以上代碼,f2 定義在 f1 內部,因此 f2 的做用域鏈包含 f1 的活動對象,當 f1 調用完成後,f1 的執行環境的做用域鏈被銷燬,可是 f2 仍然能訪問到 f1 的活動對象,因此 f1 的活動對象還存在內存中,只有 f2 銷燬,活動對象才銷燬,咱們能夠解除 func 的引用,即 func = null,通知垃圾回收機制回收,f2 的做用域鏈被銷燬,f1 的活動對象也隨之銷燬

    使用閉包的注意點

    因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露。解決方法是,在退出函數以前,將不使用的局部變量所有刪除。

    原型

    原型就是一個簡單的對象,對象中包含一些方法,用於對象屬性的繼承,每一個對象都有個__proto__屬性指向該對象的原型,以及constructor屬性指向構造函數

    原型鏈

    javascrip函數都有一個prototype屬性指向原型對象,原型對象也有一個__proto__屬性,這個屬性指向本身的原型,直到Object的原型(null),這樣就造成了原型鏈,原型鏈主要用於實現繼承和共享屬性,避免資源浪費

    手寫new

    function myNew(fn, ...args) {
        let obj = {}
        Object.setPrototypeOf(obj, fn.prototype);
        let result = fn.apply(obj, args)
        return result instanceof Object ? result : obj
      }
    
       function test(val) {
         this.name = val
       }
    
       test.prototype.sayName = function () {
         console.log(this.name)
       }
    
       var a = myNew(test, "ghc")
       console.log(a)
       a.sayName()
       
    複製代碼

    手寫instanceof

    function myInstanceof(left, right) {
        let prototype = right.prototype
        left = Object.getPrototypeOf(left)
        while (true) {
          if (left === null || typeof left !== "object") {
            return false
          }
          if (left === prototype) {
            return true
          }
          left = Object.getPrototypeOf(left)
        }
      }
      
    複製代碼

    繼承

    組合繼承

    function superType() {
        this.name = "ghc"
    }
    
    superType.prototype.sayName = function() {
        alert(this.name)
    }
    
    function supType(name) {
        superType.call(this,name)
    }
    
    supType.prototype = new superType()
    supType.constructor = supType
    
    var demo = new supType("ghc")
    
    
    複製代碼

    組合繼承是最經常使用的繼承方式,但也有他的不足,不管什麼狀況下,組合繼承都調用了兩次超類型構造函數,第一次調用 superType 函數時,supType 的原型上指定了 name 屬性,第二次在子類型構造函數調用,在實例上指定了 name 屬性把原型上的屬性覆蓋了。咱們能夠用寄生組合繼承來解決這個問題

    寄生組合繼承

    寄生組合繼承就是借用構造函數來繼承屬性,用原型鏈的混成形式來繼承方法

    function Parent(name) {
        this.name = name
     }
    
    function Child(name) {
        Parent.call(this, name)
    }
    
    Child.prototype = Object.create(Parent.prototype, {
        constructor: {
          value: Child,
          enumerable: false,
          writable: true,
          configurable: true
        }
    })
    
    var a = new Child("GHC")
    console.log(a)
    
    複製代碼

    es6部分

    解構賦值

    ES6 容許按照必定模式,從數組和對象中提取值,對變量進行賦值,這被稱爲解構

    數組
    let [a, b, c] = [1, 2, 3];
    
    對象
    let { foo, bar } = { foo: "aaa", bar: "bbb" };
    
    字符串
    const [a, b, c, d, e] = 'hello';
    
    數字
    let {toString: s} = 123;
    
    布爾
    let {toString: s} = true;
    
    複製代碼

    擴展運算符

    數組擴展運算符(spread)是三個點(...)。它比如 rest 參數的逆運算,將一個數組轉爲用逗號分隔的參數序列
    
    console.log(...[1, 2, 3])
    // 1 2 3
    
    console.log(1, ...[2, 3, 4], 5)
    // 1 2 3 4 5
    
    function add(x, y) {
      return x + y;
    }
    
    const numbers = [4, 38];
    add(...numbers) // 42
    
    對象的擴展運算符(...)用於取出參數對象的全部可遍歷屬性,拷貝到當前對象之中。
    
    let z = { a: 3, b: 4 };
    let n = { ...z };
    n  // { a: 3, b: 4 }
    
    // 等同於 {...Object(true)}
    {...true} // {}
    
    // 等同於 {...Object(undefined)}
    {...undefined} // {}
    
    // 等同於 {...Object(null)}
    {...null} // {}
    
    複製代碼

    擴展運算符與解構賦值結合

    只能放在參數的最後一位,不然會報錯

    數組擴展運算符能夠與解構賦值結合起來,用於生成數組。
    
    const [first, ...rest] = [1, 2, 3, 4, 5];
    
    const [first, ...middle, last] = [1, 2, 3, 4, 5]; //err
    
    對象
    
    對象的解構賦值用於從一個對象取值,至關於將目標對象自身的全部可遍歷的、但還沒有被讀取的屬性,
    分配到指定的對象上面。全部的鍵和它們的值,都會拷貝到新對象上面。
    
    let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
    x // 1
    y // 2
    z // { a: 3, b: 4 }
    
    複製代碼

    Promise

    基本用法

    const promise = new Promise(function(resolve, reject) {
      // ... some code
    
      if (/* 異步操做成功 */){
        resolve(value);
      } else {
        reject(error);
      }
    });
    
    // 不推薦寫法
    promise.then(function(value) {
      // success
    }, function(error) {
      // failure
    });
    
    // 推薦寫法
    promise.then(function(value) {
      // success
    }).catch(function(error){
        console.log('發生錯誤!', error);
    });
    
    複製代碼

    高級用法

    1、 Promise.all

    Promise.all方法用於將多個 Promise 實例,包裝成一個新的 Promise 實例。須要傳入一個數組做爲參數

    const p = Promise.all([p1, p2, p3]);
    
    複製代碼

    Promise.all 的兩種狀態:

    1. 只有當p一、p二、p3狀態都變成fulfilled,p的狀態纔會變成fulfilled,此時p一、p二、p3的返回值組成一個數組,傳遞給p的回調函數

    2. 只要p一、p二、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數

    2、Promise.race

    Promise.race 用法與 Promise.all 相似,只要p一、p二、p3之中有一個實例率先改變狀態,p的狀態就跟着改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。

    手寫Promise

    const PENDING = 'pending'
      const RESOLVED = 'resolved'
      const REJECTED = 'rejected'
    
      function myPromise(fn) {
        var that = this
        that.state = PENDING
        that.value = null
        that.resolveCallballs = []
        that.rejectCallballs = []
    
        function resolve(value) {
          if (that.state === PENDING) {
            that.state = RESOLVED
            that.value = value
            that.resolveCallballs.map(v => v(that.value))
          }
        }
    
        function reject(value) {
          if (that.state === PENDING) {
            that.state = REJECTED
            that.value = value
            that.rejectCallballs.map(v => v(that.value))
          }
        }
    
        try {
          fn(resolve, reject)
        } catch (e) {
          reject(e)
        }
      }
    
      myPromise.prototype.then = function (onFulfilled, onRejected) {
        const that = this
        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v
        onRejected = typeof onRejected === "function" ? onRejected : r => {
          throw r
        }
    
        if (that.state === PENDING) {
          that.resolveCallballs.push(onFulfilled)
          that.rejectCallballs.push(onRejected)
        }
    
        if (that.state === RESOLVED) {
          onFulfilled(that.value)
        }
    
        if (that.state === REJECTED) {
          onRejected(that.value)
        }
      }
    
       new myPromise((resolve, reject) => {
         setTimeout(() => {
           resolve(1)
         }, 1000)
       }).then(value => {
         console.log(value)
       })
       
    複製代碼

    Generator

    Generator有兩個特徵,一是,function關鍵字與函數名之間有一個星號;二是,函數體內部使用yield表達式,調用Generator函數,函數並不會執行,而是返回一個指向內部狀態的指針對象,當調用next方法時纔會執行函數,遇到yield函數會暫停,Generator異步編程用的比較少通常配合co模塊或thunk函數,用的比較多的會是async

    async

    async 是es7異步編程的解決方案 ,是Generator函數的語法糖,默認返回Promise,函數內部若是遇到await會阻塞下面的代碼,跳出函數繼續執行宏任務中的代碼

    class

    class能夠看做是構造函數的語法糖,constructor方法就是構造方法,this指向實例對象

    class A {
        constructor() {
          this.name = "ghc"
        }
    }
    class B extends A {
        constructor() {
          super()
        }
    }
    
    var b = new B()
    console.log(b)
      
    複製代碼

    Symbol

    ES5 的對象屬性名都是字符串,這容易形成屬性名的衝突,Symbol能夠保證每一個屬性的名字都是獨一無二的

    let mySymbol = Symbol();
    let a = {};
    a[mySymbol] = 'Hello!';
    
    let s = Symbol();
    let obj = {
      [s]() { ... }
    };
    
    複製代碼

    Set

    ES6 提供了新的數據結構 Set。它相似於數組,可是成員的值都是惟一的,沒有重複的值。

    const s = new Set();
    
    [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x));
    
    for (let i of s) {
      console.log(i);
    }
    // 2 3 5 4
    
    複製代碼

    Set 實例的屬性和方法

    屬性:

    1. Set.prototype.constructor:構造函數,默認就是Set函數。
    2. Set.prototype.size:返回Set實例的成員總數。

    Set 實例的方法分爲兩大類:操做方法(用於操做數據)和遍歷方法(用於遍歷成員)

    操做方法:

    1. add(value):添加某個值,返回 Set 結構自己。
    2. delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
    3. has(value):返回一個布爾值,表示該值是否爲Set的成員。
    4. clear():清除全部成員,沒有返回值。

    遍歷方法:

    1. keys():返回鍵名的遍歷器
    2. values():返回鍵值的遍歷器
    3. entries():返回鍵值對的遍歷器
    4. forEach():使用回調函數遍歷每一個成員

    Map

    JavaScript 的對象(Object),本質上是鍵值對的集合(Hash結構),可是傳統上只能用字符串看成鍵。這給它的使用帶來了很大的限制。ES6 提供了 Map 數據結構。它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵

    const m = new Map();
    const o = {p: 'Hello World'};
    
    m.set(o, 'content')
    m.get(o) // "content"
    
    m.has(o) // true
    m.delete(o) // true
    m.has(o) // false
    
    複製代碼

    模塊化

    模塊化的好處是防止變量衝突、提升代碼複用性、提升代碼可維護性

    一、當即執行函數

    當即執行函數是模塊化經常使用的手段

    (function(globalVariable){
       globalVariable.test = function() {}
       // ... 聲明各類變量、函數都不會污染全局做用域
    })(globalVariable)
    
    複製代碼

    二、AMD 和 CMD

    使用較少

    三、commonJS

    最先Node中使用,webpack中也常常看到

    // a.js
    module.exports = {
        a: 1
    }
    // or 
    exports.a = 1
    
    // b.js
    var module = require('./a.js')
    module.a // -> log 1
    
    複製代碼

    四、ES Module

    ES Module 是原生實現的模塊化方案

    // 引入模塊 API
    import XXX from './a.js'
    import { XXX } from './a.js'
    // 導出模塊 API
    export function a() {}
    export default function() {}
    
    複製代碼

    更多查看阮一峯老師的 ECMAScript 6 入門 es6.ruanyifeng.com/#README

    DOM 相關 API

    節點查找API

    document.getElementById()

    document.getElementsByClassName()

    document.getElementsByTagName()

    document.getElementsByName()

    document.querySelector()

    節點建立API

    document.createElement()

    document.createTextNode()

    node.cloneNode()

    節點修改API

    parent.appendChild(child)

    parent.insertBefore(newNode,refNode)

    parent.removeChild(node) 通常用法 node.parentNode.removeChild(node)

    parent.replaceChild(newNode,oldNode)

    節點關係API

    父關係API

    parentNode 返回父節點,父節點多是 element、document、DocumentFragment

    parentElement 返回父節點,與 parentNode 區別是父元素只能是 element,不然返回 null

    子關係API

    children 返回一個實時的 HTMLCollection ,子節點都是Element,IE9如下瀏覽器不支持

    childNodes 返回一個實時的 NodeList ,表示元素的子節點列表,注意子節點可能包含文本節點、註釋節點等

    firstChild 返回第一個子節點,不存在返回null,與之相對應的還有一個 firstElementChild

    lastChild 返回最後一個子節點,不存在返回null,與之相對應的還有一個 lastElementChild

    兄弟關係型API

    previousSibling 節點的前一個節點,若是不存在則返回null。注意有可能拿到的節點是文本節點或註釋節點

    nextSibling :節點的後一個節點,若是不存在則返回null。注意有可能拿到的節點是文本節點

    previousElementSibling :返回前一個元素節點,前一個節點必須是Element,注意IE9如下瀏覽器不支持。

    nextElementSibling :返回後一個元素節點,後一個節點必須是Element,注意IE9如下瀏覽器不支持。

    屬性型API

    setAttribute(name,value)

    name是特性名,value是特性值。若是元素不包含該特性,則會建立該特性並賦值

    getAttribute(name)

    getAttribute返回指定的特性名相應的特性值,若是不存在,則返回null

    樣式相關API

    node.style.xxx 只能獲取到內聯樣式

    window.getComputedStyle(node,pseudo-element) 第二個參數是僞類,能夠獲取應用到元素上的全部樣式,IE8或更低版本不支持此方法

    node.getBoundingClientRect() 用來返回元素的大小以及相對於瀏覽器可視窗口的位置

    3、瀏覽器基礎

    http

    http請求

    請求分爲兩種 get 和 post

    1. get:參數放於 url 傳遞,有必定大小限制,但請求速度較快,能夠緩存
    2. post:傳參無大小限制,較爲安全,不能緩存

    http狀態碼

    1. 200開頭,請求成功
    2. 300開頭,重定向
    3. 400開頭,客戶端錯誤,好比404找不到資源
    4. 500開頭,服務器問題

    事件的觸發三個階段

    1. window向觸發處傳播,遇到註冊的捕獲事件會觸發
    2. 觸發處觸發事件
    3. 觸發處想window傳播,遇到註冊冒泡的事件會觸發

    捕獲由外向內,冒泡由內向外 event.stopPropagation()阻止事件的冒泡

    跨域

    協議、域名、端口有一個不一樣的就是跨域,ajax請求就會失敗

    JSONP

    兼容性不錯,但只限get請求

    手寫jsonp

    function myjsonp(url, data) {
        return new Promise((resolve, reject) => {
          let dataString = url.indexOf('?') === -1 ? '?' : '&'
          if (data instanceof Object) {
            for (let key in data) {
              dataString += key + '=' + data[key] + '&'
            }
          }
          const callBackName = Math.random().toString().replace('.', '')
          dataString += "callback" + callBackName
          let el = document.createElement("script")
          el.src = url + dataString
          el.async = true
    
          window[callBackName] = function (v) {
            resolve(v)
            document.body.removeChild(el)
          }
          document.body.appendChild(el)
        })
      }
    複製代碼

    CORS

    主要由後端實現

    儲存

    cookie

    通常由服務器生成,能夠設置過時時間 大小4K

    sessionStorage

    頁面關閉就清理 通常大小5m

    LocalStorage

    除非被清理,不然一直存在 通常大小5m

    indexDB

    除非被清理,不然一直存在 大小無限

    Service Worker

    Service Worker 是運行在瀏覽器背後的獨立線程,通常能夠用來實現緩存功能 (去了解PWA)

    瀏覽器渲染機制

    將html轉換爲dom樹 css轉換爲cssom 而後合成爲render樹 瀏覽器根據render樹進行佈局(迴流)

    重繪(Repaint)和迴流(Reflow)

    1. 重繪是當節點須要更改外觀而不會影響佈局的,好比改變 color 就叫稱爲重繪
    2. 迴流是佈局或者幾何屬性須要改變就稱爲迴流。

    Event Loop

    事件循環是指: 執行一個宏任務,而後執行清空微任務列表,循環再執行宏任務,再清微任務列表

    1. 微任務 microtask(jobs): promise / ajax / Object.observe(該方法已廢棄)
    2. 宏任務 macrotask(task): setTimout / script / IO / UI Rendering

    V8垃圾回收機制

    垃圾回收: 將內存中再也不使用的數據進行清理,釋放出內存空間。V8 將內存分紅 新生代空間 和 老生代空間。

    新生代空間: 用於存活較短的對象

    老生代空間: 用於存活時間較長的對象

    內存泄露

    1. 意外的全局變量: 沒法被回收
    2. 定時器: 未被正確關閉,致使所引用的外部變量沒法被釋放
    3. 事件監聽: 沒有正確銷燬 (低版本瀏覽器可能出現)
    4. 閉包: 會致使父級中的變量沒法被釋放
    5. dom 引用: dom 元素被刪除時,內存中的引用未被正確清空
    可用 chrome 中的 timeline 進行內存標記,可視化查看內存的變化狀況,找出異常點。

    4、性能優化

    性能優化能夠經過5個方面入手,首先會同個 DNS 解析域名轉換相應的 IP 地址,而後根據 IP 地址找到服務器進行 TCP 連接,這兩個方面前端能作的很少,而後是客戶端發送 HTTP 請求和服務端響應的過程,這點前端能作的是整合資源包的大小,而後瀏覽器拿到數據,進行渲染。總的來講,前端能夠經過整合資源包的大小和優化渲染過程兩個方面入手。

    整合資源包的大小可使用按需加載,好比 Vue 路由可使用路由懶加載防止打包出來的資源包過大,同時也能夠對圖片進行壓縮優化,JPG 壓縮後圖片清晰度不會變化太大適合一些大圖,輪播圖;PNG 體積較大,線條細膩,適合小圖 logo,項目中儘可能使用字體圖標去替代圖片,或者用 base64 / 緩存圖片也能夠減小網絡請求。

    而後前端還能夠經過優化渲染過程方面入手,首先 HTML 生成 dom樹,css 生成樣式規則,二者結合生成 render 樹,而後調用 GPU 去渲染頁面。css 方面的優化要避免選擇器的嵌套,由於選擇器規則是從右到左去匹配的,嵌套就會增長開銷。避免使用通配符,它會匹配全部元素。

    另外要防止 css 阻塞,只有樣式規則完成,頁面才能去渲染,這也是爲何css要放在 head 頭裏面。防止 js 阻塞,在渲染的過程若是遇到 js 腳本,控制權會從渲染引擎到 js 引擎阻塞頁面的渲染。因此腳本要寫在最後,script 標籤能夠用 defer 和 async 異步加載。另外還要減小 dom 的訪問和操做,這是 js 引擎和渲染引擎之間的通訊,很是消耗性能

    圖片處理

    圖片可分爲位圖和矢量圖 常見的位圖有JPG、PNG、GIF,矢量圖有SVG,項目中儘可能使用字體圖標或SVG替代圖片,使用Base64也能夠減小網絡請求

    JPG

    大的背景圖,輪播圖

    png

    體積大 用在小logo 透明背景

    GIF

    動態圖片

    雪碧圖

    小圖太多的時候,集中成一張圖片減小 HTTP 請求,隨着字體圖片、SVG圖片的流行,該技術漸漸退出了歷史舞臺

    SVG

    能適應不一樣設備且畫質不能損壞的圖片

    使用緩存

    使用cach-control或expires這類強緩存時,緩存不過時的狀況下,不向服務器發送請求。強緩存過時時,會使用last-modified或etag這類協商緩存,向服務器發送請求,若是資源沒有變化,則服務器返回304響應,瀏覽器繼續從本地緩存加載資源;若是資源更新了,則服務器將更新後的資源發送到瀏覽器,並返回200響應

    減小重繪迴流

    一、避免使用層級較深的選擇器,或其餘一些複雜的選擇器,以提升CSS渲染效率

    二、避免使用CSS表達式,CSS表達式是動態設置CSS屬性的強大但危險方法,它的問題就在於計算頻率很快。不只僅是在頁面顯示和縮放時,就是在頁面滾動、乃至移動鼠標時都會要從新計算一次

    三、元素適當地定義高度或最小高度,不然元素的動態內容載入時,會出現頁面元素的晃動或位置,形成迴流

    四、給圖片設置尺寸。若是圖片不設置尺寸,首次載入時,佔據空間會從0到徹底出現,上下左右均可能位移,發生迴流

    五、不要使用table佈局,由於一個小改動可能會形成整個table從新佈局。並且table渲染一般要3倍於同等元素時間

    六、對於一些進行動畫的元素,使用硬件渲染,從而避免重繪和迴流

    使用節流和防抖

    使用函數節流(throttle)或函數去抖(debounce),限制某一個方法的頻繁觸發

    節流( Throttle )

    function throttle(fn, interval) {
      // last爲上一次觸發回調的時間
      let last = 0
      
      // 將throttle處理結果看成函數返回
      return function () {
          let context = this
          let args = arguments
          let now = +new Date()
          
          if (now - last >= interval) {
              last = now;
              fn.apply(context, args);
          }
        }
    }
    
    // 用throttle來包裝scroll的回調
    const better_scroll = throttle(() => console.log('觸發了滾動事件'), 1000)
    
    document.addEventListener('scroll', better_scroll)
    複製代碼

    防抖( debounce )

    // fn是咱們須要包裝的事件回調, delay是每次推遲執行的等待時間
    function debounce(fn, delay) {
      // 定時器
      let timer = null
      
      // 將debounce處理結果看成函數返回
      return function () {
        // 保留調用時的this上下文
        let context = this
        // 保留調用時傳入的參數
        let args = arguments
    
        // 每次事件被觸發時,都去清除以前的舊定時器
        if(timer) {
            clearTimeout(timer)
        }
        // 設立新定時器
        timer = setTimeout(function () {
          fn.apply(context, args)
        }, delay)
      }
    }
    
    // 用debounce來包裝scroll的回調
    const better_scroll = debounce(() => console.log('觸發了滾動事件'), 1000)
    
    document.addEventListener('scroll', better_scroll)
    複製代碼

    用 Throttle 來優化 Debounce

    // fn是咱們須要包裝的事件回調, delay是時間間隔的閾值
    function throttle(fn, delay) {
      // last爲上一次觸發回調的時間, timer是定時器
      let last = 0, timer = null
      // 將throttle處理結果看成函數返回
      
      return function () { 
        // 保留調用時的this上下文
        let context = this
        // 保留調用時傳入的參數
        let args = arguments
        // 記錄本次觸發回調的時間
        let now = +new Date()
        
        // 判斷上次觸發的時間和本次觸發的時間差是否小於時間間隔的閾值
        if (now - last < delay) {
        // 若是時間間隔小於咱們設定的時間間隔閾值,則爲本次觸發操做設立一個新的定時器
           clearTimeout(timer)
           timer = setTimeout(function () {
              last = now
              fn.apply(context, args)
            }, delay)
        } else {
            // 若是時間間隔超出了咱們設定的時間間隔閾值,那就不等了,不管如何要反饋給用戶一次響應
            last = now
            fn.apply(context, args)
        }
      }
    }
    
    // 用新的throttle包裝scroll的回調
    const better_scroll = throttle(() => console.log('觸發了滾動事件'), 1000)
    
    document.addEventListener('scroll', better_scroll)
    
    
    複製代碼

    圖片懶加載

    <script>
        // 獲取全部的圖片標籤
        const imgs = document.getElementsByTagName('img')
        // 獲取可視區域的高度
        const viewHeight = window.innerHeight || document.documentElement.clientHeight
        // num用於統計當前顯示到了哪一張圖片,避免每次都從第一張圖片開始檢查是否露出
        let num = 0
        function lazyload(){
            for(let i=num; i<imgs.length; i++) {
                // 用可視區域高度減去元素頂部距離可視區域頂部的高度
                let distance = viewHeight - imgs[i].getBoundingClientRect().top
                // 若是可視區域高度大於等於元素頂部距離可視區域頂部的高度,說明元素露出
                if(distance >= 0 ){
                    // 給元素寫入真實的src,展現圖片
                    imgs[i].src = imgs[i].getAttribute('data-src')
                    // 前i張圖片已經加載完畢,下次從第i+1張開始檢查是否露出
                    num = i + 1
                }
            }
        }
        // 監聽Scroll事件
        window.addEventListener('scroll', lazyload, false);
    </script>
    
    複製代碼

    webpack優化

    一、按需加載,使用路由懶加載提升首次打開的速度

    5、框架(Vue)

    生命週期鉤子函數

    1. beforeCreate (在組件建立以前執行,不能獲取到data、props)
    2. created (在組件建立以後執行)
    3. beforeMount (在組件掛載以前執行,不能訪問到dom節點)
    4. mounted (在組件掛載完成執行,能訪問到dom節點)
    5. beforeUpdete (數據更新以前執行)
    6. updated (數據更新以後執行)
    7. beforeDestroy (組件銷燬以前執行,可用於清除定時器等)
    8. destroyed (組件銷燬以後之心)
    9. activated (keep-alive鉤子進入組件以後觸發)
    10. deactivated (keep-alive鉤子離開組件以後觸發)

    父子組件通訊

    父子組件通訊是單向數據流的,父組件經過props轉遞數據給子組件,子組件不能修改props,只能經過emit觸發父組件的方法通知父組件修改數據

    兄弟組件通訊

    對於這種狀況能夠經過查找父組件中的子組件實現,也就是 this.parent.children,在 $children 中能夠經過組件 name 查詢到須要的組件實例,而後進行通訊。

    跨多層次組件通訊

    provide / inject,官方文檔中不推薦直接使用在業務中,可使用 vuex 作狀態管理

    mixin 和 mixins

    mixin 全局混入,官方不推薦使用,會影響到每一個組件實例,一般插件都是這樣作初始化的。

    mixins 封裝多個組件相同的邏輯

    computed 和 watch 區別

    computed 是計算屬性,依賴其餘屬性計算值,而且computed的值有緩存,訪問其值時不會每次計算,只有當計算值變化纔會返回內容。

    watch 監聽到值的變化就會執行回調,在回調中能夠進行一些邏輯操做。

    keep-alive

    防止組件屢次渲染,keep-alive有兩個獨有的生命週期 activated、deactivated

    v-show和v-if區別

    v-show 通常用於切換較爲平凡的場景,切換開銷較小

    v-if 通常用於切換較少的場景,切換開銷較大

    響應式原理

    響應式原理:首先會遍歷 option 裏的 data ,添加讀取器屬性到實例裏來作一層代理,這也是爲何可以經過 this 訪問到 data 裏的數據。而後會調用 observe 設置監聽器,observe 主要是遍歷 data 中的屬性,將其修改成讀取器屬性,而且生成各自的訂閱器。在 get 中進行依賴收集,把訂閱者 watcher 添加到訂閱器中,並返回屬性的值。在 set 中修改數據的值,而且調用訂閱者的 update 方法修改文本,這樣監聽器就設置完成。接着會遍歷 dom 節點,將節點中的數據替換,並生成訂閱者,觸發監聽器進行依賴收集。這樣當數據發生改變,set 方法就會觸發訂閱器,訂閱器就會通知全部的訂閱者更新視圖。

    class Vue {
        constructor(options) {
          this._data = options.data;
          observer(this._data);
          /* 新建一個Watcher觀察者對象,這時候Dep.target會指向這個Watcher對象 */
          new Watcher();
          /* 在這裏模擬render的過程,爲了觸發test屬性的get函數 */
          console.log('render~', this._data.test);
        }
      }
    
      class Dep {
        constructor() {
          /* 用來存放Watcher對象的數組 */
          this.subs = [];
        }
    
        /* 在subs中添加一個Watcher對象 */
        addSub(sub) {
          this.subs.push(sub);
        }
    
        /* 通知全部Watcher對象更新視圖 */
        notify() {
          this.subs.forEach((sub) => {
            sub.update();
          })
        }
      }
    
      class Watcher {
        constructor() {
          /* 在new一個Watcher對象時將該對象賦值給Dep.target,在get中會用到 */
          Dep.target = this;
        }
    
        /* 更新視圖的方法 */
        update() {
          console.log("視圖更新啦~");
        }
      }
    
      function observer(value) {
        if (!value || (typeof value !== 'object')) {
          return;
        }
    
        Object.keys(value).forEach((key) => {
          defineReactive(value, key, value[key]);
        });
      }
    
      function defineReactive(obj, key, val) {
        /* 一個Dep類對象 */
        const dep = new Dep();
    
        Object.defineProperty(obj, key, {
          enumerable: true,
          configurable: true,
          get: function reactiveGetter() {
            /* 將Dep.target(即當前的Watcher對象存入dep的subs中) */
            dep.addSub(Dep.target);
            return val;
          },
          set: function reactiveSetter(newVal) {
            if (newVal === val) return;
            /* 在set的時候觸發dep的notify來通知全部的Watcher對象更新視圖 */
            dep.notify();
          }
        });
      }
      
      let o = new Vue({
         data: {
           test: "I am test."
         }
      });
      o._data.test = "hello,world.";
      
    複製代碼

    vue-router

    跳轉方法:

    this.$router.push()

    // 字符串

    router.push('home')

    // 對象

    router.push({ path: 'home' })

    // 命名的路由

    router.push({ name: 'user', params: { userId: '123' }})

    // 帶查詢參數,變成 /register?plan=private

    router.push({ path: 'register', query: { plan: 'private' }})

    this.$router.replace()

    replace跳轉不會保留歷史痕跡,其餘用法和 push 一致

    vuex

    state:存放變量

    mutation:修改 state 裏面的變量

    getter:獲取 state 裏的值

    action:異步修改 state 的值,也可用來封裝多個 mutation

    相關文章
    相關標籤/搜索