前端知識彙總

記錄一些前端常用的基礎知識點

Github地址,多多star ^_^

技能樹

圖片描述

BFC

BFC 定義: BFC(Block formatting context)直譯爲"塊級格式化上下文"。它是一個獨立的渲染區域,只有Block-level box參與, 它規定了內部的Block-level Box如何佈局,並且與這個區域外部毫不相干。

BFC佈局規則:

  • 內部的Box會在垂直方向,一個接一個地放置。
  • Box垂直方向的距離由margin決定。屬於同一個BFC的兩個相鄰Box的margin會發生重疊
  • 每個元素的margin box的左邊, 與包含塊border box的左邊相接觸(對於從左往右的格式化,否則相反)。即使存在浮動也是如此。
  • BFC的區域不會與float box重疊。
  • BFC就是頁面上的一個隔離的獨立容器,容器裏面的子元素不會影響到外面的元素。反之也如此。
  • 計算BFC的高度時,浮動元素也參與計算

哪些元素會生成BFC:

  • 根元素
  • float屬性不爲none
  • position爲absolute或fixed
  • display爲inline-block, table-cell, table-caption, flex, inline-flex
  • overflow不爲visible

參考

瀏覽器渲染頁面過程

  1. 用戶輸入URL地址
  2. 對URL地址進行DNS域名解析
  3. 建立TCP連接(三次握手)
  4. 瀏覽器發送HTTP請求報文
  5. 服務器返回HTTP響應報文
  6. 關閉TCP連接(四次揮手)
  7. 瀏覽器解析文檔資源並渲染頁面

TCP

TCP三次握手

圖片描述

TCP四次揮手

圖片描述

JS單線程運行機制

  • 消息隊列:消息隊列是一個先進先出的隊列,它裏面存放着各種消息。
  • 事件循環:事件循環是指主線程重複從消息隊列中取消息、執行的過程。

主線程只會做一件事情,就是從消息隊列裏面取消息、執行消息,再取消息、再執行。當消息隊列爲空時,就會等待直到消息隊列變成非空。而且主線程只有在將當前的消息執行完成後,纔會去取下一個消息。這種機制就叫做事件循環機制,取一個消息並執行的過程叫做一次循環。消息就是註冊異步任務時添加的回調函數。

事件循環

macroTask(宏任務): 主代碼塊, setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI rendering

microTask(微任務): process.nextTick, Promise, Object.observe, MutationObserver

事件

事件流

  • 事件捕獲階段
  • 處於目標階段
  • 事件冒泡階段

事件委託

不在事件的發生地(直接dom)上設置監聽函數,而是在其父元素上設置監聽函數,通過事件冒泡,父元素可以監聽到子元素上事件的觸發,通過判斷事件發生元素DOM的類型,來做出不同的響應。

舉例:最經典的就是ul和li標籤的事件監聽

HTML

基礎標籤

<head></head>

<meta />

<link rel="stylesheet" href="" />

<title></title>

<body></body>

<center></center>

<section></section>

<article></article>

<aside></aside>

<div></div>

<ul></ul>

<li></li>

<p></p>

<h1></h1>
~
<h6></h6>

<button></button>

<input type="text" />

<a href=""></a>

<span></span>

<strong></strong>

<i></i>

CSS

CSS 樣式

優先級: 行內樣式 > 鏈接式 > 內嵌式 > @import 導入式

選擇器

/* 選擇所有元素 */
* {
}

/* 選擇 div 元素 */
div {
}

/* 選擇類名元素 */
.class {
}

/* 選擇 id 元素 */
#id {
}

/* 選擇 div 元素內的所有 p 元素 */
div p {
}

/* 選擇 div 元素內下一層級的 p 元素 */
div > p {
}

css選擇器權重: !important -> 行內樣式 -> #id -> .class -> 元素和僞元素 -> * -> 繼承 -> 默認

文本溢出

// 文本溢出單行顯示
.single {
  overflow: hidden;
  text-overflow:ellipsis;
  white-space: nowrap;
}

// 文本溢出多行顯示
.multiple {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  overflow: hidden;
}

CSS3 新特性

  • transition:過渡
  • transform:旋轉、縮放、移動或者傾斜
  • animation:動畫
  • gradient:漸變
  • shadow:陰影
  • border-radius:圓角

Javascript

原型與原型鏈

  • 實例的 proto 屬性(原型)等於其構造函數的 prototype 屬性。
  • Object.proto === Function.prototype
  • Function.prototype.proto === Object.prototype
  • Object.prototype.proto === null

繼承實現

function extend(child, parent) {
    var F = function() {}; // 空函數爲中介,減少實例時佔用的內存

    F.prototype = parent.prototype; // f繼承parent原型

    child.prototype = new F(); // 實例化f,child繼承,child、parent原型互不影響

    child.prototype.constructor = child; // child構造函數指會自身,保證繼承統一

    child.super = parent.prototype; // 新增屬性指向父類,保證子類繼承完備
}

深拷貝

function deepCopy(s, t) {
    t = t || (Object.prototype.toString.call(t) === "[object Array]" ? [] : {});

    for (var i in s) {
        if (typeof s[i] === "object") {
            t[i] = deepCopy(s[i], t[i]);
        } else {
            t[i] = s[i];
        }
    }

    return t;
}

Ajax

var ajax = {};

ajax.get = function(url, fn) {
    var xhr = new XMLHttpRequest();

    xhr.open("GET", url, true);

    xhr.onreadystatechange = function() {
        if (
            xhr.readyState === 4 &&
            (xhr.status === 200 || xhr.status === 403)
        ) {
            fn.call(this, xhr.responseText);
        }
    };

    xhr.send();
};

ajax.post = function(url, data, fn) {
    var xhr = new XMLHttpRequest();

    xhr.open("POST", url, true);

    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

    xhr.onreadystatechange = function() {
        if (
            xhr.readyState === 4 &&
            (xhr.status === 200 || xhr.status === 403)
        ) {
            fn.call(this, xhr.responseText);
        }
    };

    xhr.send(data);
};

格式化日期

function formatDate(date, format) {
    if (arguments.length === 0) return null;

    format = format || "{y}-{m}-{d} {h}:{i}:{s}";

    if (typeof date !== "object") {
        if ((date + "").length === 10) date = parseInt(date) * 1000;
        date = new Date(date);
    }

    const dateObj = {
        y: date.getFullYear(),
        m: date.getMonth() + 1,
        d: date.getDate(),
        h: date.getHours(),
        i: date.getMinutes(),
        s: date.getSeconds(),
        a: date.getDay()
    };

    const dayArr = ["一", "二", "三", "四", "五", "六", "日"];

    const str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (match, key) => {
        let value = dateObj[key];

        if (key === "a") return dayArr[value - 1];

        if (value < 10) {
            value = "0" + value;
        }

        return value || 0;
    });

    return str;
}

new 實現

function New(Class) {
    let obj = {};
    obj.__proto__ = Class.prototype;
    let res = Class.call(obj);
    return typeof res === 'object' ? res : obj;
}

call 實現

Function.prototype.callfb = function (ctx) {
    if (typeof this !== 'function') {
        throw new Error('Function undefined');
    }

    ctx = ctx || window;

    const fn = ctx.fn;

    ctx.fn = this;

    const args = [...arguments].slice(1);

    const res = ctx.fn(...args);

    ctx.fn = fn;

    return res;
}

apply 實現

Function.prototype.applyFb = function (ctx) {
    if (typeof this !== 'function') {
        throw new Error('Function undefined');
    }

    ctx = ctx || window;

    const fn = ctx.fn;

    ctx.fn = this;

    const arg = arguments[1];

    const res = Array.isArray(arg) ? ctx.fn(...arg) : ctx.fn();

    ctx.fn = fn;

    return res;
}

bind 實現

Function.prototype.bindFb = function (ctx) {

    const fn = this;

    const args = [...arguments].slice(1);

    const F = function () {};

    const fBind = function () {
        return fn.apply(this instanceof fBind ? this : ctx, args.concat(...arguments))
    }

    if (fn.prototype) {
        F.prototype = fn.prototype;
    }

    fBind.prototype = new F();

    return fBind;
}

instanceof 實現

function instanceofFb(left, right) {
    let proto, prototype = right.prototype;

    proto = left.__proto__;

    while (proto) {

        if (proto === prototype) {
            return true;
        }

        proto = proto.__proto__;

    }

    return false;
}

Promise 實現

function promiseFb(fn) {
    const _this = this;
    this.state = 'pending'; // 初始狀態爲pending
    this.value = null;
    this.resolvedCallbacks = []; // 這兩個變量用於保存then中的回調,因爲執行完Promise時狀態可能還是pending
    this.rejectedCallbacks = []; // 此時需要吧then中的回調保存起來方便狀態改變時調用

    function resolve(value) {
        if (_this.state === 'pending') {
            _this.state = 'resolved';
            _this.value = value;
            _this.resolvedCallbacks.map(cb => { cb(value) }); // 遍歷數組,執行之前保存的then的回調函數
        }
    }

    function reject(value) {
        if (_this.state === 'pending') {
            _this.state = 'rejected';
            _this.value = value;
            _this.rejectedCallbacks.map(cb => { cb(value) });
        }
    }

    try {
        fn(resolve, reject);
    } catch (e) {
        reject(e);
    }
}

promiseFb.prototype.then = function (onFulfilled, onRejected) {
    // 因爲then的兩個參數均爲可選參數,
    // 所以判斷參數類型本身是否爲函數,如果不是,則需要給一個默認函數如下(方便then不傳參數時可以透傳)
    // 類似這樣: Promise.resolve(4).then().then((value) => console.log(value))
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : fn => fn;
    onRejected = typeof onRejected === 'function' ? onRejected : e => { throw e };

    switch (this.state) {
        case 'pending':
            // 若執行then時仍爲pending狀態時,添加函數到對應的函數數組
            this.resolvedCallbacks.push(onFulfilled);
            this.rejectedCallbacks.push(onRejected);
            break;
        case 'resolved':
            onFulfilled(this.value);
            break;
        case 'rejected':
            onRejected(this.value);
            break;
        default: break;
    }
}

debounce 防抖

function debounce(fn, wait, immediate) {
    let timer;
    return function () {
        if (immediate) {
            fn.apply(this, arguments);
        }
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, arguments);
        }, wait)
    }
}

throttle 節流

function throttle(fn, wait) {
    let prev = new Date();
    return function () {
        const now = new Date();
        if (now - prev > wait) {
            fn.apply(this, arguments);
            prev = now;
        }
    }
}

雙向綁定

雙向綁定:視圖(View)的變化能實時讓數據模型(Model)發生變化,而數據的變化也能實時更新到視圖層.

圖片描述

Object.defineProperty

<!DOCTYPE html>
<html lang="en">
<head>
    <title>mvvm</title>
</head>
<body>
    <p>數據值:<span id="data"></span></p>
    <p><input type="text" onkeyup="keyup()"></p>
    <script>
        var obj = {
            data: ''
        }

        function keyup(e) {
            e = e || window.event;
            obj.data = e.target.value; // 更新數據值
        }

        Object.defineProperty(obj, 'data', {
            get: function () {
                return this.data;
            },
            set: function (newVal) {
                document.getElementById('data').innerText = newVal; // 更新視圖值
            }
        })
    </script>
</body>
</html>

Proxy

<!DOCTYPE html>
<html lang="en">
<head>
    <title>mvvm</title>
</head>
<body>
    <p>數據值:<span id="data"></span></p>
    <p><input type="text" onkeyup="keyup()"></p>
    <script>
        var obj = new Proxy({}, {
            get: function (target, key, receiver) {
                return Reflect.get(target, key, receiver);
            },
            set: function (target, key, value, receiver) {
                if (key === 'data') {
                    document.getElementById('data').innerText = value; // 更新視圖值
                }
                return Reflect.set(target, key, value, receiver);
            }
        })

        function keyup(e) {
            e = e || window.event;
            obj.data = e.target.value; // 更新數據值
        }
    </script>
</body>
</html>

算法

冒泡排序

兩兩對比

function bubble(arr) {
    const len = arr.length;

    for (let i = 0; i < len; i++) {
        for (let j = 0; j < len - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                let temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}

選擇排序

尋找最小的數,將索引保存

function selection(arr) {
    const len = arr.length;
    let minIndex, temp;
    for (let i = 0; i < len - 1; i++) {
        minIndex = i;
        for (let j = i + 1; j < len; j++) {
            if (arr[j] < arr[minIndex]) {
                minIndex = j;
            }
        }
        temp = arr[i];
        arr[i] = arr[minIndex];
        arr[minIndex] = temp;
    }
    return arr;
}

Webpack

常用loader

  • file-loader: 加載文件資源,如 字體 / 圖片 等,具有移動/複製/命名等功能;
  • url-loader: 通常用於加載圖片,可以將小圖片直接轉換爲 Date Url,減少請求;
  • babel-loader: 加載 js / jsx 文件, 將 ES6 / ES7 代碼轉換成 ES5,抹平兼容性問題;
  • ts-loader: 加載 ts / tsx 文件,編譯 TypeScript;
  • style-loader: 將 css 代碼以<style>標籤的形式插入到 html 中;
  • css-loader: 分析@import和url(),引用 css 文件與對應的資源;
  • postcss-loader: 用於 css 的兼容性處理,具有衆多功能,例如 添加前綴,單位轉換 等;
  • less-loader / sass-loader: css預處理器,在 css 中新增了許多語法,提高了開發效率;

常用plugin

  • UglifyJsPlugin: 壓縮、混淆代碼;
  • CommonsChunkPlugin: 代碼分割;
  • ProvidePlugin: 自動加載模塊;
  • html-webpack-plugin: 加載 html 文件,並引入 css / js 文件;
  • extract-text-webpack-plugin / mini-css-extract-plugin: 抽離樣式,生成 css 文件;
  • DefinePlugin: 定義全局變量;
  • optimize-css-assets-webpack-plugin: CSS 代碼去重;
  • webpack-bundle-analyzer: 代碼分析;
  • compression-webpack-plugin: 使用 gzip 壓縮 js 和 css;
  • happypack: 使用多進程,加速代碼構建;
  • EnvironmentPlugin: 定義環境變量;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章