- DOM0 和 IE支持(DOM1 开始是 W3C 规范)
- 从事件源向父级,一直到根元素(HTML)
- 某个元素的某类型事件被触发,父元素同类型事件也会被触发
- DOM2 支持
- 从根元素(HTML)到事件源
- 某个元素的某类型事件被触发,先触发根元素,再向子一级,直到事件源
- 事件的流向:事件捕获 → 事件源 → 事件冒泡
- 标准:
event.stopPropagation()
- IE:
event.cancelBubble = true
事件委托也叫事件代理,《Javascript高级程序设计》中写道:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
图为事件流的全过程,从图中我们可以看出:
- 一个完整的事件流是从window开始,最后回到window的一个过程
- 事件流被分为3个阶段:1-5捕获阶段,5-6:目标阶段(事件源),6-10:冒泡阶段
- 只绑定一次事件,无频繁访问DOM,性能较高
- 当有新DOM生成时,无需重复绑定事件,代码清晰简洁
(如果想知道哪一个子元素被点击了,可以在冒泡到父元素时拿到的event对象.target.text()来判断0m)
- Task Queue
- 常见宏任务:
setTimeout
、setInterval
、setImmediate
、I/O
、script
、UI rendering
- Job Queue
- 常见微任务:
- 浏览器:
Promise
、MutationObserver
- Node.js:
process.nextTick
- 浏览器:
当JavaScript代码执行时,它会首先执行所有的同步代码。 当同步代码执行完后,事件循环会查看是否有微任务队列中的任务需要执行。 如果有,它会先执行所有的微任务,直到微任务队列清空。 然后,事件循环会查看是否有宏任务队列中的任务需要执行,并执行一个宏任务。 这个过程会不断重复,形成一个循环。 如果在执行某一个宏任务的过程中异步地产生了微任务, 那么这些微任务会在当前宏任务里的同步任务执行完成后立即执行。 只有当当前宏任务中的所有同步代码和由此产生的所有微任务都执行完毕后,事件循环才会继续执行下一个宏任务
补充:来自https://blog.csdn.net/weixin_45491473/article/details/132901639
现在浏览器中已经用各种队列替代了宏任务,比如chrome的异步队列里有:
微队列 最高优先级
> 交互队列(鼠标事件、键盘事件) 高优先级
> 延时队列(定时器) 中优先级
缺点是:浏览器兼容性比较差,只能兼容到ie9及以上;
flex: auto
实际上是三个属性的集合:flex-grow
表示放大比例,flex-shrink
表示收缩比例,flex-basis
表示分配多余空间前,项目占据的主轴空间。
当我们没有给flex-basis
元素设置width
时,flex-basis: auto
由内部的content
决定宽度,且受max/min-width
限制。
如此一来,在内部content
自由的情况下,那么flex-basis
元素的宽度就看max/min-width
了。
max-width
的默认值是none
,而min-width
的默认值一般是0
,而此处却是auto
,这也是出现“异常”的原因了。
知道原因后,那我们就可以对症下药了:
- 首先自然是设置
width
属性即可了,只要width
小于剩余空间即可,一般设置为width: 0;
这样可百分之百确定小于剩余空间;(【解析】:width 设置为 0,但是flex-basis
会让元素填满剩余空间,所以就会铺满,由于 P 元素有不换行显示省略号,会正常显示。) - 不设置
width
但用min-width
来限制也是一样的,既然 flex 项 的min-width:auto
,那我们也设置一个小于剩余空间的值,一般也是min-width: 0;
- 设置
overflow:hidden
来限制溢出效果也是一致的。
1.加载包(bundle.js)文件的大小越小,首屏渲染速度越快 (按需加载)
2.优先渲染用户直观看到的页面部分(懒加载)
window.postMessage() 方法可以安全地实现跨源通信。
otherWindow.postMessage(message, targetOrigin, [transfer]);
otherWindow
其他窗口的一个引用,比如iframe的contentWindow属性、执行window.open返回的窗口对象、或者是命名过或数值索引的window.frames。
就是前端能效验的都效验完,奉行“前端不信任后端后端不信任前端”的严谨度;(理论应该使用上propTypes)
依托于从数据库中获取页面的限权控制逻辑;
-
text-align: center
适合内联或内联块元素的父元素设置 -
position:staic
margin: 0 auto
适合宽度已知元素- 块元素
display:block
宽度固定width:100px
- 块元素
display:block
宽度自适应内容width:fit-content
- 表格元素
display:table
- 块元素
-
position:relative
/position:absolute
/position:fixed
/position:sticky
脱离文档流后-
偏移
left:50%
或right:50%
margin-left
或margin-right
设置宽度一半transform: translateX(-50%)
-
偏移
left:0
和right:0
- 宽度固定
width:100px
或自适应width:fit-content
margin: 0 auto
- 宽度固定
-
-
display:flex
父元素justify-content: center
每行内部元素沿主轴居中排列
-
内联父元素
line-height: 100px
行高固定值
-
内联块或块元素
line-height
等于 元素height
padding-top
等于padding-bottom
-
内联或内联块元素
vertical-align: middle
元素与行的基线 + 字母x的高度的一半对齐
-
表格单元格元素:
display: table-cell
或<td>
vertical-align: middle
内容或子元素垂直居中
-
position:staic
-
margin-top: 50%
适合宽度已知元素transform: translateY(-50%)
- 块元素
display:block
高度固定height:100px
- 块元素
display:block
宽度自适应内容height:fit-content
- 表格元素
display:table
- 块元素
-
-
position:relative
/position:absolute
/position:fixed
/position:sticky
脱离文档流后-
偏移
top:50%
或bottom:50%
margin-top
或margin-bottom
设置高度一半transform: translateY(-50%)
-
偏移
top:0
和bottom:0
- 宽度固定
height:100px
或自适应height:fit-content
margin: auto 0
- 宽度固定
-
-
display:flex
父元素align-content: center
多行内部元素整体沿交叉轴居中排列align-items: center
每行内部元素整体沿交叉轴居中排列align-self: center
单个内部元素沿交叉轴居中排列
Object.getOwnPropertyDescriptor()
方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不需要从原型链上进行查找的属性)
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
在ES6中,由于 Symbol类型的特殊性,用Symbol类型的值来做对象的key与常规的定义或修改不同,而Object.defineProperty
是定义key为Symbol的属性的方法之一。
该方法允许精确地添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,在枚举对象属性时会被枚举到(for...in
或 Object.keys
方法),可以改变这些属性的值,也可以删除
这些属性。这个方法允许修改默认的额外选项(或配置)。默认情况下,使用 Object.defineProperty()
添加的属性值是不可修改(immutable)的。
对象里目前存在的属性描述符
有两种主要形式:数据描述符和存取描述符。数据描述符是一个具有值的属性,该值可以是可写的,也可以是不可写的。存取描述符是由 getter 函数和 setter 函数所描述的属性。一个描述符
只能是这两者其中之一;不能同时是两者。
这两种描述符都是对象。它们共享以下可选键值(默认值是指在使用 Object.defineProperty()
定义属性时的默认值):
-
configurable
当且仅当该属性的
configurable
键值为true
时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。 默认为false
。 -
enumerable
当且仅当该属性的
enumerable
键值为true
时,该属性才会出现在对象的枚举属性中。 默认为false
。
数据描述符还具有以下可选键值:
-
value
该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。 默认为
undefined
。 -
writable
当且仅当该属性的
writable
键值为true
时,属性的值,也就是上面的value
,才能被赋值运算符
(en-US)改变。 默认为false
。
存取描述符还具有以下可选键值:
-
get
属性的 getter 函数,如果没有 getter,则为
undefined
。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入this
对象(由于继承关系,这里的this
并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为undefined
。 -
set
属性的 setter 函数,如果没有 setter,则为
undefined
。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的this
对象。 默认为undefined
。
- 拥有布尔值的键
configurable
、enumerable
和writable
的默认值都是false
。 - 属性值和函数的键
value
、get
和set
字段的默认值为undefined
。
configurable |
enumerable |
value |
writable |
get |
set |
|
---|---|---|---|---|---|---|
数据描述符 | 可以 | 可以 | 可以 | 可以 | 不可以 | 不可以 |
存取描述符 | 可以 | 可以 | 不可以 | 不可以 | 可以 | 可以 |
如果一个描述符不具有 value
、writable
、get
和 set
中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有 value
或 writable
和 get
或 set
键,则会产生一个异常。
记住,这些选项不一定是自身属性,也要考虑继承来的属性。为了确认保留这些默认值,在设置之前,可能要冻结 Object.prototype
(en-US),明确指定所有的选项,或者通过 Object.create(null)
将 __proto__
(en-US) 属性指向 null
。
全局的 structuredClone() 方法使用结构化克隆算法将给定的值进行深拷贝。 https://developer.mozilla.org/zh-CN/docs/web/api/structuredClone
相当于私有的变量,别的模块只有查看权限,只能赋值后再使用。
盒模型由内向外:内容 content
+ 内边距 padding
+ 边框 border
+ 外边距 margin
分为两类:
- 标准盒模型(默认):
border-sizing:content-box
width
和height
设置内容content
的宽和高 - 替代盒模型:
border-sizing:border-box
width
和height
设置内容content
+ 内边距padding
+ 边框border
的宽和高
块级格式上下文,英文全称是 Block Formatting Context,简称 BFC
它声明了一块布局区域,浏览器对区域内盒子按照一定方式布局,包括默认布局、弹性布局、网格布局、表格布局等
- 默认布局时,区域高度包含浮动元素高度
- 不同区域间相互独立,区域内的盒子和区域外的盒子互不影响
- 不同区域不会发生外边距折叠
我们可以根据布局、溢出处理和有限布局,用不同方法创建块级格式上下文
-
根元素
<html>
-
无副作用:
display:flow-root
-
默认布局
- 绝对定位:
position:absolute
和position:fixed
- 浮动:
float:left
、float:right
- 行内块元素:
display: inline-block
- 绝对定位:
-
溢出处理
overflow:hidden
隐藏滚动条,裁剪溢出内容overflow:scroll
显示滚动条,裁剪溢出内容overflow:auto
未溢出,隐藏滚动条。溢出,显示滚动条
-
有限布局
-
contain
属性值不为none
CSS contain 属性允许开发者声明当前元素和它的内容尽可能的独立于 DOM 树的其他部分。
-
-
弹性布局
display:flex
直接子元素display:inline-flex
直接子元素
-
网格布局
display:gird
直接子元素display:inline-gird
直接子元素
-
多列布局(分栏布局)
column-count
分栏数属性值不为auto
column-width
分栏列宽属性值不为auto
column-span:all
跨越所有列,表现为不分栏
-
表格布局
display:table
表格display:inline-table
内联表格display:table-cell
单元格display:table-caption
表格标题display:table-row
行display:table-row-group
tbodydisplay:table-header-group
theaddisplay:table-footer-group
tfoot
通过创建块级格式上下文,我们可以:
- 清除浮动
- 解决外边距折叠
- 限定布局范围,提高渲染性能
不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方法会添加去掉重复“{}”的方法。
function unique (arr) {
return Array.from(new Set(arr))
}
// 极简版
[...new Set(arr)]
双层循环,外层循环元素,内层循环时比较值。值相同时,则删去这个值。 想快速学习更多常用的ES6语法,可以看《学习ES6笔记──工作中常用到的ES6语法》。
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()//默认排序顺序是根据字符串Unicode码点
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
利用hasOwnProperty 判断是否存在对象属性,
将每个item的typeof结果拼接上自己组成新的值,通过filter触发过滤,如果有就被过滤,如果没有就返回自己,但如果自己是undefined就触发初值ture
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
通过filter比较每一批次当前元素item,在原始数组中的第一个索引是否等于当前索引值,否则返回当前元素(通过返回flase来实现)
function unique(arr) {
return arr.filter(function(item, index, arr) {
return arr.indexOf(item, 0) === index;
//indexof的第二个参数表示开始查找的位置。可以是任意整数,默认值为 0。
});
}
function unique(arr) {
var array= arr;
var len = array.length;
array.sort(function(a,b){ //排序后更加方便去重
return a - b;
})
function loop(index){
if(index >= 1){
if(array[index] === array[index-1]){
array.splice(index,1);
}
loop(index - 1); //递归loop,然后数组去重
}
}
loop(len-1);
return array;
}
思路:把每一个值作为Map中的key,如果Map中没有这个key就将其值塞进数组、同时也在Map中创建并设置该key的值为false;如果Map中已经有该key了,就把Map中这个key的值拨为true
function arrayNonRepeatfy(arr) {
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(map .has(arr[i])) { // 如果有该key值
map .set(arr[i], true);
} else {
map .set(arr[i], false); // 如果没有该key值
array .push(arr[i]);
}
}
return array ;
}
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
用JavaScript模拟DOM树形成虚拟DOM树,
因为对DOM的直接操作是非常慢而且低效的。浏览器的渲染流程包括解析html以构建dom树->构建render树->布局render树->绘制render树,而每一次DOM改变从构建render树到布局到渲染都要重来。
而虚拟DOM的优势就是:1.开发者不再关心DOM而只关心数据,提升开发效率。2.保证最小化的DOM操作,使执行效率得到提升。
虚拟DOM的优势并不在于它操作DOM比较快,而是能够通过虚拟DOM的比较,最小化真实DOM操作
一个 Promise
必然处于以下几种状态之一:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)。当这些情况之一发生时,我们用 promise 的 then 方法排列起来的相关处理程序就会被调用。如果 promise 在一个相应的处理程序被绑定时就已经被兑现或被拒绝了,那么这个处理程序就会被调用,因此在完成异步操作和绑定处理方法之间不会存在竞争状态。
-
这个方法返回一个新的promise对象,该promise对象在iterable参数对象里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法---译者注)
-
等到所有promises都已敲定(settled)(每个promise都已兑现(fulfilled)或已拒绝(rejected))。 返回一个promise,该promise在所有promise完成后完成。并带有一个对象数组,每个对象对应每个promise的结果。
-
接收一个Promise对象的集合,当其中的一个 promise 成功,就返回那个成功的promise的值。
-
当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
-
返回一个状态为失败的Promise对象,并将给定的失败信息传递给对应的处理方法
-
返回一个状态由给定value决定的Promise对象。如果该值是thenable(即,带有then方法的对象),返回的Promise对象的最终状态由then方法执行决定;否则的话(该value为空、基本类型或者不带then方法的对象),返回的Promise对象状态为fulfilled,并且将该value传递给对应的then方法。通常而言,如果您不知道一个值是否是Promise对象,使用Promise.resolve(value) 来返回一个Promise对象,这样就能将该value以Promise对象形式使用。