前言
首先在这里祝大家在春招和校招都能找到一份自己如愿的工作,然后就是八股文是真的重要,尤其是js基础部分。然后就是希望我的文章能有帮到大家的地方
HTML5 新特性有哪些
- 语义化标签
- 音视频处理API(audio,video)
- canvas / webGL
- 拖拽释放(Drag and drop) API
- history API
- requestAnimationFrame
- 地理位置(Geolocation)API
- webSocket
- web存储 localStorage、SessionStorage
- 表单控件,calendar、date、time、email、url、search
HTML5 语义化的优点:
在没CSS样式的情况下,页面整体也会呈现很好的结构效果
代码结构清晰,易于阅读,
利于开发和维护 方便其他设备解析(如屏幕阅读器)根据语义渲染网页。
有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重
HTTP 状态码
- 1xx:指示信息类,表示请求已接受,继续处理(临时响应)
- 2xx:指示成功类,表示请求已成功接受
- 3xx:指示重定向,表示要完成请求必须进行更近一步的操作
- 4xx:指示客户端错误,请求有语法错误或请求无法实现
- 5xx:指示服务器错误,服务器未能实现合法的请求
常见状态码
- 【403】表示【服务器拒绝执行客户端的请求】
- 【404】表示【服务器找不到客户端所请求的资源(网页)】
- 【304】表示【所请求的资源并未修改(命中协商缓存)
介绍下 304 过程
缓存过期后向服务器发起请求验证缓存是否有效,有效的话则返回304。304多出现在对于静态资源的请求上面。对于静态资源来说:
当浏览器第一次发起请求时(请求头中没有If-Modified-Since),server会在响应中告诉浏览器这个资源最后修改的时间(响应头中的Last-Modified)。当你再次请求这个资源时,浏览器会询问server这个资源有没有被修改(请求头中If-Modified-Since)。
如果资源没有被修改,server返回304状态码,浏览器使用本地的缓存文件。
数组的常用方法有哪些?
- join(separator):将数组的元素组起一个字符串,以separator为分隔符,省略的话则用默认用逗号为分隔符
- push():将参数添加到原数组末尾,并返回数组的长度(修改原数组)
- pop():删除原数组最后一项,并返回删除元素的值;如果数组为空则返回undefined(修改原数组)
- shift():删除原数组第一项,并返回删除元素的值;如果数组为空则返回undefined
- slice(start,end):可以截取出数组某部份的元素为一个新的数组,有两个必填的参数,第一个是起始位置,第二个是结束位置( 操作时数字减1 ) 原数组不改变
- splice(start,deleteCount,val1,val2,…):从start位置开始删除deleteCount项,并从该位置起插入。(修改原数组)
- fill():使用特定值填充数组中的一个或多个元素(修改原数组)
- concat():可以将两个数组合并在一起,如果是使用ES6语法也可以用扩展运算符…来代替
- indexOf():返回当前值在数组中第一次出现位置的索引
- lastIndexOf():返回查找的字符串最后出现的位置,如果没有找到匹配字符串则返回 -1。
- every():判断数组中每一项是否都符合条件
- some():判断数组中是否存在满足的项
- includes():判断一个数组是否包含指定的值
- sort(orderfunction):按指定的参数对数组进行排序(修改原数组)
- reverse():将数组反序(修改原数组)
- forEach():循环遍历数组每一项(没有返回值)
- map():循环遍历数组的每一项(有返回值)
- copyWithin(): 从数组的指定位置拷贝元素到数组的另一个指定位置中(修改原数组)
- find(): 返回第一个匹配的值,并停止查找
- findIndex(): 返回第一个匹配值的索引,并停止查找
- toLocaleString()、toString():将数组转换为字符串
- flat()、flatMap():扁平化数组
- entries() 、keys() 、values():遍历数组
CSS 选择器及优先级
选择器
- id选择器(#myid)
- 类选择器(.myclass)
- 属性选择器(a[rel="external"])
- 伪类选择器(a:hover, li:nth-child)
- 标签选择器(div, h1,p)
- 相邻选择器(h1 + p)
- 子选择器(ul > li)
- 后代选择器(li a)
- 通配符选择器(*)
优先级:
- !important
- 内联样式(1000)
- ID选择器(0100)
- 类选择器/属性选择器/伪类选择器(0010)
- 元素选择器/伪元素选择器(0001)
- 关系选择器/通配符选择器(0000)
带!important 标记的样式属性优先级最高; 样式表的来源相同时: !important > 行内样式>ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性
== 和 === 区别
1. == 和 === 区别
== 表示相等 (值相等)
===表示恒等(类型和值都要相等)
js在比较的时候如果是 == 会先做类型转换,再判断值得大小,如果是===类型和值必须都相等。
2. == === 和 Object.is() 区别
== 相等,如果两边类型不一致,进行隐式转换后,再比较。+0 和 -0 相等, NaN 不等于任何数
=== 严格相等,如果类型不一致,就不相等。 +0 和 -0 相等, NaN 不等于任何数
Object.is() 严格相等,+0 和 -0 不相等, NaN 等于自身
script 标签放在 header 里和放在 body 底部里有什么区别?
放在 header 中
你能看到 html 第一时间被加载进来,但页面 body 内容迟迟没有渲染出来。因为在等待 header 标签中 script 脚本的加载,3 秒后,整个页面渲染完成。
放在 body 底部
这次 html 内容第一时间渲染完成,随后等待 js 的加载。
总结:
脚本会阻塞页面的渲染,所以推荐将其放在 body 底部,因为当解析到 script 标签时,通常页面的大部分内容都已经渲染完成,让用户马上能看到一个非空白页面。
另外你能看到多个脚本之间都是异步向服务器请求,他们之间不互相依赖,最终只等待 3 秒,而非 3+3+3 秒。
HTTP1、HTTP2、HTTP3 的区别 HTTP1.0:
HTTP1.0:
浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接
服务器完成请求处理后立即断开TCP连接。
简单来讲,每次与服务器交互,都需要新开一个连接
HTTP1.1:
引入了持久连接,即TCP连接默认不关闭,在同一个TCP连接里面,客户端可以同时发送多个请求
虽然允许复用TCP连接,但是同一个TCP连接里面,所有的数据通信是按次序进行的,服务器只有处理完一个请求,才会接着处理下一个请求。如果前面的处理特别慢,后面就会有许多请求排队等着
新增了一些请求方法,新增了一些请求头和响应头
HTTP2.0:
采用二进制格式而非文本格式
多路复用,只需一个连接即可实现并行
使用报头压缩,降低开销
服务器推送
HTTP3.0:
是 HTTP/3 中的底层支撑协议,该协议基于 UDP,又取了 TCP 中的精华,实现了即快又可靠的协议。
async
async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行
async
async函数返回一个promise对象,下面两种方法是等效的
function f() {return Promise.resolve('TEST');
}// asyncF is equivalent to f!
async function asyncF() {return 'TEST';
}
await
正常情况下,await命令后面是一个 Promise对象,返回该对象的结果。如果不是 Promise对象,就直接返回对应的值
示例 1
async function f(){
// 等同于
// return 123;
return await 123;
}
f().then(v => console.log(v))
// 123
注:上面代码中,await 命令的参数是数值 123,这时等同于 return 123。
示例 2
async function f() {
const p = new Promise((resolve,reject)=>{
resolve(100)
})
const a = 1
// await 等待promise的状态变化完成(pending->resolved, pending->rejected)
// 取出promise的值
const b = await p
console.log(a,b)//(1,100)
}
f()
不管await后面跟着的是什么,await都会阻塞后面的代码
async function fn1 (){
console.log(1)await fn2()
console.log(2) // 阻塞
}async function fn2 (){
console.log('fn2')
}fn1()
console.log(3)
上面的例子中,await
会阻塞下面的代码(即加入微任务队列),先执行 async
外面的同步代码,同步代码执行完,再回到 async
函数中,再执行之前阻塞的代码
所以上述输出结果为:1
,fn2
,3
,2
CSS3 新特性
- 过渡
/所有属性从原始值到制定值的一个过渡,运动曲线ease,运动时间0.5秒/
transition:all,.5s
- 动画
//animation:动画名称,一个周期花费时间,运动曲线(默认ease),动画延迟(默认0),播放次数(默认1),是否反向播放动画(默认normal),是否暂停动画(默认running)
/执行一次logo2-line动画,运动时间2秒,运动曲线为 linear/
animation: logo2-line 2s linear;
- 形状转换
//transform:适用于2D或3D转换的元素
//transform-origin:转换元素的位置(围绕那个点进行转换)。默认(x,y,z):(50%,50%,0)
transform:translate(30px,30px);
transform:rotate(30deg);
transform:scale(.8);
-
选择器:nth-of-type()
-
阴影 文字阴影: text-shadow: 2px 2px 2px #000;(水平阴影,垂直阴影,模糊距离,阴影颜色) 盒子阴影: box-shadow: 10px 10px 5px #999
-
边框 border-image: url(border.png);
-
背景
-
文字
-
渐变-
-
Filter(滤镜)
-
弹性布局、栅格布局、多列布局
-
媒体查询
加密算法
对称加密:加密和解密都用相同的密钥。
优缺点:效率高,算法简单,系统开销小,适合加密大量数据。安全性差。
- DES:分组式加密算法,以64位为分组对数据加密,加解密使用同一个算法。
- 3DES:三重数据加密算法,对每个数据块应用三次DES加密算法。
- AES:高级加密标准算法,目前已被广泛应用 非对称加密:采用公钥和私钥两种不同的密码来进行加解密。公钥和私钥是成对存在,公钥是从私钥中提取产生公开给所有人的,如果使用公钥对数据进行加密,那么只有对应的私钥(不能公开)才能解密,反之亦然。
- RSA:两个大素数相乘十分容易,但那时想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,可用于加密,也能用于签名。 (应用场景: 由于RSA算法的加密解密速度要比对称算法速度慢很多,在实际应用中,通常数据本身的加密和解密使用对称加密算法(AES)。 用RSA算法加密并传输对称算法所需的密钥。)
- DSA:数字签名算法,仅能用于签名,不能用于加解密。
- DSS:数字签名标准,可用于签名,也可以用于加解密。
JS 中的 8 种数据类型及区别
在JS中,我们已知有5种基本数据类型:String、Number、Boolean、Undefined、Null。
当ES6问世,新增基本数据类型:Symbol(ES6) BigInt(ES10)
一、Number类型:
专门保存数字的类型,可用于进行数学计算等的数值.
二、String类型:
专门用来保存字符串的类型;" ",用来存储字符串类型的文本.
三、Boolean类型:
专门用来保存真或者假的类型,值二选一,true or false
四、undefined类型:
只有一个值undefined,没有赋值的变量的默认值.
五、null类型:
不知向任何地址,手动赋值,清空内容等....
六、object / Symbol
Symbol在ES6中新定义,符号类型是唯一的并且不可修改。Symbol 指的是独一无二的值。
position 属性的值有哪些及其区别
position属性取值:static(默认)、relative、absolute、fixed、inherit、sticky。
float属性取值:none(默认)、left、right、inherit。
display属性取值:none、inline、inline-block、block、table相关属性值、inherit。
-
固定定位 fixed: 元素的位置相对于浏览器窗口是固定位置,即使窗口是滚动的它也不会移动。Fixed 定 位使元素的位置与文档流无关,因此不占据空间。 Fixed 定位的元素和其他元素重叠。(脱离文档流)
-
相对定位 relative: 如果对一个元素进行相对定位,它将出现在它所在的位置上。然后,可以通过设置垂直 或水平位置,让这个元素“相对于”它的起点进行移动。 在使用相对定位时,无论是 否进行移动,元素仍然占据原来的空间。因此,移动元素会导致它覆盖其它框。
-
绝对定位 absolute: 绝对定位的元素的位置相对于最近的已定位父元素,如果元素没有已定位的父元素,那 么它的位置相对于。absolute 定位使元素的位置与文档流无关,因此不占据空间。absolute 定位的元素和其他元素重叠。(脱离文档流)
-
粘性定位 sticky: 元素先按照普通文档流定位,然后相对于该元素在流中的 flow root(BFC)和 containing block(最近的块级祖先元素)定位。而后,元素定位表现为在跨越特定阈值前为相对定 位,之后为固定定位。
-
默认定位 Static: 默认值。没有定位,元素出现在正常的流中(忽略 top, bottom, left, right 或者 z-index 声 明)。 inherit: 规定应该从父元素继承 position 属性的值。
GET 与 POST 的区别
1.针对数据操作的类型不同.GET对数据进行查询,POST主要对数据进行增删改!简单说,GET是只读,POST是写。
2.参数大小不同. GET请求在URL中传送的参数是有长度的限制,而POST没有限制
3.安全性不同. GET参数通过URL传递,会暴露,不安全;POST放在Request Body中,相对更安全
4.浏览器回退表现不同 GET在浏览器回退时是无害的,而POST会再次提交请求
5.浏览器对请求地址的处理不同 GET请求地址会被浏览器主动缓存,而POST不会,除非手动设置
6.浏览器对响应的处理不同GET请求参数会被完整的保留在浏览器历史记录里,而POST中的参数不会被保留
var, cosnt, let 三者之间的区别
ES6之前创建变量用的是var,之后创建变量用的是let/const
- var 存在变量提升,而const和let不存在变量提升;
- let 不能重复定义 ; 关键字允许值的修改;
- const 不能重复定义 ; 关键字不允许的修改;
WebSocket
实现原理: 实现了客户端与服务端的双向通信,只需要连接一次,就可以相互传输数据,很适合实时通讯、数据实时更新等场景。
Websocket 协议与 HTTP 协议没有关系,它是一个建立在 TCP 协议上的全新协议,为了兼容 HTTP 握手规范,在握手阶段依然使用 HTTP 协议,握手完成之后,数据通过 TCP 通道进行传输。
Websoket 数据传输是通过 frame 形式,一个消息可以分成几个片段传输。这样大数据可以分成一些小片段进行传输,不用考虑由于数据量大导致标志位不够的情况。也可以边生成数据边传递消息,提高传输效率。
优点: 双向通信。客户端和服务端双方 都可以主动发起通讯。 没有同源限制。客户端可以与任意服务端通信,不存在跨域问题。 数据量轻。第一次连接时需要携带请求头,后面数据通信都不需要带请求头,减少了请求头的负荷。 传输效率高。因为只需要一次连接,所以数据传输效率高。
缺点: 长连接需要后端处理业务的代码更稳定,推送消息相对复杂; 兼容性,WebSocket 只支持 IE10 及其以上版本。 服务器长期维护长连接需要一定的成本,各个浏览器支持程度不一; 【需要后端代码稳定,受网络限制大,兼容性差,维护成本高,生态圈小】
Socket 连接的步骤
建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。
1、服务器监听:处于等待连接的状态,实时监控网络状态,等待客户端的连接请求
2、客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。
客户端的套接字:指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。
3、连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。
而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。
谈谈盒子模型?
在标准盒子模型中,width 和 height 指的是内容区域的宽度和高度。增加内边距、边框和外边距不会 影响内容区域的尺寸,但是会增加元素框的总尺寸。
IE盒子模型中,width 和 height 指的是内容区域+border+padding的宽度和高度。
BFC(块级格式上下文)
BFC的概念
BFC 是 Block Formatting Context的缩写,即块级格式化上下文。BFC是CSS布局的一个概念,是一个独立的渲染区域,规定了内部box如何布局, 并且这个区域的子元素不会影响到外面的元素,其中比较重要的布局规则有内部 box 垂直放置,计算 BFC 的高度的时候,浮动元素也参与计算。
BFC的原理布局规则
- 内部的Box会在垂直方向,一个接一个地放置
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反
- BFC的区域不会与float box重叠
- BFC是一个独立容器,容器里面的子元素不会影响到外面的元素
- 计算BFC的高度时,浮动元素也参与计算高度
- 元素的类型和display属性,决定了这个Box的类型。不同类型的Box会参与不同的Formatting Context。
如何创建BFC?
- 根元素,即HTML元素
- float的值不为none
- position为absolute或fixed
- display的值为inline-block、table-cell、table-caption
- overflow的值不为visible
BFC的使用场景
- 去除边距重叠现象
- 清除浮动(让父元素的高度包含子浮动元素)
- 避免某元素被浮动元素覆盖
- 避免多列布局由于宽度计算四舍五入而自动换行
数据类型判断 instanceof 和 typeof 的区别
1.typeof
console.log(typeof 1); // number
console.log(typeof true); // boolean
console.log(typeof 'mc'); // string
console.log(typeof Symbol) // function
console.log(typeof function(){}); // function
console.log(typeof console.log()); // function
console.log(typeof console.log); // undefined
console.log(typeof []); // object
console.log(typeof {}); // object
console.log(typeof null); // object
console.log(typeof undefined); // undefined
优点:能够快速区分基本数据类型
缺点:不能将Object、Array和Null区分,都返回object
2.instanceof
console.log(1 instanceof Number); // false
console.log(true instanceof Boolean); // false
console.log('str' instanceof String); // false
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
console.log({} instanceof Object); // true
优点:能够区分Array、Object和Function,适合用于判断自定义的类实例对象
缺点:Number,Boolean,String基本数据类型不能判断
3.Object.prototype.toString.call()
var toString = Object.prototype.toString;
console.log(toString.call(1)); //[object Number]
console.log(toString.call(true)); //[object Boolean]
console.log(toString.call('mc')); //[object String]
console.log(toString.call([])); //[object Array]
console.log(toString.call({})); //[object Object]
console.log(toString.call(function(){})); //[object Function]
console.log(toString.call(undefined)); //[object Undefined]
console.log(toString.call(null)); //[object Null]
优点:精准判断数据类型
缺点:写法繁琐不容易记,推荐进行封装后使用
隐藏页面元素的方法
1.opacity:0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定 一些事件,如click 事件,那么点击该区域,也能触发点击事件的
2.visibility:hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已 经绑定的事件 ,隐藏对应元素,在文档布局中仍保留原来的空间(重绘)
3.display:none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素。 不显示对应的元素,在文档布局中不再分配空间(回流+重绘)
该问题会引出 回流和重绘
DNS 协议是什么?
DNS服务器通过多层查询将解析域名为IP地址
域名劫持:是指在劫持的网络范围内拦截域名解析的请求,分析请求的域名,把审查范围以外的请求放行,否则返回假的IP地址或者什么都不做使请求失去响应,其效果就是对特定的网络不能访问或访问的是假网址。
深拷贝浅拷贝的区别
浅拷贝: 如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
- Object.assign
- Array.prototype.slice(), Array.prototype.concat()
- 使用拓展运算符实现的复制
深拷贝: 深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
常见的深拷贝方式有:
- _.cloneDeep()
- jQuery.extend()
- JSON.stringify()
- 手写循环递归
浏览器的主要功能
是向服务器发出请求,在浏览器窗口中展示所选择的网络资源。这里所说的资源一般是指 HTML 文档,也可以是 PDF、图片或其他的类型。资源的位置由用户使用 URI(统一资源标示符)指定。
浏览器的主要组成部分是什么?
1、用户界面 - 包括地址栏、前进/后退按钮、书签菜单等。
2、浏览器引擎 - 在用户界面和呈现引擎之间传送指令。
3、呈现引擎 - 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTML 和 CSS 内容,并将解析后的内容显示在屏幕上。
4、网络 - 用于网络调用,比如 HTTP 请求。其接口与平台无关,并为所有平台提供底层实现。
5、用户界面后端 - 用于绘制基本的窗口小部件,比如组合框和窗口。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
6、JavaScript 解释器。用于解析和执行 JavaScript 代码。
7、数据存储。这是持久层。浏览器需要在硬盘上保存各种数据,例如 Cookie。
闭包
闭包的特性:
- 闭包让你可以在一个内层函数中访问到其外层函数的作用域 函数嵌套函数
- 延长变量的生命周期 在内存中维持一个变量
- 一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的
闭包形成的条件:
- 函数的嵌套
- 内部函数引用外部函数的局部变量,延长外部函数的变量生命周期
闭包缺点:会导致函数的变量一直保存在自己内存中,过多的闭包可能会导致内存泄漏
闭包应用场景
闭包的两个场景,闭包的两大作用:保存/保护。 在开发中, 其实我们随处可见闭包的身影, 大部分前端JavaScript 代码都是“事件驱动”的,即一个事件绑定的回调方法; 发送ajax请求成功|失败的回调;setTimeout的延时回调;或者一个函数内部返回另一个匿名函数,这些都是闭包的应用。
Rem 布局
首先 Rem 相对于根(html)的 font-size 大小来计算。简单的说它就是一个相对单例 如:font-size:10px;
那么(1rem = 10px)了解计算原理后首先解决怎么在不同设备上设置 html 的 font-size 大小。其实 rem 布局的本质是等比缩放,一般是基于宽度。
优点:可以快速适用移动端布局,字体,图片高度
缺点:
①目前 ie 不支持,对 pc 页面来讲使用次数不多;
②数据量大:所有的图片,盒子都需要我们去给一个准确的值;才能保证不同机型的适配;
③在响应式布局中,必须通过 js 来动态控制根元素 font-size 的大小。也就是说 css 样式和 js 代码有一定的耦合性。且必须将改变 font-size 的代码放在 css 样式之前。
浏览器是如何渲染 UI 的?
浏览器是如何渲染UI的?
1、浏览器获取HTML文件,然后对文件进行解析,形成DOM Tree
2、与此同时,进行CSS解析,生成Style Rules
3、接着将DOM Tree与Style Rules合成为 Render Tree
4、接着进入布局(Layout)阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标
5、随后调用GPU进行绘制(Paint),遍历Render Tree的节点,并将元素呈现出来
DOM Tree是如何构建的?
1、转码: 浏览器将接收到的二进制数据按照指定编码格式转化为HTML字符串
2、生成Tokens: 之后开始parser,浏览器会将HTML字符串解析成Tokens
3、构建Nodes: 对Node添加特定的属性,通过指针确定 Node 的父、子、兄弟关系和所属 treeScope
4、生成DOM Tree: 通过node包含的指针确定的关系构建出DOM
浏览器重绘与回流
浏览器是如何渲染UI的?
1、浏览器获取HTML文件,然后对文件进行解析,形成DOM Tree
2、与此同时,进行CSS解析,生成Style Rules
3、接着将DOM Tree与Style Rules合成为 Render Tree
4、接着进入布局(Layout)阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标
5、随后调用GPU进行绘制(Paint),遍历Render Tree的节点,并将元素呈现出来
DOM Tree是如何构建的?
1、转码: 浏览器将接收到的二进制数据按照指定编码格式转化为HTML字符串
2、生成Tokens: 之后开始parser,浏览器会将HTML字符串解析成Tokens
3、构建Nodes: 对Node添加特定的属性,通过指针确定 Node 的父、子、兄弟关系和所属 treeScope
4、生成DOM Tree: 通过node包含的指针确定的关系构建出DOM重排/回流(Reflow):当DOM的变化影响了元素的几何信息,浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。表现为重新生成布局,重新排列元素。
回流:1、布局引擎会根据各种样式计算每个盒子在页面上的大小与位置。
2、改变元素的位置和尺寸大小都会引发回流
重绘(Repaint): 当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。表现为某些元素的外观被改变。
重绘:1、当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制。
2、『回流』必定会发生『重绘』,『重绘』不一定会引发『回流』。
重绘与重排的区别?
重排/回流(Reflow):当DOM的变化影响了元素的几何信息,浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。表现为重新生成布局,重新排列元素。
重绘(Repaint): 当一个元素的外观发生改变,但没有改变布局,叫做重绘。表现为某些元素的外观被改变
『重绘』不一定会出现『重排』,『重排』必然会出现『重绘』。
如何触发重排和重绘?
- 添加、删除、更新DOM节点
- 通过display: none隐藏一个DOM节点-触发重排和重绘
- 通过visibility: hidden隐藏一个DOM节点-只触发重绘
- 移动或者给页面中的DOM节点添加动画
- 添加一个样式表,调整样式属性
- 用户行为,例如调整窗口大小,改变字号,或者滚动。
如何避免重绘或者重排?
-
集中改变样式,不要一条一条地修改 DOM 的样式。
-
不要把 DOM 结点的属性值放在循环里当成循环里的变量。
-
尽量只修改position:absolute或fixed元素,对其他元素影响不大
-
提升为合成层
优点:
- 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
- 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
- 对于 transform 和 opacity 效果,不会触发 layout 和 paint
方式:是使用 CSS 的 will-change 属性
#target {
will-change:transform
}
Cookie、sessionStorage、localStorage 的区别
相同点:
存储在客户端
不同点:
- cookie数据大小不能超过4k;sessionStorage和localStorage的存储比cookie大得多,可以达到5M+
- cookie设置的过期时间之前一直有效;localStorage永久存储,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删
- cookie的数据会自动的传递到服务器;sessionStorage和localStorage数据保存在本地
indexDB
seesionStorage只能存储字符串的数据,对于JS中常用的数组或对象却不能直接存储,我们可以通过JSON.stringify()将json数据类型转化成字符串,再存储到storage中就可以了,获取数据时再使用JSON.parse()将读取的字符串转换成对象即可。
- 新打开的标签页会复制父级的 sessionStorage,类似于深拷贝,之后 sessionStorage 的变更不会同步。
- 相同 url 的多个 tab 页,sessionStorage 并不会同步,也就是说它们不属于同一个 session。
应用场景:
-
标记用户与跟踪用户行为的情况,推荐使用cookie
-
适合长期保存在本地的数据(令牌),推荐使用localStorage
-
敏感账号一次性登录,推荐使用sessionStorage
-
存储大量数据的情况、在线文档(富文本编辑器)保存编辑历史的情况,推荐使用indexedDB
JS 中 this 的情况
1、普通函数调用:通过函数名()直接调用:this指向全局对象window(注意let定义的变量不是window属性,只有window.xxx定义的才是。即let a =’aaa’; this.a是undefined)
2、构造函数调用:函数作为构造函数,用new关键字调用时:this指向新new出的对象
3、对象函数调用:通过对象.函数名()调用的:this指向这个对象
4、箭头函数调用:箭头函数里面没有 this ,所以永远是上层作用域this(上下文)
5、apply和call调用:函数体内 this 的指向的是 call/apply 方法第一个参数,若为空默认是指向全局对象window。
6、函数作为数组的一个元素,通过数组下标调用的:this指向这个数组
7、函数作为window内置函数的回调函数调用:this指向window(如setInterval setTimeout 等)
箭头函数有哪些特征,请简单描述一下它?
- 箭头函数没有自己的this,this指向定义箭头函数时所处的外部执行环境的this
- 即时调用call/apply/bind也无法改变箭头函数的this
- 箭头函数本身没有名字
- 箭头函数不能new,会报错
- 箭头函数没有arguments,在箭头函数内访问这个变量访问的是外部执行环境的arguments
- 箭头函数没有prototype
CSS 预处理器 Sass、Less、Stylus 的区别
什么是CSS预处理器?
CSS预处理器是一种语言用来为CSS增加一些变成的特性,无需考虑浏览器兼容问题,例如你可以在CSS中使用变量,简单的程序逻辑、函数等在编程语言中的一些基本技巧,可以让CSS更加简洁,适应性更强,代码更直观等诸多好处
基本语法区别
Sass是以.sass为扩展名,Less是以.less为扩展名,Stylus是以.styl为扩展名
变量的区别
Sass 变量必须是以$
开头的,然后变量和值之间使用冒号(:)隔开,和css属性是一样的。 Less 变量是以@开头的,其余sass都是一样的。 Stylus 对变量是没有任何设定的,可以是以$开头或者任意字符,而且变量之间可以冒号,空格隔开,但是在stylus中不能用@开头
前端性能优化
1、减少http请求数;2、图片优化;3、使用CDN;4、开启GZIP;5、构建优化;
-
减少http请求数
1)合并图片。当图片较多时,可以合并为一张大图,从而减少http请求数。
2)合并压缩css样式表和js脚本。
一般我们会把css样式表文件放到文件的头部。比如,放到标签中,这样可以让CSS样式表尽早地完成下载。对应js脚本文件,一般我们把他放到页面的尾部。
3)充分利用缓存。 -
图片优化
1)尽可能的使用PNG格式的图片,它相对来说体积较小。
2)图片的延迟加载,也叫做懒加载。 -
使用CDN
CDN即内容分发网络,可以使用户就近取得所需内容,解决网络拥挤的状况,提高用户访问网站的响应速度。 -
开启GZIP
GZIP即数据压缩,用于压缩使用Internet传输的所有文本资源。开启GZIP的方法很简单,到对应的web服务配置文件中设置一下即可。以Apache为例,在配置文件httpd.conf中添加。 -
构建优化
使用 Tree-shaking、Scope hoisting、Code-splitting
Tree-shaking是一种在构建过程中清除无用代码的技术。使用Tree-shaking可以减少构建后文件的体积。
元素水平垂直居中
仅居中元素定宽高适用
- absolute + 负margin
- absolute + margin auto
- absolute + calc
居中元素不定宽高
- absolute + transform
- lineheight
- writing-mode
- table
- css-table
- flex
- grid
- PC端有兼容性要求,宽高固定,推荐absolute + 负margin
- PC端有兼容要求,宽高不固定,推荐css-table
- PC端无兼容性要求,推荐flex
- 移动端推荐使用flex
一个页面从输入 URL 到页面加载显示完成,这个过程中都发生 了什么?
- 01.浏览器查找域名对应的IP地址(DNS 查询:浏览器缓存->系统缓存->路由器缓存->ISP DNS 缓存->根 域名服务器)
- 02.浏览器向 Web 服务器发送一个 HTTP 请求(TCP三次握手
- 03.服务器 301 重定向(从 example.com 重定向到 www.example.com)
- 04.浏览器跟踪重定向地址,请求另一个带 www 的网址
- 05.服务器处理请求(通过路由读取资源)
- 06.服务器返回一个 HTTP 响应(报头中把 Content-type 设置为 'text/html')
- 07.浏览器进 DOM 树构建
- 08.浏览器发送请求获取嵌在 HTML 中的资源(如图片、音频、视频、CSS、JS等)
- 09.浏览器显示完成页面
- 10.浏览器发送异步请求
跨域
明跨域访问的限制并不是浏览器限制发送请求,而是浏览器阻止了请求后数据的加载渲染
- 定义:
- 跨域:是由浏览器的同源策略造成的。
- 同源策略,是浏览器对 JavaScript 实施的安全限制,只要协议、域名、端口有任何一个不同,都被当作是不同的域。
- 跨域原理,即是通过各种方式,避开浏览器的安全限制。
- 解决方案: 最初做项目的时候,使用的是 jsonp,但存在一些问题,使用 get 请求不安全,携带数据较小,后来通过了解和学习发现使用 proxy 代理使用比较方便--在开发中使用 proxy,在服务器上使用 nginx 代理,这样开发过程中彼此都方便,效率也高;现在 h5 新特性还有 windows.postMessage()
- JSONP: ajax 请求受同源策略影响,不允许进行跨域请求,而 script 标签 src 属性中的链接却可以访问跨域的 js 脚本,利用这个特性,服务端不再返回 JSON 格式的数据,而是 返回一段调用某个函数的 js 代码,在 src 中进行了调用,这样实现了跨域。
- 步骤: ① 去创建一个 script ② script 的 src 属性设置接口地址 ③ 接口参数,必须要带一个自定义函数名,要不然后台无法返回数据 ④ 通过定义函数名去接受返回的数据
//动态创建 script
var script = document.createElement('script');
// 设置回调函数
function getData(data) {
console.log(data);
}
//设置 script 的 src 属性,并设置请求地址
script.src = 'http://localhost:3000/?callback=getData';
// 让 script 生效
document.body.appendChild(script);
- 缺点: JSON 只支持 get,因为 script 标签只能使用 get 请求; JSONP 需要后端配合返回指定格式的数据。
- CORS CORS:使用额外的 HTTP 头来告诉浏览器 让运行在一个 origin上的Web应用被准许访问来自不同源服务器上的指定的资源。服务器设置对CORS的支持原理:服务器设置Access-Control-Allow-Origin HTTP响应头之后,浏览器将会允许跨域请求
- 最方便的跨域方案 proxy代理+ Nginx nginx是一款极其强大的web服务器,其优点就是轻量级、启动快、高并发。 跨域问题的产生是因为浏览器的同源政策造成的,但是服务器与服务器之间的数据交换是没有这个限制。
- 反向代理就是采用这种方式,建立一个虚拟的代理服务器来接收 internet 上的链接请求,然后转发给内部网络上的服务器,并将从服务器上得到的结果,返回给 internet 上请求链接的客户端。现在的新项目中nginx几乎是首选,我们用node或者java开发的服务通常都需要经过nginx的反向代理。
Event Loop 的执行顺序
宏任务
- Task Queue
- 常见宏任务:setTimeout、setInterval、setImmediate、I/O、script、UI rendering
微任务
- Job Queue
- 常见微任务:
- 浏览器:Promise、MutationObserver
- Node.js:process.nextTick
执行顺序
-
首先执行同步代码,宏任务
-
同步栈为空,查询是否有异步代码需要执行
-
执行所有微任务
-
执行完,是否需要渲染页面
-
重新开始 Event Loop,执行宏任务中的异步代码
什么是原型 ? 什么是原型链 ?
JavaScript 一种基于原型的语言——每个函数对象都有一个 prototype 属性,这个属性指向函数的原型对象。 原型关系:
- 每个 class都有显示原型 prototype
- 每个实例都有隐式原型 proto
- 实例的 proto 指向对应 class 的 prototype
当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
原型链:函数的原型链对象 constructor 默认指向函数本身,原型对象除了有原型属性外,为了实现继承,还有一个原型链指针 proto, 该指针是指向上一层的原型对象,而上一层的原型对象的结构依然类似。因此可以利用__proto__一直指向Object的原型对象上,而 Object 原型对象用 Object.prototype.__ proto__ = null 表示原型链顶端。如此形成了js的原型链继承。
特点: JavaScript 对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
什么是作用域 ? 什么是作用域链 ?
创建函数的时候,已经声明了当前函数的作用域 ==>当前创建函数所处的上下文。
- 定义:简单来说作用域就是变量与函数的可访问范围,由当前环境与上层环境的一系列变量对象组成
- 全局作用域:代码在程序的任何地方都能被访问,window 对象的内置属性都拥有全局作用域。
- 函数作用域:在固定的代码片段才能被访问
- 作用域:作用域最大的用处就是隔离变量,不同作用域下同名变量不会有冲突
- 作用域链:一般情况下,变量到 创建该变量 的函数的作用域中取值。但是如果在当前作用域中没有查到,就会向上级作用域去查,直到查到全局作用域,这么一个查找过程形成的链条就叫做作用域链。
图片懒加载是怎么实现的?
就是我们先设置图片的data-set属性(当然也可以是其他任意的,只要不会发送http请求就行了,作用 就是为了存取值)值为其图片路径,由于不是src,所以不会发送http请求。 然后我们计算出页面 scrollTop的高度和浏览器的高度之和, 如果图片距离页面顶端的坐标Y(相对于整个页面,而不是浏览 器窗口)小于前两者之和,就说明图片就要显示出来了(合适的时机,当然也可以是其他情况),这时 候我们再将 data-set 属性替换为 src 属性即可。
谈谈set 、 map 是什么?
set 是es6 提供的一种新的数据结构,它类似于数组,但是成员的值都是唯一的。 map 是es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是键的范围不仅限于字符 串,各种类型的值都可以当做键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供 了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
v-for 循环为什么一定要绑定key ?
页面上的标签都对应具体的虚拟dom对象(虚拟dom就是js对象), 循环中 ,如果没有唯一key , 页面上删除 一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟dom重新渲染, 如果知道key为x标签被删除 掉, 只需要把渲染的dom为x的标签去掉即可!
组件中的data为什么要定义成一个函数而不是一个对象?
每个组件都是 Vue 的实例。组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一 个会影响其他
vue实例是挂载到那个标签上的?
vue实例最后会挂载在body标签里面,所以我们在vue中是获取不了body 标签的,如果要使用body标 签的话需要用原生的方式获取
js的执行机制是怎么样的?
- js是一个单线程、异步、非阻塞I/O模型、 event loop事件循环的执行机制
- 所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。 同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。异步 任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程, 某个异步任务可以执行了,该任务才会进入主线程执行。
vue中computed 和watch 的区别是什么?
computed计算属性就是为了简化template里面模版字符串的计算复杂度、防止模版太过冗余。它具有 缓存特性
computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就 可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
watch主要用于监控vue实例的变化,它监控的变量当然必须在data里面声明才可以,它可以监控一个 变量,也可以是一个对象,一般用于监控路由、input输入框的值特殊处理等等,它比较适合的场景是 一个数据影响多个数据,它不具有缓存性
- watch:监测的是属性值, 只要属性值发生变化,其都会触发执行回调函数来执行一系列操作。
- computed:监测的是依赖值,依赖值不变的情况下其会直接读取缓存进行复用,变化的情况下才 会重新计算。
除此之外,有点很重要的区别是:计算属性不能执行异步任务,计算属性必须同步执行。也就是说计算 属性不能向服务器请求或者执行异步任务。如果遇到异步任务,就交给侦听属性。watch也可以检测 computed属性。
什么vuex ,谈谈你对它的理解?
- 首先vuex的出现是为了解决web组件化开发的过程中,各组件之间传值的复杂和混乱的问题
- 将我们在多个组件中需要共享的数据放到store中,
- 要获取或格式化数据需要使用getters,
- 改变store中的数据,使用mutation,但是只能包含同步的操作,在具体组件里面调用的方式 this.$store.commit('xxxx')
- Action也是改变store中的数据,不过是提交的mutation,并且可以包含异步操作,在组件中的调 用方式 this.$store.dispatch('xxx') ; 在actions里面使用的commit('调用mutation')
后台管理系统中的权限管理是怎么实现的?
-
登录:当用户填写完账号和密码后向服务端验证是否正确,验证通过之后,服务端会返回一个token, 拿到token之后(我会将这个token存贮到cookie中,保证刷新页面后能记住用户登录状态),前端会 根据token再去拉取一个 user_info 的接口来获取用户的详细信息(如用户权限,用户名等等信息)。
-
权限验证:通过token获取用户对应的 权限,动态根据用户的 权限算出其对应有权限的路由,通过 router.addRoutes 动态挂载这些路由。
-
具体思路: 登录成功后,服务端会返回一个 token(该token的是一个能唯一标示用户身份的一个key),之后我 们将token存储在本地cookie之中,这样下次打开页面或者刷新页面的时候能记住用户的登录状态,不 用再去登录页面重新登录了。
ps:为了保证安全性,我司现在后台所有token有效期(Expires/Max-Age)都是Session,就是当浏览器关 闭了就丢失了。重新打开游览器都需要重新登录验证,后端也会在每周固定一个时间点重新刷新 token,让后台用户全部重新登录一次,确保后台用户不会因为电脑遗失或者其它原因被人随意使用账 号。
用户登录成功之后,我们会在全局钩子 router.beforeEach 中拦截路由,判断是否已获得token,在 获得token之后我们就要去获取用户的基本信息了
页面会先从 cookie 中查看是否存有 token,没有,就走一遍上一部分的流程重新登录,如果有token, 就会把这个 token 返给后端去拉取user_info,保证用户信息是最新的。 当然如果是做了单点登录得功 能的话,用户信息存储在本地也是可以的。当你一台电脑登录时,另一台会被提下线,所以总会重新登 录获取最新的内容。
先说一说我权限控制的主体思路,前端会有一份路由表,它表示了每一个路由可访问的权限。当用户登 录之后,通过 token 获取用户的 role ,动态根据用户的 role 算出其对应有权限的路由,再通过 router.addRoutes 动态挂载路由。但这些控制都只是页面级的,说白了前端再怎么做权限控制都不是 绝对安全的,后端的权限验证是逃不掉的。
我司现在就是前端来控制页面级的权限,不同权限的用户显示不同的侧边栏和限制其所能进入的页面(也 做了少许按钮级别的权限控制),后端则会验证每一个涉及请求的操作,验证其是否有该操作的权限,每 一个后台的请求不管是 get 还是 post 都会让前端在请求 header 里面携带用户的 token,后端会根据 该 token 来验证用户是否有权限执行该操作。若没有权限则抛出一个对应的状态码,前端检测到该状 态码,做出相对应的操作。
使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
具体实现:
创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页 面。
当用户登录后,获取用role,将role和路由表每个页面的需要的权限作比较,生成最终用户可访问的路 由表。
调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由。
使用vuex管理路由表,根据vuex中可访问的路由渲染侧边栏组件。
平时都是用那些工具进行打包的?babel是什么?
WebPack 是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块们所需的静 态文件。它能够很好地管理、打包Web开发中所用到的HTML、Javascript、CSS以及各种静态文件(图 片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack 模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源
babel可以帮助我们转换一些当前浏览器不支持的语法,它会把这些语法转换为低版本的语法以便浏览 器识别。