摘要:记录一些前端常用的基础知识点地址,多多技能树定义直译为块级格式化上下文。事件循环事件循环是指主线程重复从消息队列中取消息执行的过程。而且主线程只有在将当前的消息执行完成后,才会去取下一个消息。消息就是注册异步任务时添加的回调函数。
记录一些前端常用的基础知识点
Github地址,多多star ^_^
技能树 BFCBFC 定义: 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
参考
浏览器渲染页面过程用户输入URL地址
对URL地址进行DNS域名解析
建立TCP连接(三次握手)
浏览器发送HTTP请求报文
服务器返回HTTP响应报文
关闭TCP连接(四次挥手)
浏览器解析文档资源并渲染页面
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 基础标签优先级: 行内样式 > 链接式 > 内嵌式 > @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.definePropertyProxymvvm 数据值:
算法 冒泡排序mvvm 数据值:
两两对比
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 代码以