前端面試準備

原文首發於個人博客,歡迎關注~css

內推軟廣

我已經入職字節跳動實習啦~~,有對前端感興趣的同窗能夠隨時找我內推喲,郵箱:html

  • liyiming.cs@bytedance.com
  • upupming@gmail.com
招聘 Job Specification(僅供參考) 實習生、校招、社招都可

職位描述前端

  1. 負責今日頭條付費中臺產品 Web/Hybrid/Wap/小程序/Flutter 的前端開發工做;
  2. 負責高質量的設計和編碼;承擔重點、難點的技術攻堅;
  3. 負責WEB/WAP頁面性能優化,打造良好的用戶體驗;
  4. 負責推進、優化前端基礎架構、組件抽象,提高開發效率。

職位要求:vue

  1. 本科及以上學歷,計算機等相關專業;
  2. 對主流前端開發框架(如Vue/Angular/React等)有全面的瞭解,熟練使用至少一種;
  3. 熟悉WEB前端技術,對符合WEB標準的網站重構、網站性能提高等有豐富經驗,有成功做品;
  4. 良好的設計和編碼品味,熱愛寫代碼,能產出高質量的設計和代碼;較好的產品意識,願意將產品效果作爲工做最重要的驅動因素;
  5. 熱愛前端技術,有較強的學習能力,有強烈的求知慾、好奇心和進取心 ,能及時關注和學習業界最新的前端技術;
  6. 有服務端開發(Go/Node.js)/Flutter相關開發經驗者優先,熟悉TypeScript開發者優先。

正文開始

即將面試今日頭條的前端實習,這次必定要作好充足準備,特打算花個幾天的時間對前端來一個系統性的梳理(前端太龐大,其實也只能包含一小部分哈哈)。雖然檢查了不少遍,可能仍有錯誤,若是發現,請指正,謝謝!git

本文參考了不少資料,特別須要感謝的有:es6

  1. juejin.im/post/5dafb2…
  2. github.com/Molunerfinn…

JS

ES6 (ES 2015) 新特性

參考:github.com/lukehoban/e…github

Promise

Promise 與回調函數同樣用來管理 JS 中的異步編程,它的提出解決了層層回調函數嵌套形成的回調地獄。new Promise的時候,會把傳遞的函數當即執行。Promise函數天生有兩個參數,resolve(當異步操做執行成功,執行resolve方法),rejected(當異步操做失敗,執行reject方法) 。面試

經過使用 Promise 的 .then() 方法,能夠註冊回調函數,並在 Promise resolved 以後被調用,then 能夠返回一個新的 Promise,Promise 將會 resolve 爲 then 註冊的函數中的返回值,這樣實現了鏈式的回調函數註冊。Promise 有三種可能狀態,pending、fulfilled(成功)、rejected(失敗)。一個 Promise 一旦 resolve 或者 reject 狀態就再也不改變。能夠用 .catch() 獲取 reject 的 Promise 的緣由,也能夠用 .then() 第二個參數獲取。另外還有 Promise.allPromise.race 等等。ajax

相關代碼以下(來源:github.com/Molunerfinn… ):正則表達式

// 實現 Promise.race,resolve 或 reject 第一個便可
Promise.race = function (promises) {
  return new Promise((resolve, reject) => {
    for (const item of promises) {
      Promise.resolve(item).then(res => {
        resolve(res)
      }, err => {
        reject(err)
      })
    }
  })
}

// 實現Promise.all
Promise.all = function (promises) {
  const length = promises.length
  let count = 0
  const result = new Array(length) // 暫存結果
  return new Promise((resolve, reject) => {
    for (const item in promises) {
      Promise.resolve(promises[item]).then(res => {
        count++
        // Promise.all 輸出結果順序是按傳入的promise的順序來的
        result[item] = res
        if (count === length) { // 所有完成再 resolve
          return resolve(result)
        }
      }, err => {
        reject(err) // 一旦有 reject,就 reject
      })
    }
  })
}
複製代碼

相應的,還有 asyncawait

異步編程四種方法:

  • 回調函數
  • 事件監聽
  • 發佈/訂閱
  • Promise 對象

參數默認值

function print(a = 'test') {
  console.log(a)
}

print() // test
print('Hello') // Hello
複製代碼

另外還有:

  • 模板字符串(能夠嵌套)

  • 解構賦值(數組、對象)

  • 展開語法 ...,接收剩餘參數、將數組轉換爲逗號分隔的變量

  • 塊級做用域 letconst,無變量提高,不容許重複聲明

  • 迭代器和 for ... of

  • 生成器

    function* d() { // Generator 函數。它不一樣於普通函數,是能夠暫停執行的,因此函數名以前要加星號,以示區別。
      for (let i = 0; i < 3; i++) {
        yield i * i
      }
    }
    
    for (let i of d()) { // 調用 Generator 函數,會返回一個內部指針(即迭代器/遍歷器 ),即執行它不會返回結果,返回的是指針對象
      console.log(i) // 0, 1, 4
    }
    console.log(d().next()) // {value: 0, done: false},調用指針對象的 next 方法,會移動內部指針;next 方法的做用是分階段執行 Generator 函數
    複製代碼
  • 模塊,importexport

  • 模塊加載器

  • Map + Set + WeakMap(只接受對象鍵名,且是弱引用) + WeakSet

  • 箭頭函數,箭頭函數沒有 arguments 實參集合,取而代之用 ... 運算符

變量提高

  1. 全部 var 聲明都會被提高到做用域的最頂上

  2. 同一個變量聲明只進行一次

    console.log(foo) // undefined,剛剛聲明完成可是並未賦值
    var foo = 3
    console.log(foo) // 3,完成賦值
    var foo = 5
    console.log(foo) // 5,再次賦值
    複製代碼
  3. 函數聲明的優先級優於變量聲明,且函數聲明會連帶定義一塊兒被提高

    console.log(foo) // 輸出 `foo() {}`
    function foo() {}
    foo = 5
    複製代碼
  4. 注意只有 var 才能提高,不帶 var 的全局變量仍是按照順序聲明

    console.log(foo) // Uncaught ReferenceError: foo is not defined
    foo = 3
    foo = 5
    複製代碼

做用域

在 ES5 中,js 只有兩種形式的做用域:全局做用域函數做用域

先來看看 var

(function() {
      var a = b = 5;
  })();
var c = 55
console.log(window.c) // 55,var 做用域存在於所定義的函數,不然(沒有外圍函數)就屬於 window(瀏覽器)/global(Node.js)
console.log(b); // 5,b 沒有關鍵字 var,是全局變量
console.log(window.b); // 5,全局變量也屬於 window 對象
console.log(a); // undefined,離開了 a 的做用域
複製代碼

在 ES6 中,新增長的 let/const塊級做用域(block scope) 成爲現實,在js中常見到的 if{}for{}while{}try{}catch{}switch case{} 甚至直接單純的 {} 這種帶花括號的都是塊級做用域,var obj = {} 中對象的大括號不是塊級做用域。塊級做用域中的同一變量不能被重複聲明(塊級下 let 不能重複定義,嚴格模式下 function 也不能重複聲明)。

this 指向

this 的指向和 var 很相似,this 老是指向調用這個函數的對象,根據 this 所在的函數主要分爲兩種狀況:

  1. 若是此函數是一個對象 obj 的成員,咱們稱之爲方法(method),this 指向方法所屬對象 obj

    const video = {
        title: 'a',
        play() {
            console.log(this)
        }
    }
    
    video.play() // Object {title: "a", play: function play()}
    video.stop = function() {
        console.log(this)
    }
    video.stop() // Object {title: "a", play: function play()}
    複製代碼
  2. 若是此函數是一個普通函數,即不是某個對象的一部分,this 指向 window(瀏覽器)/global(Node.js),若是是嚴格模式則是 undefined

    function playVideo() {
        console.log(this)
    }
    playVideo() // Window
    複製代碼
  3. 構造函數同 1 相似,this 指向新建立的對象。

    function Video(title) {
        this.title = title
        console.log(this)
    }
    const v = new Video('b') // Video {title: "b"}
    複製代碼
  4. 回調函數,this 指向 window(瀏覽器)/global(Node.js)。

    function Video(title) {
        this.title = title
        console.log(this)
        const arr = [1, 2, 3]
        arr.forEach(function(ele) {
            console.log(this) // 三次打印 Window,要使 `this` 指向新建的 Video,有兩種方法:
            // 1. forEach 在 callback 參數以後能夠添加 `thisArg` 參數
            // 2. 使用 ES6 中新增的箭頭函數
        })
    }
    const v = new Video('b')
    複製代碼
  5. 箭頭函數,this 指向外層函數的 this,而且不能用 call 進行指定。

    const obj = {
        a: () => {
            console.log(this)
        }
    }
    obj.a()  // Window
    obj.a.call('123') // Window
    複製代碼
  6. 元素監聽函數,指向元素自己。

    let button = document.getElementById('button')
    button.addEventListener('click', function(e) {
        console.log(this) // <button id="button">測試 this</button>
    })
    複製代碼

閉包

簡單來講閉包就是在函數裏面聲明函數並返回,當一個函數可以訪問和操做另外一個函數做用域中的變量時,就構成了一個閉包(Closure)。咱們要記住函數在執行時使用的是聲明時所處的做用域鏈,而不是調用時的做用域鏈。

function addTo(base) {
  let sum = base
  return function(b) {
    sum += b
    return sum
  }
}

let add = addTo(2)
console.log(add(4)) // 6
console.log(add(5)) // 11
複製代碼
  • 優勢:避免全局變量的污染,設置私有變量,回調函數(定時器、DOM 事件監聽器、Ajax 請求等等)。
  • 缺點:閉包常駐內存,容易形成內存泄漏。

同源策略和跨域方法

同源策略指的是協議域名端口相同,一段腳本只能讀取來自同源的信息。注意子域名也不一樣源。

同源策略限制是有道理的,假設沒有同源策略,黑客能夠利用 IFrame 把真正的銀行登錄界面嵌入到他的頁面上,當你使用真實用戶名、密碼登陸時,他的頁面就能夠經過 JS 讀取到 Iframe 中 input 中的內容、你使用的 Cookie 等,可以輕鬆盜取用戶信息。

跨域主要有如下幾種方法:

  • jsonp 跨域。<script>src 屬性(相似的還有 href 屬性)不受同源策略限制,咱們在 js 中定義回調函數 callback(data) 接收服務器傳來的 data,請求時必須指定回調函數名稱,服務器動態生成 js 腳本對本地的 js callback 進行調用並傳入服務端查詢獲得的 data 數據。注意 jsonp 只能解決 GET 請求。
  • document.domain = ...。腳本能夠將 document.domain 的值設置爲其當前域或其當前域的父域。注意,company.com 不能設置 document.domain 爲 othercompany.com,由於它不是 company.com 的父域。
  • 服務器代理。內部服務器代理請求跨域 url,而後返回數據。
  • CORS 跨源資源分享(Cross-Origin Resource Sharing)。跨域請求數據,現代瀏覽器可以使用 HTML5 規範的 CORS 功能,只要目標服務器返回的 HTTP 頭部有 Access-Control-Allow-Origin: * 便可像普通 ajax 同樣訪問跨域資源。注意如請求方法是PUT或DELETE,或者Content-Type字段的類型是application/json,稱爲非簡單請求,在正式通訊以前,還須要增長一次預檢請求(preflight)。用到的頭部有 Access-Control-Request-MethodAccess-Control-Request-HeadersAccess-Control-Allow-MethodsAccess-Control-Allow-HeadersAccess-Control-Allow-Credentials(發送Cookie和HTTP認證信息)。
  • window.postMessage()。現代瀏覽器中多窗口通訊使用 HTML5 規範的 targetWindow.postMessage(data, origin);其中 data 是須要發送的對象,origin 是目標窗口的 origin。window.addEventListener('message', handler, false);handler 的 event.data 是 postMessage 發送來的數據,event.origin 是發送窗口的 origin,event.source 是發送消息的窗口引用。

localStorage vs. Cookie vs. sessionStorage

參考:juejin.im/post/5dafb2…

  • 相同點:保存在瀏覽器,同源。

  • 不一樣點

    1. Cookie 始終在同源的 http 請求中攜帶,即 Cookie 在瀏覽器和服務器間來回傳遞;
    2. window.sessionStoragewindow.localStorage 不會自動把數據發給服務器,僅在本地保存;
    3. Cookie 數據還有路徑(path)的概念,能夠限制 Cookie 只屬於某個路徑下;
    4. 存儲大小限制也不一樣,Cookie 數據不能超過 4k,同時由於每次 http 請求都會攜帶 Cookie,因此 Cookie 只適合保存很小的數據;
    5. sessionStorage 和 localStorage 雖然也有存儲大小的限制,但比 Cookie 大得多,能夠達到 5M 或更大;
    6. 數據有效期不一樣,sessionStorage 僅在當前瀏覽器窗口關閉前有效,天然也就不可能持久保持;
    7. localStorage 始終有效,窗口或瀏覽器關閉也一直保存,所以用做持久數據;
    8. Cookie 只在設置的 Cookie 過時時間以前一直有效,即便窗口或瀏覽器關閉;
    9. 做用域不一樣,sessionStorage 不在不一樣的瀏覽器窗口中共享,即便是同一個頁面;localStorage 在全部同源窗口中都是共享的;Cookie也是在全部同源窗口中都是共享的。

call vs apply vs bind

callapply 都是用來改變函數執行的時候的 this 和參數。惟一不一樣的是 call 傳入逗號(comma)分隔的參數,apply 傳入數組(array)做爲參數。

bind 返回一個新的函數,傳入一個 this 參數和逗號分隔的參數,新返回的函數執行時使用給定的 this 和參數。

若是要本身實現這三個函數的話,核心的思路就是:

Function.prototype.newCall = function (context, ...args){
    //...
    context.fn = this // 當前調用 newCall 的函數
    const
    result = context.fn(...args) // 此處調用時改變了this指向,fn的this指向context
    // ...
}
複製代碼

JavaScript 事件流

參考:segmentfault.com/a/119000000…

事件流描述的是從頁面中接收事件的順序,也可理解爲事件在頁面中傳播的順序。

事件冒泡事件捕獲分別由微軟和網景公司提出,在事件捕獲的概念下在p元素上發生click事件的順序應該是document -> html -> body -> div -> p,在事件冒泡的概念下在p元素上發生click事件的順序應該是p -> div -> body -> html -> document。

addEventListener有三個參數:

element.addEventListener(event, function, useCapture) 複製代碼

第三個參數默認值是false,表示在事件冒泡階段調用事件處理函數;若是參數爲true,則表示在事件捕獲階段調用處理函數。點擊下面的 s2 按鈕查看效果。

See the Pen event capture and bubbling by Li Yiming (@upupming) on CodePen.

注意:對於target節點上(這裏的 s2),是先捕獲仍是先冒泡則捕獲事件和冒泡事件的註冊順序,先註冊先執行)。

阻止冒泡:

function stopBubble(e) {
    if (e && e.stopPropagation) { // 若是提供了事件對象event 這說明不是IE瀏覽器
        e.stopPropagation()
    } else {
    window.event.cancelBubble = true //IE方式阻止冒泡
}
複製代碼

事件代理

See the Pen 事件代理 by Li Yiming (@upupming) on CodePen.

IE 兼容性

IE瀏覽器對addEventListener兼容性並不算太好,只有IE9以上可使用。

要兼容舊版本的IE瀏覽器,可使用IE的attachEvent函數

object.attachEvent(event, function) 複製代碼

兩個參數與addEventListener類似,分別是事件和處理函數,默認是事件冒泡階段調用處理函數,要注意的是,寫事件名時候要加上"on"前綴("onload"、"onclick"等)。

typeof vs. instanceof

參考:stackoverflow.com/questions/8…

typeof 用來判斷簡單原始類型(primitive types),instanceof 用來判斷複雜原始類型、Object、自定義數據類型。

/** 簡單原始類型 */
'example string' instanceof String; // false
typeof 'example string' == 'string'; // true,string 類型用 typeof

'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false

true instanceof Boolean; // false
typeof true == 'boolean'; // true,boolean 類型用 typeof

99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true,number 類型用 typeof

function() {} instanceof Function; // true
typeof function() {} == 'function'; // true,function 類型用 typeof、instanceof 都可

/** 複雜原始類型 */
/regularexpression/ instanceof RegExp; // true,正則表達式用 instanceof
typeof /regularexpression/; // object

[] instanceof Array; // true,array 用 instanceof
typeof []; //object

{} instanceof Object; // true,object 用 instanceof
typeof {}; // object

/** 自定義類型 */
var ClassFirst = function () {};
var ClassSecond = function () {};
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false
複製代碼

數組判斷

除了上面的 instanceof 外還有以下方法:

// Array API
Array.isArray(arr)

// Object類型的toString會返回[object type],其中type是類型
// 可是有的對象的toString方法會被改寫
// 因此須要借用一下Object原始的toString
return Object.prototype.toString.call(arr) === '[object Array]'

// 利用自定義對象的 constructor
arr.constructor.name === 'Array'
複製代碼

本身實現 instanceof

循環使用 Object.getPrototypeOf() 便可:

// getPrototypeOf 可同時用於對象和原型,不能直接用於類型(直接返回 Function.prototype)
Object.getPrototypeOf([]) === Array.prototype // true
Object.getPrototypeOf(Array.prototype) === Object.prototype // true
Object.getPrototypeOf(Array) == Function.prototype // true

let newInstanceOf = function (left, right) {
    // 檢查必須是複雜數據類型
    if (typeof left !== 'object' && typeof left !== 'function') {
        return false
    }
    right = right.prototype
    do {
        left = Object.getPrototypeOf(left)
        if (left === right) return true
    } while (left !== null)
    return false
}
複製代碼

也可使用 isPrototypeOf 直接檢查對象是否在另外一對象的其原型鏈上:

Object.prototype.isPrototypeOf([]) // true
Array.prototype.isPrototypeOf([]) // true
複製代碼

另外注意 hasOwnProperty 在執行對象查找時,始終不會查找原型。

== vs ===

  • ==容許不一樣數據類型之間的比較,若是是不一樣類型的數據進行比較,會默認進行數據類型之間的轉換,若是是對象數據類型的比較,比較的是空間地址;

    a = [1, 2]
    b = [1, 2]
    // 比較地址空間
    a == b // false
    _.isEqual(array1, array2) // true,使用 Lodash 庫進行比較,或者本身一個一個元素進行比較
    false
    複製代碼
  • ===:只要數據類型不同,就返回false。

防抖(debounce) vs. 節流(throttle)

防抖是說連續兩次的調用必須間隔指定的時間,節流是說當調用一次以後,必須在指定時間以後的調用纔會有效。

具體使用場景:

  • 好比用戶 resize 調整窗口大小,由於一次窗口調整中間會出發出至關多的時間間隔很短的 resize 事件,那麼防抖主要是看用戶進行調整的總次數,而節流看的是每一次調整時,用戶的 resize 的手速有多快。
  • 在搜索引擎中,時常出現好比要搜索 front end,當你輸入前面的 f 或者 front 時就會出現候選結果。可是由於 API 調用消耗很大,因此會使用防抖來較少調用次數,這符合用戶停頓時就是想看到搜索結果的現實邏輯。

實現以下:

function debounce(func, limit) {
  let timer
  return function (...args) {
    // 前一次還沒來得及執行的話,取消掉前一次的
    clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, limit)
  }
}

function throttle(func, limit) {
  let flag = true
  return function(...args) {
    if (flag) {
      func.apply(this, args)
      flag = false
      // 只有通過指定時間後,才能夠執行新的
      setTimeout(() => {
        flag = true
      }, limit)
    }
  }
}
複製代碼

清除浮動

在非IE瀏覽器(如Firefox)下,當容器的高度爲auto,且容器的內容中有浮動(float爲left或right)的元素,在這種狀況下,容器的高度不能自動伸長以適應內容的高度,使得內容溢出到容器外面而影響(甚至破壞)佈局的現象。這個現象叫浮動溢出,爲了防止這個現象的出現而進行的CSS處理,就叫CSS清除浮動。

  • clear 清除浮動,添加空div法,在浮動元素下方添加空div,並給該元素寫css樣式 {clear:both;height:0;overflow:hidden;}
  • 給浮動元素父級設置高度
  • 父級同時浮動(須要給父級同級元素添加浮動)
  • 父級設置成 inline-block,其 margin: 0 auto 居中方式失效
  • 給父級添加 overflow:hidden
  • 萬能清除法 after 僞類清浮動(如今主流方法,推薦使用)

聖盃佈局和雙飛翼佈局

聖盃佈局

See the Pen 聖盃佈局 by Li Yiming (@upupming) on CodePen.

雙飛翼佈局

See the Pen 雙飛翼佈局 by Li Yiming (@upupming) on CodePen.

Ajax

ajax的原理:至關於在用戶和服務器之間加一箇中間層(ajax引擎),使用戶操做與服務器響應異步化。

  • 優勢:在不刷新整個頁面的前提下與服務器通訊維護數據。不會致使頁面的重載能夠把前端服務器的任務轉嫁到客服端來處理,減輕服務器負擔,節省帶寬;
  • 劣勢:不支持返回上一次請求內容。對搜索引擎的支持比較弱(百度在國內搜索引擎的佔有率最高,可是很不幸,它並不支持ajax數據的爬取);不容易調試。

怎麼解決呢?經過location.hash值來解決Ajax過程當中致使的瀏覽器前進後退按鍵失效, 解決之前被人常遇到的重複加載的問題。主要比較先後的hash值,看其是否相等,在判斷是否觸發ajax。

function getData(url) {
    var xhr = new XMLHttpRequest();  // 建立一個對象,建立一個異步調用的對象
    xhr.open('get', url, true)  // 設置一個http請求,設置請求的方式,url以及驗證身份
    xhr.send() //發送一個http請求
    xhr.onreadystatechange = function () {  //設置一個http請求狀態的函數
        if (xhr.readyState == 4 && xhr.status ==200) {
            console.log(xhr.responseText)  // 獲取異步調用返回的數據
        }
    }
}
複製代碼

AJAX狀態碼:

  • 0 - (未初始化)尚未調用send()方法
  • 1 - (載入)已調用send方法,正在發送請求
  • 2 - (載入完成)send()方法執行完成
  • 3 - (交互)正在解析相應內容
  • 4 - (完成)響應內容解析完成,能夠在客戶端調用了

setTimeout 實現 setInterval

基本思想:

function mySetInterval(handler, timeout, ...arguments) {
  const fn = () => { // 關鍵在於構造 fn 反覆調用 handler
    handler()
    setTimeout(fn, timeout)
  }
  setTimeout(fn, timeout)
}
mySetInterval(() => {
  console.log(`bla bla...`)
}, 1000)
複製代碼

另外,還能夠實現 clearTimeInterval(利用全局 obj 存儲自增的 idtimeId 的映射) 和 arguments 自定義參數。

事件循環

JavaScript 的併發模型基於「事件循環」。這個模型與像 C 或者 Java 這種其它語言中的模型大相徑庭。

一個 JavaScript 運行時包含了一個待處理的消息隊列。每個消息都關聯着一個用以處理這個消息的函數。

在事件循環期間的某個時刻,運行時從最早進入隊列的消息開始處理隊列中的消息。爲此,這個消息會被移出隊列,並做爲輸入參數調用與之關聯的函數。調用一個函數老是會爲其創造一個新的棧幀。函數的處理會一直進行到執行棧再次爲空爲止;而後事件循環將會處理隊列中的下一個消息(若是還有的話)。

Event Loop是一個程序結構,用於等待和發送消息和事件。常見形式:

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
複製代碼
const s = new Date().getSeconds();

setTimeout(function() {
  // 輸出 "2",表示回調函數並無在 500 毫秒以後當即執行
  // 而是等待下面的 while 執行完以後纔開始執行
  // 在瀏覽器裏,當一個事件發生且有一個事件監聽器綁定在該事件上時,消息會被隨時添加進隊列。
  // 500ms事後,WebAPIs把此函數放入任務隊列,此時while循環還在棧中,此函數須要等待;
  console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
}, 500);

while(true) {
  // while循環執行完畢從棧中彈出,main()彈出,此時棧爲空,Event Loop,setTimeout中的回調函數進入棧
  if(new Date().getSeconds() - s >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}
複製代碼

class & interface

在es6中,咱們有一種新的關鍵字class來定義一個類;咱們能夠繼承方法和屬性,使用extends關鍵字繼承;其實本質上,仍是使用原型鏈的方式繼承,只是給了更好理解的語法糖;Typescript在 class 的基礎上添加了訪問修飾符和接口 interface

HTML

Property 和 Attribute 的區別

property:屬性,attribute:特性

attribute 是 DOM 元素在文檔中做爲 HTML 標籤擁有的屬性;property 是 DOM 元素在 JavaScript 中做爲對象擁有的屬性。

建立

  • DOM對象初始化時會在建立默認的基本property;input.valueinput.idinput.disableda1.href 等等
  • 只有在HTML標籤中定義的attribute纔會被保存在元素的 attributes 屬性中,經常使用方法:getAttributesetAttributeremoveAttribute
  • attribute會初始化property中的同名屬性,但自定義的attribute不會出如今property中;
  • attribute的值都是字符串;

數據綁定

  • attributes的數據會同步到property上,然而property的更改不會改變attribute;
  • 對於 valueclass 這樣的屬性/特性,數據綁定的方向是單向的,attribute->property;
  • 對於 id 而言,數據綁定是雙向的,attribute<=>property;
  • 對於 disabled 而言,property上的disabled設置爲false時,會移除attribute上的 disabled,反之亦然,此時數據綁定能夠認爲是雙向的;

CSS

置換元素

置換元素(replaced element)主要是指 img, input, textarea, select, object 等這類默認就有 CSS 格式化外表範圍的元素。進而可知,非置換元素(non-replaced element)就是除了 img, input, textarea, select, object 等置換元素之外的元素。

在 CSS 中,可替換元素(replaced element)的展示效果不是由 CSS 來控制的。這些元素是一種外部對象,它們外觀的渲染,是獨立於 CSS 的。

背景屬性

background-color 規定要使用的背景顏色。
background-position 規定背景圖像的位置。
background-size 規定背景圖片的尺寸。
background-repeat 規定如何重複背景圖像。
background-origin 規定背景圖片的定位區域。
background-clip 規定背景的繪製區域。
background-attachment 規定背景圖像是否固定或者隨着頁面的其他部分滾動。
background-image 規定要使用的背景圖像。
inherit 規定應該從父元素繼承 background 屬性的設置。

盒模型

W3C盒模型

box-sizing: content-box(默認)

總寬度 = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right

若是你設置一個元素的寬爲 100px,那麼這個元素的內容區會有 100px 寬,而且任何邊框和內邊距的寬度都會被增長到最後繪製出來的元素寬度中。

IE盒模型

box-sizing: border-box

總寬度 = margin-left + width + margin-right

你想要設置的邊框和內邊距的值是包含在width內的。也就是說,若是你將一個元素的width設爲100px,那麼這100px會包含它的border和padding,內容區的實際寬度是width減去(border + padding)的值。大多數狀況下,這使得咱們更容易地設定一個元素的寬高。

支持狀況

參考:juejin.im/post/59ef72…

在ie8+瀏覽器中使用哪一個盒模型能夠由box-sizing(CSS新增的屬性)控制,默認值爲content-box,即標準盒模型;若是將box-sizing設爲border-box則用的是IE盒模型。若是在ie6,7,8中DOCTYPE缺失會觸發IE模式。在當前W3C標準中盒模型是能夠經過box-sizing自由的進行切換的。

純 CSS 畫三角形

利用標準盒模型便可:

See the Pen VwwdxXr by Li Yiming (@upupming) on CodePen.

選擇器

參考:www.w3schools.com/cssref/trys…

staticrelativeabsolutefixed

參考:www.cnblogs.com/theWayToAce…

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

  2. relative(相對定位):生成相對定位的元素,經過top,bottom,left,right的設置相對於其正常(原先自己)位置進行定位。可經過z-index進行層次分級。  

    • 定位爲relative的元素脫離正常的文本流中,但其在文本流中的位置依然存在。
    • 不管父級存在不存在,不管有沒有TRBL,均是以父級的左上角進行定位,可是父級的Padding屬性會對其影響。
    • relative定位的層老是相對於其最近的父元素,不管其父元素是何種定位方式。
  3. absolute(絕對定位):生成絕對定位的元素,相對於 static 定位之外的第一個父元素進行定位。元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。可經過z-index進行層次分級。

    • 定位爲absolute的層脫離正常文本流,但與relative的區別是其在正常流中的位置再也不存在。
    • 即便父級有Padding屬性,對其也不起做用,說簡單點就是:它只堅持一點,就以父級左上角爲原點進行定位,父級的padding對其根 本沒有影響。
    • 對於absolute定位的層老是相對於其最近的定義爲absolute或relative的父層。若是其父層中都未定義absolute或relative,則其將相對body進行定位。
  4. fixed(固定定位):生成絕對定位的元素,相對於瀏覽器窗口進行定位。元素的位置經過 "left", "top", "right" 以及 "bottom" 屬性進行規定。可經過z-index進行層次分級。

定位於父級內部某個位置的元素,最好用 absolute,由於它不受父級元素的padding的屬性影響,固然你也能夠用relative,不過到時候計算的時候不要忘記padding的值。

inline vs. inline-block vs. block

參考:21cm.js.org/2018/05/24/…

block和inline這兩個概念是簡略的說法,完整確切的說應該是 block-level elements (塊級元素) 和 inline elements (內聯元素)。

block元素一般被現實爲獨立的一塊,會單獨換一行;inline元素則先後不會產生換行,一系列inline元素都在一行內顯示,直到該行排滿。

大致來講HTML元素各有其自身的佈局級別(block元素仍是inline元素):

  • 常見的塊級元素有 DIV, FORM, TABLE, P, PRE, H1~H6, DL, OL, UL 等。
  • 常見的內聯元素有 SPAN, A, STRONG, EM, LABEL, INPUT, SELECT, TEXTAREA, IMG, BR 等。

block元素能夠包含block元素和inline元素;但inline元素只能包含inline元素。要注意的是這個是個大概的說法,每一個特定的元素能包含的元素也是特定的,因此具體到個別元素上,這條規律是不適用的。好比 P 元素,只能包含inline元素,而不能包含block元素。

細節對比:

  • display:block

    block元素會獨佔一行,多個block元素會各自新起一行。默認狀況下,block元素寬度自動填滿其父元素寬度。
    block元素能夠設置width,height屬性,即便設置了寬度,仍然是獨佔一行。
    block元素能夠設置margin和padding屬性。

  • display:inline

    inline元素不會獨佔一行,多個相鄰的行內元素會排列在同一行裏,直到一行排列不下,纔會新換一行,其寬度隨元素的內容而變化。
    inline元素設置width,height屬性無效。
    inline元素的margin和padding屬性,水平方向的padding-left, padding-right, margin-left, margin-right都產生邊距效果;
    但豎直方向的padding-top, padding-bottom, margin-top, margin-bottom不會產生邊距效果。

  • display:inline-block

    簡單來講就是將對象呈現爲inline對象,可是對象的內容做爲block對象呈現。以後的內聯對象會被排列在同一行內。
    好比咱們能夠給一個link(a元素)inline-block屬性值,使其既具備block的寬度高度特性又具備inline的同行特性。

居中

參考:juejin.im/post/5a7a9a…

水平居中

  1. margin: auto:適用於塊級元素

    See the Pen KKKBRRE by Li Yiming (@upupming) on CodePen.

  2. text-align: center:適用於內聯元素

    See the Pen XWWBqwd by Li Yiming (@upupming) on CodePen.

垂直居中

  1. line-height: height:適用於內聯元素

    The line-height CSS property sets the height of a line box. It's commonly used to set the distance between lines of text. On block-level elements, it specifies the minimum height of line boxes within the element. On non-replaced inline elements, it specifies the height that is used to calculate line box height.

    line-height CSS 屬性用於設置多行元素的空間量,如多行文本的間距。對於塊級元素,它指定元素行盒(line boxes)的最小高度。對於非替代的 inline 元素,它用於計算行盒(line box)的高度。(也就是說內聯元素的高度就是在父元素中指定的 line-height 了。)

    See the Pen gOOjzVj by Li Yiming (@upupming) on CodePen.

  2. 絕對定位負 margin:適用於塊級元素

    父元素:relative;子元素:absolute,margin-top: -(高度的一半); margin-left: -(寬度的一半);

    See the Pen abbjKyy by Li Yiming (@upupming) on CodePen.

  3. 絕對定位 + transform:適用於塊級元素

    See the Pen neg-margin by Li Yiming (@upupming) on CodePen.

  4. 絕對定位 + margin: auto:適用於塊級元素

    See the Pen neg-transform by Li Yiming (@upupming) on CodePen.

另外還有:

  • 使用 flex 彈性盒子佈局:塊級元素(兼容性很差)

    .parent {
      width: 600px;
      height: 200px;
      border: 1px solid red;
      display: flex;
      align-items: center; /*垂直居中*/
      justify-content: center;  /*水平居中*/
    }
    複製代碼
  • padding child 是 parent 的一半:塊級元素

  • display: table-cell

  • 僞元素

僞元素

::before::after

垂直居中:

.parent {
    width: 300px;
    height: 300px;
    border: 1px solid red;
    text-align: center;
}
.child {
    background: blue;
    width: 100px;
    height: 40px;
    display: inline-block;
    vertical-align: middle;
}
.parent::before {
    content: '';
    height: 100%;
    display: inline-block;
    vertical-align: middle;
}
複製代碼

CSS 優先級

  • 不一樣級別:!important > 行內樣式>ID選擇器 > 類選擇器 > 標籤 > 通配符 > 繼承 > 瀏覽器默認屬性
  • 同一級別:後寫的會覆蓋先寫的

visibility: hidden vs display: none

連接:www.nowcoder.com/questionTer… 來源:牛客網

  1. display:none會讓元素從渲染樹中消失,渲染的時候不佔據任何空間;visibility:hidden不會讓元素從渲染樹中消失,渲染的時候仍然佔據空間,只是內容不可見。
  2. display:none是非繼承屬性,子孫節點消失是因爲元素從渲染樹中消失形成,經過修改子孫節點的屬性沒法顯示;visibility:hidden是繼承屬性,子孫節點消失是因爲繼承了hidden,經過設置visibility:visible,可讓子孫節點顯示。
  3. 讀屏器不會讀取display:none的元素內容,而會讀取visibility:hidden的元素內容。

CSS data

<article id="electriccars" data-columns="3" data-index-number="12314" data-parent="cars">
...
</article>
複製代碼

JS 訪問利用 .dataset

var article = document.querySelector('#electriccars');

article.dataset.columns // "3"
article.dataset.indexNumber // "12314"
article.dataset.parent // "cars"
複製代碼

CSS 訪問利用 attr()

article::before {
  content: attr(data-parent);
}
/* 屬性選擇器使用 data */
article[data-columns='3'] {
  width: 400px;
}
article[data-columns='4'] {
  width: 600px;
}
複製代碼

Vue

生命週期

  • beforeCreate:vue 實例的掛載元素 el 和數據對象 data 都是 undefined,尚未初始化。【None】
  • created:vue 實例的數據對象 data 有了,能夠訪問數據和方法,未掛載到 DOM,el 尚未。【data
  • beforeMount:vue 實例的 eldata 都初始化了,可是掛載以前爲虛擬的 DOM 結點。【data & el
  • mounted:vue 實例掛載到真正的 DOM 上,能夠經過 DOM 獲取 DOM 結點。【data & el & DOM】
  • beforeUpdate:響應式數據更新時調用,發生在虛擬 DOM 打補丁以前,適合在更新以前訪問現有的 DOM,好比手動移除已添加的事件監聽器。【data & el & 舊 DOM】
  • updated:虛擬DOM從新渲染和打補丁以後調用,組成新的DOM已經更新,避免在這個鉤子函數中操做數據,防止死循環。【【data & el & 新 DOM】】
  • beforeDestroy:實例銷燬前調用,實例還能夠用,this能獲取到實例,經常使用於銷燬定時器,解綁事件。
  • destroyed:實例銷燬後調用,調用後全部事件監聽器會被移除,全部的子實例都會被銷燬。

雜項

從輸入url地址到頁面相應都發生了什麼

  1. 瀏覽器的地址欄輸入URL並按下回車。
  2. 瀏覽器查找當前URL是否存在緩存,並比較緩存是否過時。
  3. DNS解析URL對應的IP。
  4. 根據IP創建TCP鏈接(三次握手)。
  5. HTTP發起請求。
  6. 服務器處理請求,瀏覽器接收HTTP響應。
  7. 渲染頁面,構建DOM樹。
  8. 關閉TCP鏈接(四次揮手)

參考資料

  1. DOM 中 Property 和 Attribute 的區別
  2. JavaScript this Keyword | YouTube
  3. this | MDN
相關文章
相關標籤/搜索