rgba()和 opacity区别
由上图运行结果可说明:
opacity的透明度会影响子元素----作用于元素以及元素内所有内容的透明度
rgba()的透明度不会影响子元素 ----只作用于元素的颜色或背景色
z-index:0和z-index:auto的区别
z-index:0 会创建一个新的层叠上下文
z-index:auto不会
0在auto的上面
伪元素和伪类的区别和作用?
为什么有时候⽤translate 来改变位置⽽不是定位?
实现元素居中对齐
纯定位(不推荐)
父元素
position: relative;
子元素
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
margin: auto;
或者
父元素
position: relative;
子元素
position: absolute;
top: 50%;
left: 50%;
margin-left: -50px;
margin-top: -50px;
(兼容性好,但是要知道元素高度)
定位+transform
父元素
position: relative;
子元素
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
(兼容性好,但是要知道元素高度)
flex布局
父元素
display: flex;
justify-content: center; (水平居中)
align-items: center;(垂直居中)
(不需要元素高度,但可能需要考虑兼容性)
详情介绍,请欣赏:
CSS实现水平垂直居中的10种方式
图片居中对齐
定位+transform
父元素 position: relative; 子元素 position: absolute; top: 50%; left: 50%;
transform: translate(-50%,-50%);
(要给父元素一个高度)
display:table
此处使用得、的 dom 结构是三层(div.fa>div.son>img)
注意第三层,即在(son内部)display 设置为 table-cell 内部的 元素应该是 行内块元素或者行内元素。
这不难理解,table 内本身(div.fa 此时已相当于一个table元素)就该写内容,内部应该在嵌套元素了
flex布局
水平居中
text-align:center
margin:auto
子绝父相+transform: translateX(-50%)
flex布局+justify-content: center ;
垂直居中
line-height: 父盒子高度;
定位
flex布局+align-items: center ;
多行文字居中对齐
父级高度不固定时
高度只能通过内部文本来撑开。所以,我们可以通过设置内填充(padding)的值来使文本看起来垂直居中,只需
设置padding-top和padding-bottom的值相等
父级元素高度固定
使用
vertical-align:middle ;display:table-cell
使文字垂直居中
CSS实现等腰三角形
用flex实现九宫格
设置padding-top/padding-bottom:a%,与宽度的百分比相等,就是个正方形。
padding和margin区别
作用对象不同
padding是作用于自身的 margin是作用于外部的
vw与百分比区别 px rem em 区别
绝对长度
px
固定的长度,写多少就是多少。
相对长度
%
基于父元素的设置
vw vh
根据窗口的宽高,分成100等份,100vh就表示满高,50vh就表示一半高。
em
相对于父元素的font-size
默认情况下font-size = 16px,那么1em = 16px
rem
相对于html根元素的font-size
默认情况下font-size = 16px,那么1rem = 16px
行内元素与块级元素,行内块元素
每个元素都有 display 属性,确定该元素的类型,如 div 默认 display 属性值为“block”,成为“块级”
元素; span 默认display 属性值为“inline”,是“行内”元素。
行内元素的宽高与内容有关系 不会自动换行
a b span img input select strong
margin padding只能设置左右 不能设置上下
块级元素 会继承父级 可以自动换行
div 、p、h1~h6、hr、ul、ol、li、dl、dd、form、table、header、footer、main、nav、section、arcitcle、pre、table、tbody、thead、th、tr、
都可以设置 但是会造成margin重叠
空元素
br,hr,img,input,link,meta
行内块元素 具有行内元素的特点 又有块级元素的特点
img input td
display:inline-block; /* 元素以行内形式排列,以块级形式展示 */
margin paddinig不对产生任何影响
说一下 slice splice split 的区别?
slice
-----数组-不会改变原数组
// slice(start,[end])
// slice(start,[end])方法:该方法是对数组进行部分截取,该方法返回一个新数组
// 参数start是截取的开始数组索引,end参数等于你要取的最后一个字符的位置值加上1(可选)。
// 包含了源函数从start到 end 所指定的元素,但是不包括end元素,比如a.slice(0,3);
// 如果出现负数就把负数与长度相加后再划分。
// slice中的负数的绝对值若大于数组长度就会显示所有数组
// 若参数只有一个,并且参数大于length,则为空。
// 如果结束位置小于起始位置,则返回空数组
// 返回的个数是end-start的个数
// 不会改变原数组
var arr = [1,2,3,4,5,6]
/*console.log(arr.slice(3))//[4,5,6] 从下标为0的到3,截取3之后的数console.log(arr.slice(0,3))//[1,2,3] 从下标为0的地方截取到下标为3之前的数console.log(arr.slice(0,-2))//[1,2,3,4]console.log(arr.slice(-4,4))//[3,4]console.log(arr.slice(-7))//[1,2,3,4,5,6]console.log(arr.slice(-3,-3))// []console.log(arr.slice(8))//[]*/
// 个人总结:slice的参数如果是正数就从左往右数,如果是负数的话就从右往左边数,
// 截取的数组与数的方向一致,如果是2个参数则截取的是数的交集,没有交集则返回空数组
// ps:slice也可以切割字符串,用法和数组一样,但要注意空格也算字符
splice
----数组-会改变原数组
// splice(start,deletecount,item)
// start:起始位置
// deletecount:删除位数
// item:替换的item
// 返回值为被删除的字符串
// 如果有额外的参数,那么item会插入到被移除元素的位置上。
// splice:移除,splice方法从array中移除一个或多个数组,并用新的item替换它们。
//举一个简单的例子
var a=['a','b','c'];
var b=a.splice(1,1,'e','f');
console.log(a) //['a', 'e', 'f', 'c']
console.log(b) //['b']
var a = [1, 2, 3, 4, 5, 6];
//console.log("被删除的为:",a.splice(1, 1, 8, 9)); //被删除的为:2
// console.log("a数组元素:",a); //1,8,9,3,4,5,6
// console.log("被删除的为:", a.splice(0, 2)); //被删除的为:1,2
// console.log("a数组元素:", a) //3,4,5,6
console.log("被删除的为:", a.splice(1, 0, 3, 3)) //插入 第二个数为0,表示删除0个 []
console.log("a数组元素:", a) //[1, 3, 3, 2, 3, 4, 5, 6]
split
-----字符串-不会改变原字符串
// split(字符串)
// string.split(separator,limit):split方法把这个string分割成片段来创建一个字符串数组。
// 可选参数limit可以限制被分割的片段数量。
// separator参数可以是一个字符串或一个正则表达式。
// 如果separator是一个空字符,会返回一个单字符的数组,不会改变原数组。
var a="0123456";
var b=a.split("",3);
console.log(b);//b=["0","1","2"]
// 注意:String.split() 执行的操作与 Array.join 执行的操作是相反的。
如何让谷歌浏览器支持小字体
transform: scale(指定值);
var let const
var:
可以先使用后声明,存在变量提升 全局作用域
let:
块级作用域,存在暂时性死区 不允许重复声明 必须先声明后使用,不存在变量提升
const:
与let类似,
但是多了两点更强的约束:
声明时必须赋值 声明的变量内存地址不可改变
(对于用const声明基本类型,值就保存在内存地址之中,意味着变量不可重新赋值;对于用const声明的对象,对象内容还是可以更改的,只是不能改变其指向。)
补充:
谈谈变量提升
在生成执行环境时,会有两个阶段。第一个是创建阶段,js解析器会找出需要提升的变量和函数,并且给他们提前开辟好内存空间,函数的话会将整个函数存入到内存中,变量只声明并赋值为undefined,所以在第二个阶段,也就是代码执行阶段,我们可以直接提前使用。
深拷贝和浅拷贝
都只针对引用数据类型
浅拷贝—改变数据会影响旧数据 (藕断丝连)
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,可以通过Object.assign或**展开运算符(…)**来解决问题。
深拷贝—改变数据不会影响旧数据(毫无关系)
深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
使用**JSON.parse(JSON.stringify())**实现深拷贝:JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象;
但是该⽅法也是有局限性的:
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引⽤的对象
采用递归去拷贝所有层级属性。递归--------很重要!!!
循环递归的原理就是循环过程中判断值的类型,如果为对象类型,则在对象类型的数据里边进行进一步循环赋值,直到循环对象里面没有对象类型的数据为止
在浏览器中输入URL并回车都发生了什么
URL解析->DNS查询->TCP连接->处理请求->接受响应->渲染页面
渲染到页面
HTML被解析成DOM树,CSS被解析成CSS结构体,结合DOM树和CSS结构体,生成一颗渲染树,生成布局,将布局绘制在屏幕上。
补充:
CSS加载会阻塞DOM渲染吗?会阻塞DOM解析吗?
从上图可以看出:
CSS加载和DOM解析是两个并行的进程,互不影响。即不会阻塞DOM解析。 CSS加载完成之后才会渲染DOM,所以CSS加载会阻塞DOM渲染。
详细介绍可参考:
css加载会造成阻塞吗
TCP 三次握手(建立连接)
1)、客户端发送带有 SYN 标识(SYN=1,seq=x)的请求报文段,然后进入 SYN_SENT 状态,等待服务端确认;
(2)、服务端接收到客户端 SYN 报文段后,需要发送 ACK 信息对这个 SYN 进行确认,同时还要发送自己的 SYN 信息(SYN=1,ACK=1,seq=y,ack=x+1)服务端把这些信息放在一个报文段中((SYN+ACK 报文段),一并发给客户端,服务端处于 SYN-RCVD 状态;
(3)、客户端接收到服务端的 SYN+ACK 报文段后会向服务端发送 ACK(ACK=1,seq=x+,ack=y+1)确认报文段,这次报文可以携带客户到服务器的数据,这个报文段发送后,客户端和服务端都进入 ESTABLISHED 状态,完成三次握手。
为什么要三次握手,两次不行吗
为了防止服务端开启一些无用的连接增加服务器开销
如果没有第三次握手告诉服务端接收到传输的数据的话,服务端是不知道客户端有没有接收到服务器端返回的信息的。服务端就认为这个连接是可用的,端口就一直开着,等到客户端因超时重新发送请求时,服务器就会重新开启一个端口连接。这样一来,就会有很多无效的连接端口白白的开着,导致资源的浪费。
防止已失效的连接请求报文段突然又传送到了服务器,因而产生错误
已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
所以我们需要“第三次握手”来确认这个过程:
通过第三次握手的数据告诉服务端,客户端有没有收到服务器“第二次握手”时传过去的数据,以及这个连接的序号是不是有效的。
若发送的这个数据是“收到且没有问题”的信息,接收后服务器就正常建立 TCP 连接,否则建立 TCP 连接失败,服务器关闭连接端口。由此减少服务器开销和接收到失效请求发生的错误。
TCP四次挥手(断开连接)
(1)、客户端发送标记为 FIN=1(finished 的缩写,表示接收完成,请求释放连接),同时生成一个 Seq=u 的序列号,之后进入 FIN-WAIT-1 半关闭阶段(此时客户端到服务端发送数据的通道已经关闭,但是仍然可以接收服务端发过来的数据);
(2)服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号 seq=v,此时,服务端就进入了 CLOSE-WAIT(关闭等待)状态。TCP 服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个 CLOSE-WAIT 状态持续的时间。
(3)客户端收到服务器的确认请求后,此时,客户端就进入 FIN-WAIT-2(终止等待 2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
(4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为 seq=w,此时,服务器就进入了 LAST-ACK(最后确认)状态,等待客户端的确认。
(5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是 seq=u+1,此时,客户端就进入了 TIME-WAIT(时间等待)状态。
(6)服务器只要收到了客户端发出的确认,立即进入 CLOSED 状态,就结束了这次的 TCP 连接。
为什么需要四次挥手
关闭连接时,客户端向服务器发送FIN时,仅仅表示客户端不再发送数据但是还能接收数据。
服务器收到客户端的FIN报文时,先回一个ACK应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送FIN报文给客户端表示同意现在关闭连接。
为什么客户端在TIME-WAIT阶段要等2MSL
确认服务端是否收到客户端发出的ACK确认报文,当客户端发出最后的 ACK 确认报文时,并不能确定服务器端能够收到该段报文。
所以客户端在发送完 ACK 确认报文之后,会设置一个时长为 2MSL 的计时器。
MSL 指的是 Maximum Segment Lifetime:一段 TCP 报文在传输过程中的最大生命周期。
性能优化
加载优化:
减少HTTP请求:
精灵图,文件的合并,
缓存资源:
减少向服务器发送的请求数,节省网络资源,
压缩代码:
多余的缩进,空格,换行符,
无阻塞:
样式放在头部并使用link方式引入,脚本放在尾部并使用异步方式加载,
首屏加载
按需加载:
按需加载会导致大量重绘,影响渲染性能、
预加载:
资源加载完成后再显示页面、
压缩图像
减少Cookie:
去除没有必要的cookie,
将cookie的大小减到最小,
设置合适的过期时间,较长的过期时间可以提高响应速度。
避免重定向:
当页面发生了重定向,就会延迟整个HTML文档的传输。
异步加载第三方资源
执行优化
CSS写在头部,JS写在尾部并异步。
避免img、iframe等的src为空:
空src会重新加载当前页面,影响速度和效率。
尽量避免重置图像大小:
多次重置图像大小会引发图像的多次重绘,影响性能。
图像尽量避免使用DataURL:
DataURL图像没有使用图像的压缩算法,文件会变大,并且要解码后再渲染,加载慢耗时长。
渲染优化
设置viewport:HTML的viewport可加速页面的渲染
减少DOM节点:DOM节点太多影响页面的渲染,尽量减少DOM节点
优化动画:
尽量使用CSS3动画
合理使用requestAnimationFrame动画代替setTimeout
适当使用Canvas动画:5个元素以内使用CSS动画,5个元素以上使用Canvas动画,iOS8+可使用WebGL动画
优化高频事件:
scroll、touchmove等事件可导致多次渲染
函数节流,
函数防抖,
使用requestAnimationFrame监听帧变化:使得在正确的时间进行渲染
增加响应变化的时间间隔:减少重绘次数
GPU加速:
使用某些HTML5标签和CSS3属性会触发GPU渲染,请合理使用(过渡使用会引发手机耗电量增加)
HTML标签:video、canvas、webgl
CSS属性:opacity、transform、transition
样式优化
避免在HTML中书写style,
避免CSS表达式:CSS表达式的执行需跳出CSS树的渲染
移除CSS空规则:CSS空规则增加了css文件的大小,影响CSS树的执行
正确使用display:display会影响页面的渲染
display:inline后不应该再使用float、margin、padding、width和height
display:inline-block后不应该再使用float
display:block后不应该再使用vertical-align
display:table-*后不应该再使用float和margin
不滥用float:float在渲染时计算量比较大,尽量减少使用
不滥用Web字体:Web字体需要下载、解析、重绘当前页面,尽量减少使用
不声明过多的font-size:过多的font-size影响CSS树的效率
值为0时不需要任何单位:为了浏览器的兼容性和性能,值为0时不要带单位
避免让选择符看起来像正则表达式:高级选择符执行耗时长且不易读懂,避免使用
脚本优化
减少重绘和回流
避免不必要的DOM操作
避免使用document.write
减少drawImage
尽量改变class而不是style,使用classList代替className
缓存DOM选择与计算:每次DOM选择都要计算和缓存
缓存.length的值:每次.length计算用一个变量保存值
尽量使用事件代理:避免批量绑定事件
尽量使用id选择器:id选择器选择元素是最快的
touch事件优化:使用tap(touchstart和touchend)代替click(注意touch响应过快,易引发误操作)
webpack性能优化
webpack是一个模块打包工具,可以使用webpack管理模块依赖,并编译输出我们需要的静态文件,它能够很好的管理,打包开发中所用到的静态文件,让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后生成了优化且合并后的静态资源。
有哪些⽅式可以减少 Webpack 的打包时间
如何减少 Webpack 打包体积
重绘 回流
重绘:
DOM树没有元素增加或删除,只是样式的改变,针对浏览器对某一元素进行单独的渲染,这个过程就叫做重绘
回流:
DOM树中的元素被增加或者删除,导致浏览器需要重新的去渲染整个DOM树,
回流比重绘更消耗性能,发生回流必定重绘,重绘不一定会导致回流。
会导致性能问题
浏览器窗口大小改变
元素尺寸,位置,内容发生改变
元素字体大小变化
删除或添加可见的dom元素
激活css伪类(例如::hover)
定位或者浮动
盒模型
如何减少重绘和回流
1.使⽤ transform 替代 top
<div class="test"></div>
<style>
.test {
position: absolute;
top: 10px;
width: 100px;
height: 100px;
background: red;
}
</style>
<script>
setTimeout(() => {
// 引起回流
document.querySelector('.test').style.top = '100px'
}, 1000)
</script>
2.使⽤ visibility 替换 display: none ,因为前者只会引起重绘,后者会引发回流(改变了布局)
3.不要把节点的属性值放在⼀个循环⾥当成循环⾥的变量
for(let i = 0; i < 1000; i++) {
// 获取 offsetTop 会导致回流,因为需要去获取正确的值
console.log(document.querySelector('.test').style.offsetTop)
}
4.不要使⽤ table 布局,可能很⼩的⼀个⼩改动会造成整个 table 的重新布局。
5.动画实现的速度的选择,动画速度越快,回流次数越多,也可以选择使⽤requestAnimationFrame
6.将频繁重绘或者回流的节点设置为图层,图层能够阻⽌该节点的渲染⾏为影响别的节点。⽐如对于 video 标签来说,浏览器会⾃动将该节点变为图层。
图片资源懒加载
懒加载也叫做 延迟加载、按需加载 。
对于图片过多的页面,为了加速页面加载速度,所以很多时候我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。这样对于页面加载性能上会有很大的提升,也提高了用户体验。
我们在项目中使用 Vue 的 vue-lazyload 插件
安装:
npm install vue-lazyload --save-dev
在入口文件main.js引入并使用:
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
// 或者添加自定义选项
Vue.use(VueLazyload, {
preLoad: 1.3,
error: 'dist/error.png',
loading: 'dist/loading.gif',
attempt: 1
})
在 vue 文件中将 img 标签的 src 属性直接改为 v-lazy ,从而将图片显示方式更改为懒加载显示
<img v-lazy="/static/img/1.png">
路由懒加载
Vue 是单页面应用,可能会有很多的路由引入 ,这样使用 webpcak 打包后的文件很大,当进入首页时,加载的资源过多,页面会出现白屏的情况,不利于用户体验。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应的组件,这样就更加高效了。这样会大大提高首屏显示的速度,但是可能其他的页面的速度就会降下来
传统路由配置:
路由懒加载写法:
预加载
预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。
一个官网怎么优化,有哪些性能指标,如何量化
对首屏加载速度影响最大的还是资源大小,请求数量,请求速度等。代码方面,前端一般很难写出严重影响速度的代码。减小资源大小,可以用各种压缩,懒加载,预加载,异步加载等方法。减少请求数量可以使用雪碧图,搭建node中台将多个请求合并成一个等。对于官网这种项目,最好使用服务端渲染,首屏快之外,也有利于SEO。
this指向
没有调用者则指向window。
有调用者指向上一级调用者。
箭头函数本身没有this 会指向外部函数 。(可以改变this指向,继承而来的this不能改变)
定时器this指向window
对于new的方式来说 this指向实例,不会被任何⽅式改变 this
function foo() {
console.log(this.a) //undefined
console.log(this) // foo {}
}
var a = 1
const c = new foo()
《你不知道的JS上篇中》,有关于判断this指向的解释,描述的非常好:
使用new来调用函数/发生构造函数时,会自动执行下面操作
改变this指向
1.call
第一个参数是,指向函数体内this的指向,传递的参数以逗号形式分开
可以实现继承
2.apply
第一个参数是,指向函数体内this的指向,传递的参数是数组形式
调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的this指向
3.bind
不会调用函数,可以改变函数内部this指向 多应用于定时器
扩展:
call比apply的性能要好,平常可以多用call,call传入参数的格式正是内部所需要的格式
补充:
箭头函数
箭头函数是普通函数的简写,可以更优雅的定义一个函数,和普通函数相比, 有以下几点差异:
箭头函数没有自己的this,this指向定义箭头函数时所处的外部执行环境的this
箭头函数继承而来的this指向永远不变
即使调用call/apply/bind也无法改变箭头函数的this
箭头函数本身没有名字(匿名函数)
箭头函数没有原型prototype
箭头函数没有arguments 在箭头函数内访问这个变量访问的是外部执行环境的arguments
箭头函数不能作为构造函数使用
数组去重
利用 ES6的Set 方法
利用两次循坏 ,然后splice去重
splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。
注释:该方法会改变原始数组。
利用数组的indexOf下标属性来查询。
补充:
语法:str.indexOf(searchValue [, fromIndex]) searchValue-要被查找的字符串值, fromIndex
开始查找的位置,可以是任意整数,默认值为0。
如果fromIndex的值小于0,或者大于str.length,那么查找分别从0和str.length开始(fromIndex的值
小于0,等同于为空情况;fromIndex的值大于或等于str.length,那么结果 会直接返回-1。)
举例:
‘hello world’.indexOf(‘o’, -5)返回4,因为它是从位置0处开始查找,然后o在位置4处被找到。另一
方面,‘hello world’.indexOf(‘o’, 11)(或fromIndex填入任何大于11的值) 将会返回-1,因为开始查
找的位置11处,已经是这个字符串的结尾了。
利用 includes 方法
利用 filter方法 ----(满足方法的在漏斗的上面 不满足的在漏斗的下面)
利用Map数据结构去重:
创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
sort()方法:
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。
预编译器(不完整)
首先: 为什么会出现预编译器?
由于css不支持嵌套 代码复用性差,会有大量重复性代码,为了弥补这些不足之处,CSS预编译器
应运而生。CSS预处理器,提供CSS缺失的样式层复用机制、减少冗余代码,提高样式代码的可维
护性,大大提高了开发效率。
但是,CSS预处理器也不是万金油,CSS的好处在于简便、随时随地被使用和调试。预编译CSS
步骤的加入,让我们开发工作流中多了一个环节,调试也变得麻烦。更大的问题在于,预编译很容
易造成后代选择器的滥用。
Less
嵌套写法:
使用变量: @变量名:值
混合:
导入:less文件中导入另一个less文件
Sass
变量:
语法: $变量名:样式值;
使用: $变量名;
嵌套:
选择器嵌套:
伪类元素嵌套
继承:
opacity: 0、visibility: hidden、display: none区别
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
.box {
width: 100px;
height: 100px;
background-color: aquamarine;
margin-top: 0px;
/* 可以点击 占据位置 --透明度为0*/
/* opacity: 0; */
/* 不能点击 占据位置 --- 仅仅在视觉上的看不见 */
/* visibility: hidden; */
/* 不能点击 不占据位置 */
display: none;
}
.box1,
.box2 {
width: 100px;
height: 100px;
margin-top: 0px;
}
.box1 {
background-color: rgb(71, 197, 46);
}
.box2 {
background-color: rgb(132, 91, 229);
}
</style>
</head>
<body>
<div class="box1"></div>
<div class="box" οnclick="box()">1</div>
<div class="box2"></div>
<script>
function box() {
console.log('我被点了');
}
</script>
</body>
</html>
map()
map是操作js数组的方法,也可以说是一个函数,作用是遍历整个数组,对里面的每个值做处理再返回一个新的值。 需要return接收
可以在函数里面return(return的内容将作为新值代替数组遍历到的旧值item)
比如:把值变为原来的两倍
箭头函数:
简便:
map 和 forEach 的区别
相同点:
都是循环遍历数组中的每一项
每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)
匿名函数中的this都是指向window
只能遍历数组
不同点:
1.map()会分配内存空间存储新数组并返回,forEach()不会返回数据。
2.forEach函数不接受将其他方法附加到它,map函数执行的结果还能附加其他方法
补充:map和set区别
set:
成员不能重复
只有键值,没有键名,类似数组
可以遍历,方法有add,delete,has等等
set不能通过get方法获取因为只有值
map:
本质上是键值对的集合,类似集合
可以遍历,方法有很多,可以跟各种数据格式转换
可以通过get方法获取值,
都能通过迭代器进行for…of遍历
for…of 和 for…in
for…of
for …of是ES6新增的遍历方式,用于遍历数组和对象的。
for…of是允许遍历一个含有Iterator接口的数据结构(对象、数组等)并且返回各项值。普通对象是无法遍历的。
类数组对象正常遍历:(转化数组的时候,必须指定length)
普通对象获取值:
或者:
普通对象:需要给对象添加一个Symbol.iterator属性,并指向迭代器
创建一个指针对象,指向当前数据结构的起始位置
第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
第二次调用针对象的next方法,指针就指向数据结构的第二个成员
不断调用指针对象的next方法,直到它指向数据结构的结束位置
每一次调用next方法,都会返回数据结构的当前成员的信息,返回的是一个包含value和done两个属性的对象。
value:当前成员的值;
done:是一个布尔值,表示遍历是否结束
for…in
(for in 循环特别适合遍历对象)
遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
for … in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。
特别情况下, for … in 循环会以看起来任意的顺序遍历键名
null 和 undefined 的区别
undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。当需要释放一个对象时,直接赋值为 null 即可。
undefined:字面意思就是,未定义的值。希望表示一个变量最原始的状态,而非人为操作的结果:
1.声明了一个变量,但没有赋值
2.访问对象上不存在的属性
3.函数定义了形参,但没有传递实参
4.使用void对表达式求值
null:字面意思是空置,希望表示一个对象被人为的重置为空对象,而非一个变量最原始的状态。
null有属于自己的类型NULL,而不属于Object类型,typeof 之所以会判定为 Object 类型,是因为
JavaScript 数据类型在底层都是以二进制的形式表示的,二进制的前三位为 0 会被 typeof 判断为
对象类型,而 null 的二进制位恰好都是 0 ,因此,null 被误判断为 Object 类型。
数组和伪数组(类数组)的区别
类数组:
本质:类数组是简单对象,它的原型关系与数组不同。类数组对象不能直接使用数组的方法,比如push,shift等
补充:
数组的reduce方法
会有返回值 需要return返回
计算数组中元素的和
了解
max min
delete使用
当你删除一个数组元素时,数组的 length 属性并不会变小,数组元素变成undefined
扩展运算符—克隆
link 和 @import 的区别
1.引入内容不同,
@import只能引入样式文件,link不仅能引入样式文件,还可以引入图片等资源文件
2.加载顺序不同
link引用css时,在页面载入时同时加载,@import需要页面完全载入才加载
3.兼容性不同
link是HTML标签无兼容问题,@import低版本的浏览器不支持
4.对JS的支持不同
link 支持使用 Javascript 控制 DOM 去改变样式;而 @import 不支持
为什么link用href获取资源 script和img用src
src用于替换当前元素,href用于在当前文档和引用资源之间确立关系
src:
指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在的位置,在请求src资源时会将其指向的资源下载并应用到当前文档。当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到该资源完全执行完毕,这也就是为什么将js脚本放在底部而不是头部
href:
指向资源所在的位置,建立和当前元素之间的链接。在文档中添加link标签,浏览器会识别该文档为css文件,就会并行下载资源并且不会暂停对其他资源的处理,这也就是为什么建议使用link方式来加载css,而不是使用@import方式字符串中的单词逆序输出(手写)
方法一:split(“”).reverse().join(“”)
方法二:for循环
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度
回文
形如 ABCBA 的字符串或12321的数字被称为回文。
给你一个字符串 s,找到 s 中最长的回文子串。
function rotate(s) {
let str = s[0]
// 奇数
for (let i = 0; i < s.length; i++) {
// 依次截取前i个字符
const ss = s.slice(0, i + 1)
for (let j = 0; j < ss.length; j++) {
// 小于字符串的长度 且 当前字符 和 下下个字符相等
if (i + j + 2 <= s.length - 1 && s[i - j] === s[i + j + 2]) {
// 截取 相等之前的字符串
sss = s.slice(i - j, i + j + 3)
if (sss.length > str.length) str = sss
}else{
break
}
}
}
// 偶数
for (let i = 0; i < s.length; i++) {
const ss = s.slice(0, i + 1)
for (let j = 0; j < ss.length; j++) {
if (i + j + 1 <= s.length - 1 && s[i - j] === s[i + j + 1]) {
sss = s.slice(i - j, i + j + 2)
if (sss.length > str.length) str = sss
}else{
break
}
}
}
return str
};
console.log(rotate("babad"));
cookie sessionStorage localStorage 区别
1.cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递,而sessionStorage和localStorage不会自动把数据发送给服务器,仅存在本地。
2.存储大小限制不同,cookie数据不能超过4k,适合存很小的数据。sessionStorage 和localStorage也有存储大小限制,但比cookie大的多,可以达到5M或更大。
3.数据有效期限不同,sessionStorage:仅在当前浏览器窗口关闭之前有效 。localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据。cookie只在设置的的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
4.作用域不同,sessionStorage在不同浏览器窗口中不共享,即使在同一个页面, localStorage和cookie在所有同源窗口中都是共享的。
由于以上他们的区别,所以应用场景也不同:
Cookie一般用于存储登录验证信息SessionID或者token,
LocalStorage常用于存储不易变动的数据,减轻服务器的压力,SessionStorage可以用来检测用户是否是刷新进入页面,如音乐播放器恢复播放进度条的功能。
网络安全
CSRF(跨站请求伪造)
XSS(跨站脚本攻击)
xss和csrf的区别
xss是获取信息,不需要提前知道用户的页面代码和数据包
csrf是代替用户完成指定操作,组要知道用户页面的代码和数据包,要完成一次csrf攻击,受害者必须一次完成两个步骤:
登录信任网站A,并本地生成cookie
不退出A的情况下,访问危险网站B
点击劫持
点击劫持是一种视觉欺骗的攻击手段。攻击者将需要攻击的网站通过iframe嵌套的方式嵌入到自己的网页中,并将iframe设置为透明,在页面中透出一个按钮诱导用户点击。
防御:
X-FRAME-OPTIONS(http响应头)
HTTP 响应头为了防御⽤ iframe 嵌套的点击劫持攻击。
BFC(块级格式上下文)
如何创建BFC
BFC作用
display:inline-block 什么时候不会显示间隙?
HTML代码中的回车换行被 转成一个空白符,在字体不为0的情况下,空白符占据一定宽度,所以inline-block的元素之间就出现了 空隙。
1.移除空格: (代码的可读性变差)
2.使⽤ font-size:0 子元素必须设置font-sise,否则文字不显示
3.设置父元素,display:table和word-spacing
闭包
闭包就是能够读取其他函数内部变量的函数:函数 A 内部有⼀个函数 B ,函数 B 可以访问到函数 A 中的变量,那么函数 B 就是闭包
创建闭包最简单的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域。
闭包的特性:
函数内部再嵌套函数
内部函数可以引用外层参数和变量
参数和变量不会被垃圾回收机制回收
闭包的应用场景 :
防抖,节流 库的封装 (保证数据的私有性)
《你不知道的js上篇中》是这样总结闭包的:
说说你对闭包的理解
使用闭包主要是为了设计私有的方法和变量。
优点:
避免全局变量的污染
可以读取函数内部的变量
可以让这些变量始终保持在内存中
封装对象的私有属性和私有方法
缺点:
消耗内存
容易造成内存泄露
使用闭包的注意点:
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页性能问题,会导致内存泄漏。
解决方法是,在退出函数之前,将不使用的局部变量全部删除。
面试题:
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i) // 6 6 6 6 6
}, i * 1000)
}
// 因为 setTimeout是异步函数 会先把循环全部执行完毕 这时i就是6
解决:
使用let解决 (推荐) let是块级作用域
for (let i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i) // 1 2 3 4 5
}, i * 1000)
}
使用闭包
for (var i = 1; i <= 5; i++) {
// 立即执行函数 i的变量固定在j上不会改变
// 执行timer闭包时 就可以可以访问外部变量j
(function (j) {
setTimeout(function timer() {
console.log(j) // 1 2 3 4 5
}, j * 1000)
})(i)
}
使⽤ setTimeout 的第三个参数,这个参数会被当成 timer 函数的参数传⼊
for (var i = 1; i <= 5; i++) {
setTimeout(function timer(j) {
console.log(j) // 1 2 3 4 5
}, i * 1000, i)
}
说说你对作用域链的理解
作用域链的变量只能向上访问,变量访问到window对象即被终止,作用域链向下访问变量是不被允许的。
作用域链就是变量和函数的可访问范围,即控制着变量与函数的可见性和生命周期。
js原型 原型链?有什么特点?
每个对象都会在内部初始化一个prototype属性,当我们访问一个对象时,如果对象内部不存在这个属性,就会去找该对象的prototype属性,这个prototype又有自己的prototype,于是这样一直找下去,就形成了原型链。
特点:
当我们需要一个属性时,js引擎会先看当前对象是否有这个属性,如果没有,就会去找它的prototype对象是否有这个属性,如此递推下去,一直检索到Object内建对象。
事件代理
又称事件委托,简单讲就是把原本要绑定在子元素上的事件绑定在了父元素身上,让父元素担当事件监听的事务。事件代理的原理就是DOM元素的事件冒泡。
好处:
提高性能
节省内存占用
减少事件注册
可以实现当前新增子对象时无需再对其绑定
事件模型
捕获阶段–使用事件捕获时,父级元素先触发,子级元素后触发
目标阶段
冒泡阶段–使用事件冒泡时,子级元素先触发,父级元素后触发
如何实现继承
原型继承
实例继承
拷贝继承
构造继承
说说new操作符具体⼲了什么?
新生成一个对象
让 this 指向这个新的对象。
执行构造函数里面的代码,给这个新对象添加属性和方法。
返回这个新对象(所以构造函数里面不需要return )
谈谈this对象的理解?
在ES5中,如果想要知道this指向谁,就要看当前的这个函数是在哪里调用的
在事件中调用,this就是当前触发事件的元素
在对象中调用,this就是当前对象
在全局调用,this就是window
在面向对象中,this就是当前用new关键字创建出来的对象
在ES6的箭头函数中,要看定义这个箭头函数的父级作用域是谁,this就是谁
如果用call、apply、bind调用函数,这三个函数的第一个参数就是this指向
AJAX原理
简单来说就是在用户和服务器之间加了一个中间层,通过XmlHttpRequest对象来向服务器发异步请求,从服务器获取数据,然后用js来操作DOM更新页面,使用户操作与服务器响应异步化。
ajax有哪些优缺点
优点:
通过异步方式,提升用户体验
优化了服务器和浏览器之间的传输,减少不必要的数据往返,减少了宽带的占用
可以实现动态不刷新(局部刷新)
ajax在客户端运⾏,承担了⼀部分本来由服务器承担的⼯作,减少了⼤⽤户量下的服
务器负载。
缺点:
不容易调试
对搜索引擎支持比较弱
安全问题,ajax暴露了与服务器交互的细节
跨域
同源策略是浏览器的一种约定,所谓同源是指“协议+端口+域名”三者相同,不同则是非同源
如何解决跨域问题
1.Jsonp跨域
2.cors中间件跨域
通过自定义请求头来让服务器和浏览器进行沟通
3.nginx反向代理,node中间件
nginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的
跨域场景:前后端分离式开发、调用第三方接口
为什么要有同源限制
比如说:一个黑客程序,利用iframe把真正的银行登录页面嵌入到它的页面上,这样你在使用真实用户名密码登录时,他的页面就可以通过js读取到你表单的内容,这样用户名密码就轻松到手了。
说一下 HTTP 和 HTTPS 协议的区别?
1、HTTPS协议需要CA证书,费用较高;而HTTP协议不需要
2、HTTP协议是超文本传输协议,信息是明文传输的,HTTPS则是具有安全性的SSL加密传输协议;
3、使用不同的连接方式,端口也不同,HTTP协议端口是80,HTTPS协议端口是443;
4、HTTP协议连接很简单,是无状态的;HTTPS协议是具有SSL和HTTP协议构建的可进行加密传输、身份认证的网络协议,比HTTP更加安全
哪些操作会造成内存泄漏
----在不需要使用的时候依然存在
1、意外的全局变量:由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收
2、被遗忘的计时器或回调函数:设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
3、脱离 DOM 的引用:获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
4、闭包:不合理的使用闭包,从而导致某些变量一直被留在内存当中。
正常情况下,js语言本身会释放内存不必要的变量,这种机制就是垃圾回收机制
标记清除法
引用计数法
XML和JSON的区别?
用来传输和存储数据
数据体积⽅⾯
JSON 相对 于XML 来讲,数据的体积⼩,传递的速度更快些。
数据交互⽅⾯
JSON 与 JavaScript 的交互更加⽅便,更容易解析处理,更好的数据交互
数据描述⽅⾯
JSON 对数据的描述性⽐ XML 较差
传输速度⽅⾯
JSON 的速度要远远快于 XML
说说你对promise的了解
Promise是JS中进行异步编程的解决方案
从语法上来说:Promise是一个构造函数
从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果
谈谈你对ES6的理解
1.let cost 块级作用域
2.箭头函数
3.解构赋值
4.promise
5.set map方法
双向绑定的原理
双向绑定就是:数据变化更新视图,视图变化更新数据
采用数据劫持和观察者方式,通过Object.defineProperty()来劫持各个属性的setter,getter。在数据变动时发布消息给订阅者,触发相应的监听回调。
怎样添加、移除、移动、复制、创建和查找节点
创建新节点
添加,移除,替换,插入
查找
冒泡排序
快速排序
async await 优缺点
async和await相比直接使用promise来说,优势在于处理then的调用链,能够更清除准确的写出代码。缺点在于滥用await可能会导致性能问题,因为await会阻塞代码,也许之后的异步代码并不依赖与前者,但仍然需要等待前者完成,导致代码失去了并发性。
浏览器缓存
先根据这个资源的一些http header判断它是否命中强缓存,如果命中,则直接从本地获取缓存资源,不会发请求到服务器。
当强缓存没有命中时,客户端会发送数据到服务器,服务器通过另一些request header验证这个资源是否命中协商缓存,如果命中,服务器将请求返回,但不会返回资源,而是告诉客户端直接从缓存中获取,客户端收到返回后就会从缓存中获取资源。
强缓存(本地缓存)
客户端第一次问服务器要某个资源时,服务器丢还给客户端所请求的这个资源同时,告诉客户端将这个资源保存在本地,并且在未来的某个时点之前如果还需要这个资源,直接从本地获取就行了,不用向服务器请求。
协商缓存
客户端第一次问服务器要某个资源时,服务器丢还给客户端所请求的这个资源同时,将该资源的一些信息(文件摘要、或者最后修改时间)也返回给客户端,告诉客户端将这个资源缓存在本地。当客户端下一次需要这个资源时,将请求以及相关信息(文件摘要、或者最后修改时间)一并发送给服务器,由服务器来判断客户端缓存的资源是否需要更新:如不需要更新,就直接告诉客户端获取本地缓存资源;如需要更新,则将最新的资源连同相应的信息一并返回给客户端。
为什么需要浏览器缓存?
所谓的浏览器缓存指的是浏览器将用户请求过的静态资源,存储到电脑本地磁盘中,当浏览器再次访问时,就可以直接从本地加载,不需要再去服务端请求了。
优点:
减少了服务器的负担,提高了网站的性能
加快了客户端网页的加载速度
减少了多余网络数据传输
为什么操作DOM慢
因为DOM是渲染引擎中的东西,JS是JS引擎中的东西。通过JS操作DOM的时候,这个操作涉及到了两个线程之间的通信,并且操作DOM可能还会带来重绘回流的情况,所以就导致了性能上的问题。
补充:
插入几万个DOM,如何实现页面不卡顿?
分批次部分渲染DOM。
虚拟滚动。
MVVM
Vue生命周期
什么是生命周期:
vue实列从创建到销毁的过程,就是生命周期。
一共分为八个阶段:创建前/后、载⼊前/后、更新前/后、销毁前/销毁后。
生命周期的作用:
生命周期中有很多事件钩子,让我们控制整个vue实列的过程时更容易形成好的逻辑。
vue的优点:
路由之间跳转
声明式
编程式
this.$router.push()
Vue实现双向绑定的原理
Object.defineProperty()
采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Vue组件间的参数传递
Vue 组件间通信只要指以下 3 类通信 :
父子组件通信、隔代组件通信、兄弟组件通信
更详细内容参考:
https://xie.infoq/article/274f8294dca8b3e31375f7b55
Vuex
复杂关系的组件数据传递
v-if和v-show区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,操作的实际上是dom元素的创建或销毁。
v-show 不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换,它操作的是display:none/block属性。
一般来说, v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
NextTick 原理分析
nextTick 可以让我们在下次 DOM 更新循环结束之后执⾏延迟回调,⽤于获得更新后的 DOM 。
进程与线程
进程
一个在内存中运行的应用程序。每个进程都有自己独立的一块内存空间,一个进程可以有多个线程。
线程
进程中的一个执行任务(控制单元),负责当前进程中程序的执行。一个进程至少有一个线程,一个进程可以运行多个线程,多个线程可共享数据。
区别:
进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
Object.keys(obj)
处理对象 返回键名
处理数组 返回索引值
Object.values()
返回键值
Object.entries()
返回键值对
HTML5十大新特性
computed 和 watch 的区别和运用的场景?
适用场景:
当我们需要进行数值计算,并且依赖于其它数据时,应该使用computed,因为可以利用computed的缓存特性,避免每次获取值时,都要重新计算。
当我们需要在数据变化时执行异步或开销较大的操作时,应该使用watch,使用watch选项允许我们执行异步操作,限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
组件中data为什么是一个函数,而不是一个对象
data( ){
return{ }
}
跟实列对象data可以是对象也可以是函数(跟实例是单例),不会产生数据污染。
组件实列对象data必须是函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新的data对象。
(组件复⽤时所有组件实例都会共享 data ,如果 data 是对象的话,就会造成⼀个组件修改 data 以后会影响到其他所有组件,所以需要将 data 写成函数,每次⽤到就调⽤⼀次函数获得新的数据。)
给定一组字符串判断是否有效
通过栈的特性来完成
两个数不使⽤四则运算得出和
利用按位异或
冒泡排序
从第⼀个元素开始,把当前元素和下⼀个索引元素进⾏⽐较。如果当前元素⼤,那么就交换位置,
插入排序
第⼀个元素默认是已排序元素,取出下⼀个元素和当前元素⽐较,如果当前元素⼤就交换位置。那么此时第⼀个元素就是当前的最⼩数,所以下次取出操作从第三个元素开始,向前对⽐,
快速排序
采用二分法,找到一个基准值,小的放左边,大的放右边,(左边找到比基准值大的 右边找到比基准值小的 交换位置)
let arr = [7, 6, 8, 1, 2, 0, 4, 3, 9, 5];
function quickSort(arr, left, right) {
let l = left;//左下标
let r = right;//右下标
let pivot = arr[Math.floor((l + r) / 2)];//中轴值
let tmp = 0;//临时变量,作为交换时使用
//while循环的目的是让比pivot值小的放到左边,比pivot值大的放到右边
while (l < r) {
//在pivot的左边一直找,直到找到大于等于pivot的值,才退出
while (arr[l] < pivot) {
l += 1;
}
//在pivot的右边一直找,直到找到小于等于pivot值,才退出
while (arr[r] > pivot) {
r -= 1;
}
//如果l >= r说明pivot 左右两边的值,已经按照左边全都是小于等于pivot的值,右边全是大于等于pivot值
if (l >= r) {
break;
}
//交换
tmp = arr[l];
arr[l] = arr[r];
arr[r] = tmp;
//如果交换完后,发现arr[l]==pivot值相等,r=r-1
if (arr[l] == pivot) {
r -= 1;
}
//如果交换完后,发现arr[r]==pivot值相等,l++
if (arr[r] == pivot) {
l += 1;
}
//如果l==r,必须l++,r--否则会出现栈溢出
if (l == r) {
l += 1;
r -= 1;
}
//向左递归
if (left < r) {
quickSort(arr, left, r);
}
//向右递归
if (right > l) {
quickSort(arr, l, right);
}
}
return arr;
}
console.log(quickSort(arr, 0, arr.length - 1));//[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
数据类型转换
在 JS 中类型转换只有三种情况,分别是:
转换为布尔值
// 转换布尔值
// 以下输出false
console.log(Boolean(undefined));
console.log(Boolean(null));
console.log(Boolean(NaN));
console.log(Boolean(''));
console.log(Boolean(0));
console.log(Boolean(-0));
// 以下输出true (除了上边的输出false以外 其他都输出true)
console.log(Boolean(' ')); // 空格
console.log(Boolean('0'));
console.log(Boolean({}));
console.log(Boolean([]));
转换为数字
var b = '2'
console.log(Number(b));
console.log(typeof Number(b)); //转换为数字
转换为字符串
var a = 2
console.log(String(a));
console.log(typeof String(a)); //转换为字符串
四则运算
// 对于加法来说
// 如果一方为字符串 就会把另一方转换为字符串
// 如果一方不是字符串或者数字 就会转换成数字或者字符串
console.log(1 + '1'); // '11' string
console.log(true + true); // 2 number
console.log(4 + [1, 2, 3]); // "41,2,3" string
// 注意 + 'b' 为NAN
console.log('a' + + 'b'); // aNaN
console.log(typeof +'1'); // number
// 对于除了加法来说 只要一方是数字 另一方就会转换为数字
console.log(typeof (4 * '3')); //number
console.log(4 * []); // 0
console.log(4 * [1, 2]); // NaN
console.log(typeof (4-'1')); //number
模块化
优点:
解决命名冲突
提供复用性
提高代码可维护性
实现模块化的方式:
立即执行函数
通过函数作用域解决命名冲突,污染全局作用域的问题
CommonJS
Commonjs是服务端模块的规范,node.js采用了这个规划,Commonjs规范加载模块是同步的,也就是说,加载完成之后,才能执行后边的操作,
导出:
导入:
ES Module
ES Module和CommonJS区别
CommonJS:
1.支持动态导入,是同步导入,因为用于服务端,文件都在本地,同步导入即使卡在主线程影响也不大。
2.在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变。
ES Module:
1.异步导入,因为用于浏览器,需要下载文件,如果也采用同步导入会对渲染有很大影响。
2.采用实时绑定的方式,导入导出的值都是指向同一个内存地址,导入的值会跟随导出值变化。
Vue 中 key 的作用和原理,谈谈你对它的理解
更多推荐
面试知识点总结
发布评论