loading

前端基础知识整理02

进阶版 要多练习 😈😈😈

# 好文

# 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]';
};
1
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 ,setTimeoutsetInterval ,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){
    // 执行某些操作
})  // 无返回值
1
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 );
}
1
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);
}
1
2
3
4
5
6
7

第二种就是使用 setTimeout 的第三个参数

for ( var i=1; i<=5; i++) {
	setTimeout( function timer(j) {
		console.log( j );
	}, i*1000, i);
}
1
2
3
4
5

第三种就是使用 let 定义 i 了

for ( let i=1; i<=5; i++) {
	setTimeout( function timer() {
		console.log( i );
	}, i*1000 );
}
1
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()
1
2
3
4
5
6
7

# 13.拆解url的各部分

使用location的属性

href 完整url地址
protocol 协议
host 主机名+端口号
hostname 主机名
port 端口号
pathname 相对路径
hash #锚点
search ?查询字符串
1
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"); 
1
2
3
4

DOM事件 DOM事件的级别

DOM0 element.onclick=function(){}
DOM2 element.addEventListener('click',function(){},false)
DOM3 element.addEventListener('keyup',function(){},false)
1
2
3

DOM0级事件就是将一个函数赋值给一个事件处理属性,缺点在于一个处理程序无法同时绑定多个处理函数。

DOM2级事件运行给一个程序添加多个处理函数,定义了addEventListenerremoveEventListener两个方法,分别用于绑定和解绑事件,方法包含三个参数分别是绑定的事件处理的属性名称,处理函数,是否在捕获时执行事件

IE8以下使用attachEvent和detachEvent实现,不需要传入第三个参数,因为IE8以下只支持冒泡型事件

btn.attachEvent('onclick', showFn);
btn.detachEvent('onclick', showFn);
1
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+溢出内容的尺寸
1
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);
1
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('验证通过')
    }
}
1
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()  向下取整
1
2
3
4
5

# 23. this

  • this指向

定义:this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

总结:

1.在普通函数内部,this的指向是window
2.在方法内部,this的指向是方法的拥有者。
3.在箭头函数内部,this指向是创建箭头函数时所在的环境中的this指向的值。
4.在对象中,this指向当前对象
1
2
3
4

这里的this指向会发生改变

5.计时器中的this
6.回调函数中的this
7.事件处理函数中的this指向事件的绑定者
1
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
}
1
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
}

1
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]))
  }
}
1
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)
            }
        }
1
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)
        })

1
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);
  };
};
1
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);
        }
    }
}
1
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—绘制

参考:从输入url到页面加载完成发生了什么? (opens new window)

最近更新时间: 2022/09/28 16:26:36
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00