JS必會(huì)基礎(chǔ)知識(shí)3

描述cookie和localStorage和sessionStorage的區(qū)別

從容量和API易用性角度。

cookie

  1. cookie 本身用于瀏覽器和 server 通訊,被“借用”到本地存儲(chǔ)
  2. api為document.cookie,不夠友好
  3. 容量最大為4kB
  4. http請(qǐng)求時(shí)需要一同發(fā)送到服務(wù)器,增加了請(qǐng)求的數(shù)據(jù)量

localStorage和sessionStorage

  1. 專為本地存儲(chǔ)而設(shè)計(jì)的,最大為5MB
  2. API簡(jiǎn)單易用,setItem,getItem
  3. 不會(huì)隨http請(qǐng)求發(fā)送出去
  4. localStorage數(shù)據(jù)永久存儲(chǔ),除非被動(dòng)刪除
  5. sessionStorage中存在當(dāng)前會(huì)話,瀏覽器關(guān)閉后就會(huì)清空

從輸入U(xiǎn)RL到渲染出頁面的整個(gè)過程

  1. DNS解析:域名 -> IP地址
  2. 瀏覽器根據(jù)IP地址向服務(wù)器發(fā)送http請(qǐng)求
  3. 服務(wù)器處理http請(qǐng)求,并返回給瀏覽器
  4. 根據(jù)html代碼生成DOM樹
  5. 根據(jù)CSS代碼生成CSSOM
  6. 將DOM樹和CSSOM整合成RenderTree
  7. 根據(jù)RenderTree渲染頁面,遇到script標(biāo)簽則暫停渲染,優(yōu)先加載腳本并執(zhí)行js代碼,完成后再繼續(xù)。暫停是因?yàn)镴S進(jìn)程和渲染進(jìn)程是公用一個(gè)線程的,js可能會(huì)改變DOM結(jié)構(gòu)
  8. 直到渲染完成

其中l(wèi)ink要放在head中,因?yàn)榉旁诤竺婵赡軙?huì)造成再次渲染問題,js放在最后,是因?yàn)镴S進(jìn)程和渲染進(jìn)程是公用一個(gè)線程的,而且有可能js加載時(shí)間很長(zhǎng),然后就會(huì)造成頁面卡頓現(xiàn)象,img標(biāo)簽不會(huì)暫停渲染,不會(huì)阻塞DOM渲染,不會(huì)造成重排現(xiàn)象。

window.onload和DOMContentLoaded的區(qū)別

window.addEventListener('load', function() {
  // 頁面全部資源加載完才會(huì)執(zhí)行,包括圖片、視頻
  console.log('load');  // 后輸出
})
document.addEventListener('DOMContentLoaded', function() {
  // DOM渲染完成即可執(zhí)行,此時(shí)圖片、視頻可能還未加載完成
  console.log('DOMContentLoaded');  // 先輸出,所以操作 js 最好在這個(gè)方法里面
})

性能優(yōu)化

原則:

  1. 多使用內(nèi)存、緩存
  2. 減少CPU計(jì)算,減少網(wǎng)絡(luò)加載耗時(shí)
  3. 以空間換取時(shí)間

從何入手

1. 讓加載更快

1.1 減少資源的體積:壓縮代碼
1.2 減少訪問次數(shù):合并代碼、SSR渲染、緩存
1.3 使用更快的網(wǎng)絡(luò)

2. 讓渲染更快

2.1 css放在head部分,js放在body最后
2.2 盡早執(zhí)行js,用DOMContentLoaded觸發(fā)
2.3 懶加載:圖片懶加載、上滑加載更多
2.4 對(duì)DOM查詢緩存
2.5 頻繁DOM操作,合并到一起插入DOM結(jié)構(gòu)
2.6 節(jié)流和防抖

防抖debounce

場(chǎng)景:監(jiān)聽一個(gè)輸入框的文字,變化后觸發(fā)change事件,直接用keyup事件,則會(huì)頻繁觸發(fā)change事件,使用防抖,只有在用戶輸入結(jié)束或暫停的時(shí)候,才會(huì)觸發(fā)change事件

<input type="text" id="input1" />

<script>
    function debounce(fn, delay = 300) {
        let timer = null;
        return function() {
            if (timer) {
                clearTimeout(timer);
            }
            timer = setTimeout(() => {
                fn.call(this, arguments[0]);
                timer = null;
            }, delay);
        };
    }
    const input = document.getElementById("input1");
    input.addEventListener(
        "keyup",
        debounce(function(e) {
            console.log(this.value, e);
        })
    );
</script>

節(jié)流throttle

場(chǎng)景:拖拽一個(gè)元素師,要隨時(shí)拿到該元素的拖拽位置,直接用drag事件,則會(huì)頻繁觸發(fā),很容易造成卡頓,此時(shí)使用節(jié)流的話,無論拖拽速度多快,都快每隔一段時(shí)間觸發(fā)一次

<div
    id="div1"
    draggable="true"
    style="width: 200px;height: 100px;background: rebeccapurple;"
/>

<script>
    function throttle(fn, delay = 100) {
        let timer = null;
        return function() {
            if (timer) {  // timer不為空就什么都不做
                return;
            }
            timer = setTimeout(() => {
                fn.call(this, arguments[0]);
                timer = null;
            }, delay);
        };
    }
    const div = document.getElementById("div1");
    div.addEventListener(
        "drag",
        throttle(function(e) {
            console.log(e.offsetX, e.offsetY);
        })
    );
</script>

如何捕獲異常

  1. try...catch
  2. window.onerror = funtion(message, source, lineNumber, colNumber, error) {}

var 和let、const的區(qū)別

  • var是ES5語法,let和const是ES6語法,var有變量提升
  • var和let是變量,可修改,const是常量,不可改變
  • let和const有塊級(jí)作用域,var沒有

手寫一個(gè)深度比較

// 判斷是否是對(duì)象
function isObject(target) {
    return typeof target === "object" && target !== null;
}
function isEqual(source, target) {
    // 只要其中有一個(gè)不是對(duì)象,那就直接比較
    // 如 isEqual(1, { a: 2 })
    // 如 isEqual(1, 1)
    if (!isObject(source) || !isObject(target)) {
        return source === target;
    }
    // 如過兩個(gè)都引用的是一個(gè)對(duì)象,直接比較
    // 如 isEqual(a, a)
    if (source === target) {
        return true;
    }
    //  兩個(gè)都是對(duì)象或數(shù)組,而且不相等
    // 1. 先取出 source 和 target 的keys, 比較個(gè)數(shù)
    const sourceKeys = Object.keys(source);
    const targetKeys = Object.keys(target);
    if (sourceKeys.length !== targetKeys.length) {
        return false;
    }
    // 以 source 為基準(zhǔn),和 target 依次遞歸比較
    for (let key in sourceKeys) {
        const res = isEqual(source[key], target[key]);
        // 如果 res 中有一個(gè)為false,那就直接返回false
        if (!res) {
            return false;
        }
    }
    // 如果res都為true
    return true;
}
const a = { a: 1, b: 2, c: { x: 3, y: 4 } };
const b = { a: 1, b: 2, c: { x: 3, y: 4 } };
const c = { a: 1, b: 2, c: { x: 3, y: 4 }, d: 5 };
const d = { a: 1, b: 2, c: { x: 3, y: 44 } };

console.log(isEqual("aa", "aa")); // true
console.log(isEqual(11, 1)); // false
console.log(isEqual(a, b)); // true
console.log(isEqual(a, c)); // false
console.log(isEqual(a, d)); // false

獲取URL參數(shù)

// 傳統(tǒng)方法
function getURLQueryParams(_url) {
    const params = {};
    const url = _url || location.href; // _url 存在則用 _url, 不存在則用location.href
    const search = url.split("?");
    if (!search[1]) {
        return params;
    }
    const searches = search[1].split("&");

    searches.map(item => {
        const items = item.split("=");

        params[items[0]] = items[1];
    });
    return params;
}
console.log(getURLQueryParams("http:www.baidu.com?name=xxx&age=20")); // {name: "xxx", age: "20"}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容