記錄一些前端經常使用的基礎知識點
BFC 定義: BFC(Block formatting context)直譯爲"塊級格式化上下文"。它是一個獨立的渲染區域,只有Block-level box參與, 它規定了內部的Block-level Box如何佈局,而且與這個區域外部絕不相干。html
BFC佈局規則:前端
哪些元素會生成BFC:webpack
參考git
主線程只會作一件事情,就是從消息隊列裏面取消息、執行消息,再取消息、再執行。當消息隊列爲空時,就會等待直到消息隊列變成非空。並且主線程只有在將當前的消息執行完成後,纔會去取下一個消息。這種機制就叫作事件循環機制,取一個消息並執行的過程叫作一次循環。消息就是註冊異步任務時添加的回調函數。github
macroTask(宏任務): 主代碼塊, setTimeout, setInterval, setImmediate, requestAnimationFrame, I/O, UI renderingweb
microTask(微任務): process.nextTick, Promise, Object.observe, MutationObserverajax
不在事件的發生地(直接dom)上設置監聽函數,而是在其父元素上設置監聽函數,經過事件冒泡,父元素能夠監聽到子元素上事件的觸發,經過判斷事件發生元素DOM的類型,來作出不一樣的響應。算法
舉例:最經典的就是ul和li標籤的事件監聽數組
<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>
優先級: 行內樣式 > 連接式 > 內嵌式 > @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; }
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; }
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; }
function New(Class) { let obj = {}; obj.__proto__ = Class.prototype; let res = Class.call(obj); return typeof res === 'object' ? res : obj; }
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; }
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; }
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; }
function instanceofFb(left, right) { let proto, prototype = right.prototype; proto = left.__proto__; while (proto) { if (proto === prototype) { return true; } proto = proto.__proto__; } return false; }
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; } }
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) } }
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)發生變化,而數據的變化也能實時更新到視圖層.
<!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>
<!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; }