前端基础知识整理02
进阶版 要多练习 😈😈😈
# 好文
- webpack 打包优化 (opens new window)
- web打印,一篇搞定 (opens new window)
- 正则表达式不要背 (opens new window)
- 一个合格(优秀)的前端都应该阅读这些文章 (opens new window)
- Vue源码阅读前必须知道javascript的基础内容 (opens new window)
- 灵活运用CSS开发技巧 (opens new window)
- 一篇文章构建你的 NodeJS 知识体系 (opens new window)
- vue插件开发、文档书写、github发布、npm包发布一波流 (opens new window)
- 2020年前端面试复习必读文章 (opens new window)
# 1.注意点
- IOS 无法识别yy-mm-dd这种带 - 的时间格式'
- typeof null === 'object': 在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。
- 原生sort使用的是哪些排序算法?插入排序和快速排序结合的排序算法
- 数组扁平化:arr.toString().split(','),注意返回数组中的数据类型
- 求最大值 Math.max.apply(null, arr) Math.max.call(null, ...arr)
- async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await。
- vue.js中组件export default 中name的三种作用:vue-tools调试,keep-alive识别组件,组件模板递归调用自己
- Object.prototype.toString.call(null) === "[object Null]"
# 2.判断一个数组的类型
1.判断是否具有数组某些方法
if(arr.sort()){}
2.instanceof(某些IE版本不正确)arr instanceof Array
3.Array.isArray()
4.Object.prototype.toString.call(arr);
// '[object Array]'
5.constructor方法arr.constructor === Array
6.通用办法
var isArray = Array.isArray || function(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
};
2
3
# 3.变量提升 && 函数提升
- js查找变量 先在 当前作用域中查找 存在则返回,不存在则向上查找
- 函数的优先权是最高的,它永远被提升至作用域最顶部,然后才是函数表达式和变量按顺序执行 变量提升是人为实现的问题,而函数提升在当初设计时是有目的的。
# 4.事件
- 事件委托:让利用事件冒泡的原理,让自己的所触发的事件,让他的父元素代替执行!
- 事件捕获阶段(与冒泡相反))=>目标元素阶段=>事件冒泡阶段
# addEventListener
- 该函数的第三个参数可以是布尔值,也可以是对象。对于布尔值 useCapture 参数来说,该参数默认值为 false 。useCapture 决定了注册的事件是捕获事件(true)还是冒泡事件(false)。
如果一个节点中的子节点是动态生成的,那么子节点需要注册事件的话应该注册在父节点上
- 阻止事件冒泡:event.stopPropagation()
- 阻止默认事件:event.preventDefault()
# Event loop
JS 是门非阻塞单线程语言,如果 JS 是门多线程的语言话,我们在多个线程中处理 DOM 就可能会发生问题(一个线程中新加节点,另一个线程中删除节点),当然可以引入读写锁解决这个问题
# Event loop 顺序是这样的
1.执行同步代码 // console
2.执行栈为空,查询是否有微任务需要执行
3.执行所有微任务 // Promise.then
4.执行宏任务中的异步代码 // setTimeout
5.然后开始下一轮 Event loop,
# 任务队列
不同的任务源会被分配到不同的 Task 队列中,任务源可以分为 微任务(microtask) 和 宏任务(macrotask) 微任务包括 process.nextTick ,promise ,Object.observe ,MutationObserver 宏任务包括 script ,setTimeout ,setInterval ,setImmediate ,I/O ,UI rendering
# 5.HTTP
简单快速:客户向服务器请求服务时,只需传送请求方法和路径
灵活:HTTP允许传输任意类型的数据对象。正在传输的类型由 Content-Type 加以标记
无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接 (深入-持久连接、管线化)
无状态:HTTP协议是无状态协议( Cookie 的出现)
# http 请求方法
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
# 一般的http连接都是:
- 三次握手建立连接,
- 发送http请求报文,获取响应报文,
- 通过四次挥手,中断连接
- HTTP1.1中connection默认开启keep-alive,就不需要连续的建立然后中断
# http 状态码
- 1xx指示信息,请求已接收,继续处理
- 2xx成功,请求已成功
- 3xx重定向,要完成请求必须要进行下一步操作
- 4xx客户端错误,请求有语法错误或无法实现
- 5xx服务端错误,服务器未能实现合法的请求
# 6.浏览器渲染页面的过程
从耗时的角度,浏览器请求、加载、渲染一个页面,时间花在下面五件事情上:
- DNS 查询
- TCP 连接
- HTTP 请求即响应
- 服务器响应
- 客户端渲染
第五个部分,即浏览器对内容的渲染,这一部分(渲染树构建、布局及绘制),又可以分为下面五个步骤:
- 处理 HTML 标记并构建 DOM 树。
- 处理 CSS 标记并构建 CSSOM 树。
- 将 DOM 与 CSSOM 合并成一个渲染树。
- 根据渲染树来布局,以计算每个节点的几何信息。
- 将各个节点绘制到屏幕上。
# 7.原型
所有引用类型(数组、对象、函数)都有一个__proto__隐式原型属性,属性值是一个普通对象。 此外,Object.prototype.__proto__指向null
所有函数都有一个prototype显式原型属性,属性值是一个普通对象。
Function.prototype.bind()没有prototype属性
所有引用类型(数组、对象、函数)的__proto__执行它的构造函数的prototype属性
# 8. 迭代方法
- every 查询数组是否每一项都满足条件
- some 查询数组中是否有满足条件的项
- filter 过滤,返回true的项组成的数组
- map 对每一项运行给定函数,返回每次函数调用结果组成的数组
- forEach 对每一项运行给定函数,无返回值
- reduce 让数组的前一项和后一项做某种计算,累计最终值
- find 查找某一项
var numbers = [1,2,3,4,5,4,3,2,1];
numbers.every(function(item,index,array){
return item>2;
}) // false
numbers.some(function(item,index,array){
return item>2;
}) // true
numbers.filter(function(item,index,array){
return item>2;
}) // [3,4,5,4,3]
numbers.map(function(item,index,array){
return item*2;
}) // [2,4,6,8,10,8,6,4,2]
numbers.forEach(function(item,index,array){
// 执行某些操作
}) // 无返回值
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 9.new操作符具体干了什么? (理解构造函数相当于一个模板)
- 创建一个空对象
- 将对象的__proto指向构造函数的原型prototype
- 执行构造函数中的代码,传递参数,并将this指向这个对象
- 返回对象
# 10.继承
ES5实现思路就是将子类的原型设置为父类的原型
在 ES6 中,我们可以通过 class 语法**(本质也是原型链继承)**
# 11.闭包
闭包指有权访问另一个函数内部变量的函数,当在函数内部定义了其他函数,也就创建了闭包
想要访问一个f1内的变量,在f1内在创建一个函数f2,将f2的值作为返回值,在调用f1时就能访问到f1里面的局部变量
场景1:使用函数内部变量
场景2:保存变量在内存中
内存泄露 闭包会引用包含函数的整个变量对象,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素无法被销毁。所以我们有必要在对这个元素操作完之后主动销毁。 = null
函数内部定时器 当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。
应用场景
- 设计私有的变量和方法 模块模式:为单例创建私有的变量和方法
单例:指的是只有一个实例的对象。一般以对象字面量的方式来创建一个单例对象。
匿名函数最大的用途是创建闭包,并且还可以构建命名空间,以减少全局变量的使用。从而使用闭包模块化代码,减少全局变量的污染。
在这段代码中函数 addEvent 和 removeEvent 都是局部变量,但我们可以通过全局变量 objEvent 使用它,这就大大减少了全局变量的使用,增强了网页的安全性。
- 经典面试题,循环中使用闭包解决 var 定义函数的问题
for ( var i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
2
3
4
5
首先因为 setTimeout 是个异步函数,所有会先把循环全部执行完毕,这时候 i 就是 6 了,所以会输出5个6。
解决办法两种,第一种使用闭包
for (var i = 1; i <= 5; i++) {
(function(j) {
setTimeout(function timer() {
console.log(j);
}, j * 1000);
})(i);
}
2
3
4
5
6
7
第二种就是使用 setTimeout 的第三个参数
for ( var i=1; i<=5; i++) {
setTimeout( function timer(j) {
console.log( j );
}, i*1000, i);
}
2
3
4
5
第三种就是使用 let 定义 i 了
for ( let i=1; i<=5; i++) {
setTimeout( function timer() {
console.log( i );
}, i*1000 );
}
2
3
4
5
# 12.BOM对象
window JS最顶层对象
location 浏览器当前URL信息
navigator 浏览器本身信息
screen 客户端屏幕信息
history 浏览器访问历史信息
window对象的方法
alert(),prompt(),confirm(),open(),close(),print(),focus(),blur(),moveBy(),moveTo(),resizeBy(),resizeTo(),scrollBy(),scrollTo(),setInterval(),setTimeout(),clearInterval(),clearTimeout()
2
3
4
5
6
7
# 13.拆解url的各部分
使用location的属性
href 完整url地址
protocol 协议
host 主机名+端口号
hostname 主机名
port 端口号
pathname 相对路径
hash #锚点
search ?查询字符串
2
3
4
5
6
7
8
# 14.为什么操作DOM慢?
因为DOM属于渲染引擎的东西,JS又是JS引擎的东西,当我们通过JS操作DOM的时候,涉及到两个线程间的通信,而且操作DOM可能会带来重绘回流的情况,所以就导致了性能问题。
DOM对象本身也是一个js对象,操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint)。 重绘是当节点改变样式而不影响布局,回流是当布局或几何属性需要改变 回流必定会发生重绘,回流的成本比重绘高
虚拟dom 在浏览器内存中进行渲染
# 15.Dom
document.querySelector // 返回第一个匹配的元素
document.querySelectorAll // 返回匹配的所有元素
// 获取文档中所有 class="example" 的 <p> 元素
var x = document.querySelectorAll("p.example");
2
3
4
DOM事件 DOM事件的级别
DOM0 element.onclick=function(){}
DOM2 element.addEventListener('click',function(){},false)
DOM3 element.addEventListener('keyup',function(){},false)
2
3
DOM0级事件就是将一个函数赋值给一个事件处理属性,缺点在于一个处理程序无法同时绑定多个处理函数。
DOM2级事件运行给一个程序添加多个处理函数,定义了addEventListener和removeEventListener两个方法,分别用于绑定和解绑事件,方法包含三个参数分别是绑定的事件处理的属性名称,处理函数,是否在捕获时执行事件
IE8以下使用attachEvent和detachEvent实现,不需要传入第三个参数,因为IE8以下只支持冒泡型事件
btn.attachEvent('onclick', showFn);
btn.detachEvent('onclick', showFn);
2
DOM3级事件是在DOM2级事件的基础上添加很多事件类型如load,scroll,blur,focus,dbclick,mouseup,mousewheel,textInput,keydown,keypress,同时也允许使用者自定义一些事件
# 16.js获取盒模型宽高
最常用,兼容性最好** dom.offsetWidth/offsetHeight**
offsetWidth/offsetHeight,clientWidth/clientHeight与srcollWidth/scrollHeight的区别
offsetWidth/offsetHeight返回包含content+padding+border 全部宽高
clientWidth/clientHeight返回包含content+padding,如果有滚动条,也不包含滚动条
scrollWidth/scrollHeight返回包含content+paddin+溢出内容的尺寸
2
3
4
# 17.Ajax
// 创建XMLHTTPRequest对象
var xhr = new XMLHttpRequest();
// 创建一个新的http请求
xhr.open("get", url, true)
// 设置响应HTTP请求状态变化的函数
xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
// 获取异步调用返回的数据
alert(xhr.responseText)
}
}
}
// 发送HTTP请求
xhr.send(null);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
状态码readyState说明:0:未初始化,未调用send();1:已调用send(),正在发生请求;2:send()方法执行完毕,已经接收到全部响应内容;3:正在解析响应内容;4:解析完成,可以在客户端调用了
# 18.跨域
跨域指通过JS在不同的域之间进行数据传入或通信。 协议,域名,端口有一个不同就是跨域 同源策略是为了防止CSRF攻击,它是利用用户的登录态发起恶意请求。
解决跨域方式
- JSONP使用简单,兼容性不错但仅限GET请求
- CORS服务器端设置Access-Control-Origin开启CORS,该属性表明哪些域名可以访问资源。
- document.domain 只适用于二级域名相同,a.test.com。在页面添加docuemtn.domain = 'test.com'表示二级域名相同即可跨域
- postMessage 通常用于获取嵌入页面(iframe)的第三方页面数据,一个页面发送消息,另一个页面判断来源并接收消息
// 发送消息
window.parent.postMessage('message', 'http://www.test.com')
// 接收消息
let mc=new MessageChannel()
mc.addEventListener('message', event => {
let origin = event.origin || event.originalEvent.origin;
if(origin === 'http://www.test.com'){
console.log('验证通过')
}
}
2
3
4
5
6
7
8
9
10
# 19.Server Worker的工作? 缓存文件
与缓存进行交互,当用户请求缓存中的东西时,Service Worker能立刻从缓存中获取数据不通过外部https调用,传输协议必须为https,目前该技术通常用来做缓存文件,提高首屏速度
# 20.indexDB
Cookie 的大小不超过4KB,且每次请求都会发送回服务器;LocalStorage 在 2.5MB 到 10MB 之间(各家浏览器不同),而且不提供搜索功能,不能建立自定义的索引。indexDB都可以做到,存储无上限
# 21.浅拷贝 && 深拷贝
栈(stack)为自动分配的内存空间,它由系统自动释放,存放基本类型(不可改变))
堆(heap)则是动态分配的内存,大小不定也不会自动释放,存放引用类型。
基本类型的比较是值的比较,只要它们的值相等就认为他们是相等的
引用类型的比较是引用的比较,比较是否指向同一块堆内存
基本数据类型的赋值(=)是在内存中新开辟一段栈内存,然后再把再将值赋值到新的栈中。
引用类型的赋值是传址。只是改变指针的指向
深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象,
浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象
深拷贝:
- JSON.parse(JSON.stringify(Obj))对象中存在循环对象,undefined,函数,日期,正则无法处理
- structuredClone() 函数:解决了 JSON.stringify() 的大部分缺点,它可以处理数据的循环引用,支持许多内置的数据类型;
- 缺点:原型:如果 structuredClone() 传入一个类的实例,会得到一个普通的对象,因为结构化拷贝会丢弃对象的原型链。
- 函数:如果对象包含了函数,会抛出异常。
- 拷贝 DOM 节点会抛出异常。如果需要兼容旧平台,可以引入 core-js 的兼容库
- Object.create()
- Object.assign() 对象只有一层
- obj2 = _.cloneDeep(obj1) 复杂情况的深拷贝使用lodash实现 浅拷贝:
- = 赋值
- ... es6展开符
- object.assign() 对象有多层
# 21.flex + rem + vw wh
rem 自动转换:使用lib-flexible和px2rem
- flex flex 是 flex-grow(放大),flex-shrink (缩放)和 flex-based (基本)的缩写 默认flex:0 1 auto;
flex-grow 控制的是 flex 项的拉伸比例,而不是占据 flex 容器的空间比例。当设置为 0 时,该 flex 项将不会被拉伸去填补剩余空间 两个项的比例是 1:2,意思是在被拉伸时,第一个 flex 项将占用 1/3,而第二个 flex 项将占据余下的空间。
flex-shrink相反
flex-based 自定义元素宽度,200px ,10%都行
以下6个属性设置在容器上。
- flex-direction
- flex-wrap
- flex-flow
- justify-content
- align-items
- align-content
以下6个属性设置在项目上。
- order
- flex-grow
- flex-shrink
- flex-basis
- flex
- align-self
# rem
计算方式: 设计稿px / 根节点px = 真实rem
flexible实际上就是能过JS来动态改写meta标签,动态改写
标签给<html>
元素添加data-dpr属性,并且动态改写data-dpr的值
给<html>
元素添加font-size属性,并且动态改写font-size的值
# vh vw
vh vw是相对视口(viewport)的宽度而定的,长度等于视口宽度的1/100,当前屏幕可见高度的1%。 假如浏览器的宽度为200px,那么1vw就等于2px(200px/100)。
vh是相对视口(viewport)的高度而定的,长度等于视口高度的1/100。 假如浏览器的高度为500px,那么1vh就等于5px(500px/100 calc(100vh - 10px) 表示整个浏览器窗口高度减去10px的大小
# 22.js 结果舍入运算
x.toFixed( num) 将x保留num位小数 银行家舍入:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。四舍六入五取偶
Math.round(x) 四舍五入 round() 方法可把一个数字舍入为最接近的整数
parseInt() 丢弃小数部分,保留整数部分
Math.ceil() 向上取整,有小数就整数部分加1
Math.floor() 向下取整
2
3
4
5
# 23. this
- this指向
定义:this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象
总结:
1.在普通函数内部,this的指向是window
2.在方法内部,this的指向是方法的拥有者。
3.在箭头函数内部,this指向是创建箭头函数时所在的环境中的this指向的值。
4.在对象中,this指向当前对象
2
3
4
这里的this指向会发生改变
5.计时器中的this
6.回调函数中的this
7.事件处理函数中的this指向事件的绑定者
2
3
# 24.安全
XSS
XSS 通过修改 HTML 节点或者执行 JS 代码来攻击网站。 最普遍的做法是转义(replace)输入输出的内容,对于引号,尖括号,斜杠进行转义。显示富文本的采用白名单过滤的方式
CSP CSP 本质上也是建立白名单,通常可以通过 HTTP Header 中的 Content-Security-Policy 来开启 CSP
CSRF
CSRF 就是利用用户的登录态发起恶意请求。 防御:1.请求时附带验证信息,比如验证码或者 token 2.验证 Referer:对于需要防范 CSRF 的请求,我们可以通过验证 Referer 来判断该请求是否为第三方网站发起的。 3.Token:服务器下发一个随机 Token,每次发起请求时将 Token 携带上,服务器验证 Token 是否有效 4.信息加密
SQL注入
就是攻击者把SQL命令插入到Web表单的输入域或页面请求的查询字符串,欺骗服务器执行恶意的SQL命令。 攻击者通过在应用程序预先定义好的SQL语句结尾加上额外的SQL语句元素,欺骗数据库服务器执行非授权的查询,篡改命令。
参数化查询已被视为最有效的可防御SQL注入攻击的防御方式。目前主流的ORM 框架都内置支持并且推荐使用这种方式进行持久层封装。 参数化查询是指在设计与数据库链接并访问数据时,在需要填入数值或数据的地方,使用参数来给值。
# 25.为什么不推荐使用setInterval
js 的执行原理:js引擎是单线程的,主要分为主线程和事件队列,同步操作是在主线程上执行,而异步操作的函数会先放在事件队列当中,等到js主线程空闲了,才会去事件队列取出放到主线程执行。定时器是属于异步事件,参数里面设置的时间,并不是延迟多少秒去执行回调函数,这个时间代表的是延迟多少秒,把回调函数放到异步队列,等待主线程空闲再被执行。
如果当事件队列当中,已经存在了定时器的回调函数,即使已经到了规定的间隔时间,也不会再把这个时间点的定时器回调函数放到事件队列当中,定时器依旧运行。当下一个约定时间又到了,如果事件队列当中依然存在定时器的回调函数,这个时间点的定时器回调函数也不会放进事件队列…
# 26.中文版Chrome浏览器不支持12px以下字体的解决方案
一般解决方案是禁止webkit浏览器配置调整网页的字体大小。如下CSS定义方式:
.classstyle{ -webkit-text-size-adjust:none; font-size:9px; }
# 27.getElementBy* 和 querySelector 区别
getElementById / querySelector 这两个获取到的都是dom节点,结果没有区别。
getElement* 的实时性体现在返回集合的时候,我们知道getElementsBy*和querySelectorAll返回的都是一个节点集合,类似于数组,两种方法的区别就在于这个集合会不会自动更新。
getEle会,queryS不会
# 28.async 与 promise 的区别
- async/await让try/catch 可以同时处理同步和异步错误。
- Promise then 中try/catch不能处理JSON.parse的错误
# 30.手写 call apply bind
# call
Function.prototype.myCall = function(context) {
// 判断是否是undefined和null
if (typeof context === 'undefined' || context === null) {
context = window
}
context.fn = this
let args = [...arguments].slice(1)
let result = context.fn(...args)
delete context.fn
return result
}
2
3
4
5
6
7
8
9
10
11
# apply
Function.prototype.myApply = function(context) {
if (typeof context === 'undefined' || context === null) {
context = window
}
context.fn = this
let args = arguments[1]
let result
if (args) {
result = context.fn(...args)
} else {
result = context.fn()
}
delete context.fn
return result
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# bind
Function.prototype.myBind = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
let _this = this
let args = [...arguments].slice(1)
return function F() {
// 判断是否被当做构造函数使用
if (this instanceof F) {
return _this.apply(this, args.concat([...arguments]))
}
return _this.apply(context, args.concat([...arguments]))
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
# 31.手写 promise
const PENDING = "pending";//初始值,不是fulfilled,也不是rejected
const FULFILLED = "filfilled";//代表操作成功
const REJECTED = "rejected";//代表操作失败
function myPromise(fn) {
console.log(1);
let that = this;
that.state = PENDING;
that.value = null;
that.resolvedCallBacks = [];
that.rejectedCallBacks = [];
// 首先两个函数都得判断当前状态是否为等待中,因为规范规定只有等待态才可以改变状态
// 将当前状态更改为对应状态,并且将传入的值赋值给 value
// 遍历回调数组并执行
function resolve(value) {
console.log(2);
if (that.state == PENDING) {
that.value = value;
that.resolvedCallBacks.map(cb => that.value);
}
};
function reject(value) {
console.log(3);
if (that.state == PENDING) {
that.value = value;
that.rejectedCallBacks.map(cb => that.value);
}
};
// 实现很简单,执行传入的参数并且将之前两个函数当做参数传进去
// 要注意的是,可能执行函数过程中会遇到错误,需要捕获错误并且执行 reject 函数
try {
console.log(4);
fn(resolve, reject)
} catch (e) {
console.log(5);
reject(e)
}
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
const that = this;
console.log(6);
// 首先判断两个参数是否为函数类型,因为这两个参数是可选参数
// 当参数不是函数类型时,需要创建一个函数赋值给对应的参数,同时也实现了透传
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v;
onRejected = typeof onRejected === "function" ? onRejected : r => { throw r };
// 接下来就是一系列判断状态的逻辑,当状态不是等待态时,就去执行相对应的函数。
// 如果状态是等待态的话,就往回调函数中 push 函数
if (that.state === PENDING) {
that.resolvedCallBacks.push(onFulfilled);
that.rejectedCallBacks.push(onRejected);
}
if (that.state === FULFILLED) {
onFulfilled(that.value)
}
if (that.state === REJECTED) {
onRejected(that.value)
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# 调用
new myPromise((resolve, reject) => {
setTimeout(() => {
resolve(1)
}, 3000)
}).then(res => {
console.log(res)
console.log(7)
}, err => {
console.log(8)
})
2
3
4
5
6
7
8
9
10
11
# 32.手写 防抖节流
# 防抖:某个函数在短时间内只执行最后一次。
函数被触发时,需要先延迟,在延迟的时间内,如果再次被触发,则取消之前的延迟,重新开始延迟。这样就能达到,只响应最后一次,其余的请求都过滤掉。
export const Debounce = (fn, t) => {
const delay = t || 500;
let timer;
return function () {
const args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
timer = null;
fn.apply(this, args);
}, delay);
};
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 节流:某个函数在指定时间段内只执行第一次,直到指定时间段结束,周而复始。
export const throttle = (func, interval) => {
let flag = null;
return function(...args) {
if (!flag) {
flag = true;
setTimeout(() => {
flag = false;
fn.call(this, ...args);
}, interval);
}
}
}
2
3
4
5
6
7
8
9
10
11
12
# BFC 块级格式化上下文
BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
一个HTML元素要创建BFC,则满足下列的任意一个或多个条件即可:
- 1、float的值不是none。
- 2、position的值不是static或者relative。
- 3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
- 4、overflow的值不是visible
# 从URL输入到页面加载过程
流程:缓存 -> DNS解析 -> TCP三次握手 -> HTTP请求 -> 数据响应 -> 页面渲染 -> TCP四次挥手
浏览器渲染:创建DOM树—创建StyleRules—创建Render树—布局Layout—绘制
- 01
- 2023/07/03 00:00:00
- 02
- 2023/04/22 00:00:00
- 03
- 2023/02/16 00:00:00