记录一些前端经常使用的基础知识点
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; }