面试后记(持续更新中,每天十个知识点,感谢关注...)

4,206 阅读1小时+

前言:

今天去面试了,实际上呢是我自己把话题给引导到了es5对象。回答的话都是回答的一些概念性的问题,不过对于我来说也不太难,毕竟都听过,如果实在不会就直接用自己的话回答的。为了端正自己的态度,我决定记录一下这次面试的一些问题!

具体问题具体分析:

html+css方面:

  • 高度塌陷:
    定义:是由于父元素高度不固定,其高度由子元素进行撑开,当子元素浮动时,脱离文档流,就会造成高度塌陷
    解决方案:
    ①给父元素一个固定的高度
    ②给子元素清除浮动(当回答到这儿,问题自然会延伸到如何清除浮动)
  • 如何清除浮动?

请记住前两种方式的中文部分,代码都会写,但你会发现很多单词并不会读,请记住这两种方式的英文单词如何去读,如果你会拼写出来也行。记住:在面试官的眼里,只要你说不出来就是不会!!!!

方式一:在浮动元素的父元素添加 overflow:hidden的css属性;(回答到这儿,问题可以延伸到bfc)

    .ovh{
        overflow:hidden;
    }

方式二: 在浮动元素的兄弟元素中添加clear:both的属性;

    .clear{
        clear:both;
    }

方法三:使用伪元素来清除浮动:

    .clearfix:after{
        content:"";//设置内容为空
        height:0;//高度为0
        line-height:0;//行高为0
        display:block;//将文本转为块级元素
        visibility:hidden;//将元素隐藏
        clear:both//清除浮动
    }
    .clearfix{  
        zoom:1;//为了兼容IE
    }

方法四:使用双伪元素清除浮动:

    .clearfix:before,.clearfix:after {
        content: "";
        display: block;
        clear: both;
    }
    .clearfix {
      zoom: 1;
    }
  • bfc是什么?说一个实际应用场景:
    定义:格式化上下文,是一个独立的渲染区域!
    满足以下任意一个条件则能形成bfc:
    1. float的值不为none(默认值)
    2. overflow的值不为visible(默认值)(回答到这儿问题可以延伸到如何解决上下margin重合的问题)
    3. position的值为absolute(绝对定位)或fixed(固定定位)(问题可以延伸到元素定位)
  • 上下margin重合的问题:(问题可以延伸到盒模型)
    解决办法:盒子的外面包一个div,通过改变此div的属性设置overflow:hidden,使两个盒子分属于两个不同的BFC,以此来阻止margin重叠
    <div class="aside"></div>
    <div class="text">
        <div class="main"></div>
    </div>
    <!--下面是css代码-->
     .aside {
                margin-bottom: 100px;  
                width: 100px;
                height: 150px;
                background: #f66;
            }
            .main {
                margin-top: 100px;
                height: 200px;
                background: #fcc;
            }
             .text{
                overflow: hidden;  //此时已经触发了BFC属性。
            }
  • 元素定位
    absolute绝对定位一般情况下参照浏览器的左上角,特殊情况下参照的是任意一个非默认(static)定位的父元素
    relative相对定位相对定位一般相对于正常位置进行对位,也就是参照父元素的原始点
    fixed固定定位相对于浏览器窗口进行定位
    应用场景:
    1.设置z-index属性时必须设置元素定位;
    2.一些悬浮窗口必须用到固定定位;
    3.垂直水平居中的方式之一(说到这里自然会将问题延伸至垂直水平居中)
  • 垂直水平居中:(方式比较多,我会列举大概四种易记的,请记住文字表达部分)
  1. relative+absolute+负margin——适用于已知宽高

父元素设置相对定位(relative),子元素设置绝对定位(absolute),top和left值设置为50%,设置margin-top和margin-left的值,值通过margin-top = -(height+padding-top+border-top+margin-top)/2得到(纵轴上的参数),margin-left = -(width+padding-left+border-top+margin-left)/2得到(横轴上的参数)

css部分:

    .content{
		width:400px;
		height:400px;
		position:relative;
		background-color:#ccc;
	}
	.center{
	    padding:100px;
		margin:100px;
		border:2px solid #333;
		position:absolute;
		top:50%;
		left:50%;
		margin-top:-100.5px;
		margin-left:-100.5px;
	}

html部分:

    <div class="content">
        <div class="center"></div>
    </div>
  1. relative+absolute+transform——适用于未知宽高

父元素设置relative,子元素设置absolute,并且将top值和left中的值设置为50%,子元素设置transform属性中translate为两个-50%

css部分(html部分同上)

  .content{
		width:400px;
		height:400px;
		position:relative;
		background-color:#ccc;
	}
	.center{
		padding:100px;
		border:1px solid #333;
		position:absolute;
		top:50%;
		left:50%;
		transform:translate(-50%,-50%);
	}  
  1. flex普通布局:(如果说到flex,有的面试官会让你阐述它具体还有哪些属性)——适用于未知宽高

在父元素中设置display: flex;justify-content: center;align-items: center;

css部分:(html部分同上)

    .content{
		width:400px;
		height:400px;
		display: flex;
		justify-content: center;
		align-items: center;
		background-color:#ccc;
	}
	.center{
		padding:100px;
		border:1px solid #333;
	}
  1. flex最简方式——适用于已知宽高

在父元素中设置display: flex;在子元素中设置margin:auto;

css部分:(html部分同上)

    .content{
		width:400px;
		height:400px;
		display: flex;
		background-color:#ccc;
	}
	.center{
		padding:100px;
		margin:auto;
		border:1px solid #333;
	}
  • flex具体的属性都有哪些?
   flex-direction:属性指定了弹性子元素在父容器中的位置。
   justify-content:主轴线(横向)上的元素排列
   align-items:设置或检索弹性盒子元素在侧轴(纵轴)方向上的对齐方式。
   flex-wrap:属性用于指定弹性盒子的子元素换行方式。
   align-content:用于修改 flex-wrap 属性的行为,设置各个行的对齐。
   align-self:属性用于设置弹性元素自身在侧轴(纵轴)方向上的对齐方式。
   flex:属性用于指定弹性子元素如何分配空间。
  • css中可以用来计算的属性:
    calc属性,该属性多用于自适应类型的布局(由此可以延伸到:三栏布局,左边固定右边自适应布局,以及瀑布流等等自适应类型的布局)
  • 如何用代码实现瀑布流布局?思路是什么? (1). 多列实现瀑布流布局:

大致思路是让图片成几列排布,然后规定中间的空隙大概多少像素,另外图片长和宽100%现实即可。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>瀑布流布局-多列</title>
		<style>
		.box{
			column-count:4;
			margin:10px;
			column-gap:10px; 
		}
		.item{
			margin-bottom: 10px; 
		}
		.item img{
			width: 100%;
			height: 100%;
		}
		</style>
	</head>
	<body>
		<div class="box">
			<div class="item"><img src="imgs/1.jpg" alt=""></div>
			<div class="item"><img src="imgs/2.jpg" alt=""></div>
			<div class="item"><img src="imgs/3.jpg" alt=""></div>
			<div class="item"><img src="imgs/4.jpg" alt=""></div>
			<div class="item"><img src="imgs/5.jpg" alt=""></div>
			<div class="item"><img src="imgs/6.jpg" alt=""></div>
			<div class="item"><img src="imgs/7.jpg" alt=""></div>
			<div class="item"><img src="imgs/8.jpg" alt=""></div>
		</div>
	</body>
</html>

效果图:

image
(2). flexbox实现瀑布流布局:

先规定横向布局,再规定换行,存图片的容器通过满屏100%宽度除以4得到把这个图片铺成4列需要的宽度,必须减去左右的margin值,以及必须初始化样式,如果不初始化样式会出现内容溢出(滚动条)。大容器为视图的宽高,图片宽高都为100%,撑满父容器即可。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>瀑布流布局-flexbox</title>
		<style>
		body{
			margin: 0;
			padding: 0;
		}
		.box{
			display: flex;
			flex-flow:column wrap;
			height: 100vh;
			width: 100vw;
		}
		.item{
			margin: 10px;
			width: calc(100%/4 - 20px);
		}
		.item img{
			width: 100%;
			height: 100%;
		}
		</style>
	</head>
	<body>
		<div class="box">
			<div class="item"><img src="imgs/1.jpg" alt=""></div>
			<div class="item"><img src="imgs/2.jpg" alt=""></div>
			<div class="item"><img src="imgs/3.jpg" alt=""></div>
			<div class="item"><img src="imgs/4.jpg" alt=""></div>
			<div class="item"><img src="imgs/5.jpg" alt=""></div>
			<div class="item"><img src="imgs/6.jpg" alt=""></div>
			<div class="item"><img src="imgs/7.jpg" alt=""></div>
			<div class="item"><img src="imgs/8.jpg" alt=""></div>
		</div>
	</body>
</html>

效果图:

image
(3). 浮动实现瀑布流布局:

这个方式不及前两种简单,这个方式如果要换成2列或者3列,html布局也必须跟着更改。实现其实很简单,一个大的div中有4个横向排列的小div,小div通过100%宽度除以4得到,里面的图片百分之百撑开即可!

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>瀑布流布局-float</title>
		<style>
		.box{
			width: 100%;
			height: 100%;
		}
		.item{
			width: calc(100%/4 - 20px);
			/*border: 1px solid #333;*/
			float: left;
			margin: 10px;
		}
		.item img{
			width: 100%;
			height: 100%;
			margin: 5px;
		}
		</style>
	</head>
	<body>
		<div class="box">
			<div class="item">
				<img src="imgs/1.jpg" alt="">
				<img src="imgs/2.jpg" alt="">
			</div>
			<div class="item">
				<img src="imgs/3.jpg" alt="">
				<img src="imgs/4.jpg" alt="">
			</div>
			<div class="item">
				<img src="imgs/5.jpg" alt="">
				<img src="imgs/6.jpg" alt="">
			</div>
			<div class="item">
				<img src="imgs/7.jpg" alt="">
				<img src="imgs/8.jpg" alt="">
			</div>
		</div>
	</body>
</html>

效果图:

image

  • 三栏布局:(对于这个问题我用计算属性来颠覆传统)
  1. float(浮动)+calc(计算属性)

实现思路是让左右两侧的固定部分进行浮动并给一个固定宽度,我用计算属性将中间不固定的部分宽度计算了出来,并且也让它浮动脱离文档流,如果不让它浮动,这三个div不会在同一行,高度设置为100%即可

css部分:

        *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
		}
		.left{
			width:100px;
			height:100%;
			float:left;
			background-color:red;
		}
		.center{
			float:left;
			width:calc(100% - 200px);
			height:100%;
			background-color:yellow;
		}
		.right{
			width:100px;
			height:100%;
			float:right;
			background-color:red;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="center">2</div>
		<div class="right">3</div>
	</div>

普通的float(浮动)布局

左右两侧的固定宽度先进行浮动定位,最后在将中间部分进行布局(实际上是将左右两侧固定部分先渲染出来后,在用自适应部分在中间进行填充.这个布局的特殊之处是自适应部分必须在末尾)

css部分:

        *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
		}
		.left{
			width:100px;
			height:100%;
			float:left;
			background-color:red;
		}
		.center{
		    height:100%;
			background-color:yellow;
		}
		.right{
			width:100px;
			height:100%;
			float:right;
			background-color:red;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="right">3</div>
		<div class="center">2</div>
	</div>
  1. 相对定位(absolute)+绝对定位(relative)+计算属性(calc)

利用绝对定位和相对定位让固定部分居于左右两侧,中间部分利用计算属性将其宽度计算出来

css部分:

       *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
			position:relative;
		}
		.content>div{
			position:absolute;
			height:100%;
		}
		.left{
			width:100px;
			background-color:red;
			left:0;
		}
		.center{
			width:calc(100% - 200px);
			background-color:yellow;
			left:100px;
		}
		.right{
			width:100px;
			background-color:red;
			right:0;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="center">2</div>
		<div class="right">3</div>
	</div>

普通的position(元素定位):

给父元素设置相对定位,给子元素设置绝对定位,固定宽度定位于左右两侧,自适应部分的left为左侧固定部分的宽度,rigth为右侧固定部分的宽度,这样即可得到中间部分的宽度

css部分

        *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
			position:relative;
		}
		.content>div{
			position:absolute;
			height:100%;
		}
		.left{
			width:100px;
			background-color:red;
			left:0;
		}
		.center{
			background-color:yellow;
			right:100px;
			left:100px;
		}
		.right{
			width:100px;
			background-color:red;
			right:0;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="center">2</div>
		<div class="right">3</div>
	</div>
  1. flexbox(弹性盒子)+calc:

在父元素中设置display:flex;justify-content:space-between;用计算属性计算出中间自适应的宽度

css部分:

    *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
			display:flex;
			justify-content:space-between;
		}
		.content>div{
			height:100%;
		}
		.left{
			width:100px;
			background-color:red;
		}
		.center{
			width:calc(100% - 200px);
			background-color:yellow;
		}
		.right{
			width:100px;
			background-color:red;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="center">2</div>
		<div class="right">3</div>
	</div>

普通的flex布局(flex+position):

这个方式结合前两个的阐述吧,说实话,我讨厌文字叙述

css部分:

        *{
			padding:0;
			margin:0;
		}/*为了快速清除默认样式,如果是项目上请少用通配符*/
		.content{
			width:100vw;
			height:100vh;
			display:flex;
			justify-content:space-between;
		}
		.content>div{
			height:100%;
		}
		.left{
			width:100px;
			background-color:red;
		}
		.center{
			background-color:yellow;
			position:absolute;
			right:100px;
			left:100px;
		}
		.right{
			width:100px;
			background-color:red;
		}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="center">2</div>
		<div class="right">3</div>
	</div>
  • 左边固定,右边自适应:
  1. float(浮动)+calc(计算属性):

左侧左浮动,右侧右浮动,用calc计算出自适应部分

css部分:

    *{
		padding:0;
		margin:0;
	}
	.content{
		width:100vw;
		height:100vh;
	}
	.left{
		width:100px;
		height:100%;
		float:left;
		background-color:red;
	}
	.right{
		width:calc(100% - 100px);
		height:100%;
		float:right;
		background-color:yellow;
	}

html部分:

    <div class="content">
		<div class="left">1</div>
		<div class="right">2</div>
	</div>
  1. 相对定位(relative)+绝对定位(absolute)

左边固定,右侧left为左边div的宽度,右侧的right设置为0

css部分:(html部分同上)

    *{
		padding:0;
		margin:0;
	}
	.content{
		width:100vw;
		height:100vh;
		position:relative;
	}
	.content>div{
		position:absolute;
		height:100%;
	}
	.left{
		width:100px;
		background-color:red;
	}
	.right{
		left:100px;
		right:0;
		background-color:yellow;
	}
  1. flex(弹性盒子)+ calc(计算属性)

父元素设置弹性盒子,设置子元素的横向排列方式,将自适应部分通过计算属性将宽度计算出来

css部分:(html部分同上)

    *{
		padding:0;
		margin:0;
	}
	.content{
		width:100vw;
		height:100vh;
		display:flex;
		justify-content:space-between;
	}
	.left{
		width:100px;
		height:100%;
		background-color:red;
	}
	.right{
		width:calc(100% - 100px);
		height:100%;
		background-color:yellow;
	}
  • 上下固定中间自适应?

只写一个,其他的自己悟!!!

  1. 绝对定位(absolute)+相对定位(relative)

自适应部分的宽度top值为最顶部div的高度,bottom的值为最底部div的高度,最底部的div bottom的值为0,让它固定到最底部 css部分:

    *{
		padding:0;
		margin:0;
	}
	.content{
		width:100vw;
		height:100vh;
		position:relative;
	}
	.content>div{
		width:100%;
		position:absolute;
	}
	.top{
		height:100px;
		background-color:red;
	}
	.center{
		top:100px;
		bottom:100px;
		background-color:yellow;
	}
	.bottom{
		height:100px;
		bottom:0;
		background-color:red;
	}

html部分:

    <div class="content">
		<div class="top">1</div>
		<div class="center">2</div>
		<div class="bottom">3</div>
	</div>
  • 用css实现滚动效果,如何实现?(用谷歌浏览器的手机模式调试,即可看到效果)

css部分:

    *{
		margin:0;
		padding:0;
	}
	.content{
		width:100vw;
		height:100vh;
		position:relative;
	}
	.content>div{
		position:absolute;
		width:100%;
	}
	.top{
		height:100px;
		background-color:#48a76d;
	}
	.center{
		top:100px;
		bottom:100px;
		overflow-y:scroll;
		overflow-x:hidden;
		-webkit-overflow-scrolling:touch;
		background-color:#ccc;
	}
	.bottom{
		height:100px;
		bottom:0;
		background-color:#48a76d;
	}
	.scroll{
		height:10000px;
		background-color:#fff;
	}
	.txtTop{
		color:red;
	}

html部分:

    <div class="content">
		<div class="top"></div>
		<div class="center">
			<div class="scroll">
				<span class="txtTop">顶部</span>
			</div>
		</div>
		<div class="bottom"></div>
	</div>
  • 布局是所有css问题中出现概率最高的问题,所以我会花一定的时间重点阐述!!!
  • 如何在页面上实现一个圆形的可点击区域?
    实现方案:
    1.svg
    2.canvas
    3.border-radius

具体实现示例: css部分:

    .content{
		position:absolute;
		top:50%;
		left:50%;
		transform:translate(-50%,-50%);
		width:100px;
		height:100px;
		border-radius:50%;
		background-color:red;
	}

html部分:

    <div class="content">
	</div>
  • 一行或多行文本超出隐藏? 一行文本: css部分:
    *{
		margin:0;
		padding:0;
	}
	.content{
		width:100px;
		height:200px;
		position:absolute;
		top:50%;
		left:50%;
		transform:translate(-50%,-50%);
		background-color:#ccc;
	}
	.txt{
		display:block;
		text-overflow: ellipsis;/*显示省略符号来代表被修剪的文本*/
		overflow: hidden;/*溢出隐藏*/
	}

html部分:

    <div class="content">
		<p class="txt">sikhafodhasodfhjaiofhiadhfishdihjasidfhiasdhjfihafihadsifhasidfhiasdhfiasdhjfiashdfiashjdiofjksf</p>
	</div>

多行文本: css部分:

    *{
		margin:0;
		padding:0;
	}
	.content{
		width:100px;
		height:200px;
		position:absolute;
		top:50%;
		left:50%;
		transform:translate(-50%,-50%);
		background-color:#ccc;
		word-wrap:break-word;/*文本自动换行*/
	}
	.txt{
		display:-webkit-box;/*将对象作为弹性伸缩盒子*/
		overflow:hidden;/*文本溢出隐藏*/
		text-overflow:ellipsis;/*溢出省略号显示*/
		-webkit-box-orient:vertical;/*设置伸缩盒子的子元素排列方式-从上到下垂直排列*/
		-webkit-line-clamp:2;/*这个属性不是css的规范属性,需要组合上面两个属性,数组代表显示的行数,如2,3,4....*/
	}

html部分:

    <div class="content">
		<p class="txt">sikhafodhasodfhjaiofhiadhfishdihjasidfhiasdhjfihafihadsifhasidfhiasdhfiasdhjfiashdfiashjdiofjksf</p>
	</div>
  • 用css写一个三角形: css部分:
    *{
		margin:0;
		padding:0;
	}
	.triangle{
		/*width:100px;
		height:100px;*/
		position:absolute;
		top:50%;
		left:50%;
		transform:translate(-50%,-50%);
		border-top:100px solid transparent;/*transparent为透明色*/
		border-bottom:100px solid #48a76d;
		border-left:100px solid transparent;
		border-right:100px solid transparent;
	}

html部分:

    <div class="triangle">
	</div>
  • 如何实现一条0.5px的细线?

css部分:

    .box{
		position:relative;
	}
	.box::after{
		content:'';
		position:absolute;
		width:200%;
		bottom:0;
		border-bottom:1px solid red;
		transform-origin:0 0;
		transform:scale(.5,.5);
	}

html部分:

    <div class="box"></div>
  • 实现一个布局,五个div左右排列,要求长和宽能等比例放大和缩小
  1. 浮动实现: css部分:
    *{
		margin:0;
		padding:0;
	}
	body{
		background-color:#ccc;
	}
	.item{
		margin:10px;
	}
	.item:nth-child(n){
		/*odd*/
		width:calc((100% - 40px) / 2);
		height:0;
		padding-bottom:calc((100% - 40px) / 2 * 1000/952);
		float:left;
		background-color:#fff;
	}
	.item:nth-child(2n){
		/*even*/		
		width:calc((100% - 40px) / 2);
		height:0;
		padding-bottom:calc((100% - 40px) / 2 * 1000/952);
		float:right;
		background-color:#fff;
	}

html部分:

    <div class="content">
		<div class="item">
			<div class="txt">这是图片文字</div>
		</div>
		<div class="item">
			<div class="txt">这是图片文字</div>
		</div>
		<div class="item">
			<div class="txt">这是图片文字</div>
		</div>
		<div class="item">
			<div class="txt">这是图片文字</div>
		</div>
		<div class="item">
			<div class="txt">这是图片文字</div>
		</div>
	</div>
  1. flex布局: css部分:(html同上)
    *{
		margin:0;
		padding:0;
	}
	body{
		background-color:#ccc;
	}
	.content{
		display: flex;
		flex-flow: row wrap;

	}
	.item{
		margin: 10px;
		width:calc((100% - 40px) / 2);
		height:0;
		padding-bottom:calc((100% - 40px) / 2 * 1000/952);
		background-color:#fff;
	}

注:多列的话,如果div的个数除以列数除不尽就会产生布局错乱,所以这个例子多列不可行;定位在设置子元素的左右位置时也会产生问题,所以定位也不可行 最终效果:

  • 作者已写吐!!!!!!让我缓缓...
  • 盒模型:
    content(内容)+padding(内边距)+border(边框)+margin(外边距)
  • IE盒模型和标准盒模型的区别:
    IE盒模型:宽度(width)= content(内容)+padding(内边距)+border(边框);
    标准盒模型:宽度(width) = content(内容);
  • 问题延伸:IE盒模型和标准盒模型如何相互转化:
    box-sizing:content-box(标准盒模型)
    box-sizing:border-box(IE盒模型)
  • css优先级:
    伪类;通配符(0)<元素(1)<class(10)<id(100)<style(1000)
    注:
    1.优先级相同,样式会进行覆盖,后定义的样式生效;
    2.通过继承得到的优先级样式最低(问题扩展:哪些样式可以通过继承父元素的样式得到?)
    3.样式的优先级并非是简单的相加
  • 哪些样式可以通过继承父元素的样式得到?(请注意继承这个词,css中有继承,js有继承,vue照样有!!!)
    内联元素可继承:line-height、color、font、 font-family、font-size、font-style、font-weight、text- decoration、text-transform、direction。
    块级元素可继承:text-align。
    简记为:文本类型的属性字体字号字体颜色字间距行间距基本都能继承
  • 问题延伸:style(内联样式)与!important(用户样式)谁的优先级更高?
    !important(用户样式)
  • 优雅降级和渐进增强:
    优雅降级:先满足最高版本浏览器的功能,再逐渐对低版本的浏览器减少功能的供给
    渐进增强:先满足最低浏览器的功能,再逐渐对高版本浏览器进行功能扩充
  • 回流重绘:
    回流:reflow(回流)是指浏览器为了重新渲染部分或者全部的文档,重新计算文档中的元素的位置和几何构造的过程。
    注:回流必将引起重绘,而重绘不一定会引起回流。回流一般是所有的全部重绘,重绘有可能只是部分重绘。
    引起回流的操作:(还有很多,记几个就行了)
    ① 改变窗口大小
    ② font-size大小改变
    ③ 增加或者移除样式表
  • 移动端如何适配?
    1. px=>rem;
    2. px=>vh
    3. 百分比布局
    4. 媒体查询
    5. flexbox布局
  • 从浏览器地址栏输入url到显示页面的步骤?
    1. 浏览器根据请求的URL交给DNS域名解析,找到真实IP
    2. 服务器交给后台处理完成后返回数据,浏览器接收文件
    3. 浏览器对加载到的资源进行语法解析,建立相应的内部数据结构
    4. 载入解析到的资源文件,渲染页面,完成.
  • 前端有做过SEO吗:
    1. 合理的title、description、keywords
    2. 语义化的HTML代码,符合W3C规范
    3. 重要内容HTML代码放在最前
    4. 重要内容不要用js输出
    5. 少用iframe
    6. 非装饰性图片必须加alt
    7. 提高网站速度
  • TCP的三次握手与四次挥手解释一下,并阐述一些常用的http状态码?
    //三次握手
    1. 第一次握手:指明客户端打算连接的服务器的端口
    2. 第二次握手:服务端发回确认包,设置确认序号
    3. 第三次握手:客户端再次发送确认包
    //四次挥手:
    1. 第一次挥手:假设客户端想要关闭连接,客户端发送一个FIN标志位置为1的包,表示自己已经没有数据可以发送了,但是仍然可以接受数据。
    2. 第二次挥手:服务器端确认客户端的FIN包,发送一个确认包,表明自己接受到了客户端关闭连接的请求,但还没有准备好关闭连接。
    3. 第三次挥手:服务器端准备好关闭连接时,向客户端发送结束连接请求,FIN 置为1。
    4. 第四次挥手:客户端接收到来自服务器端的关闭请求,发送一个确认包,并进入TIME_WAIT状态,等待可能出现的要求重传的 ACK 包。
    //常见http状态码:
    1. 200——服务器成功返回网页
    2. 304——客户端已经执行了GET,但文件未变化
    3. 400——错误请求,如语法错误
    4. 403——请求不允许
    5. 404——请求的网页不存在
    6. 500——服务器产生内部错误
    7. 502——服务器暂时不可用,有时是为了防止发生系统过载
    8. 503——服务器超时过载或暂停维修
    9. 504——关口过载,服务器使用另一个关口或服务来响应用户,等待时间设定值较长
  • 为什么要初始化css?
    为了清除各个浏览器的默认样式,实现样式上更好的统一
  • px和rem以及em有什么区别?
    px:相对长度单位,像素px是相对于显示器屏幕分辨率而言的;
    em:相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。
    em的使用:任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。那么12px=0.75em,10px=0.625em。为了简化font-size的换算,需要在css中的body选择器中声明Font-size=62.5%,这就使em值变为 16px*62.5%=10px, 这样12px=1.2em, 10px=1em, 也就是说只需要将你的原来的px数值除以10,然后换上em作为单位就行了。
    rem:为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。
    rem的使用:它的单位转换和em基本相同,唯一的不同之处是需要在html标签中设置Font-size=62.5%,设置之后12px=1.2rem,也就是10px=1rem
  • 缓存(cookies+localStorage+sessionStorage)的相同点与不同点:(问题延伸到如何使用,以及cookie隔离)
    相同点:都存储在客户端
    不同点:
    1.存储大小
    cookies大小不超过4k;
    localStorage 和 sessionStorage能达到5M或更大
    2.存储时间:
    cookies过期时间之前有效
    sessionStorage关闭浏览器窗口后自动删除
    localStorage浏览器关闭后数据不丢失,除非主动删除
    3.数据与服务器之间的交互方式
    cookies数据会自动传递到服务器,服务器端也可以写cookies到客户端
    localStorage和sessionStorage不会把数据发给服务器,仅仅把数据保存在本地 
  • cookies的用法:示例:(这也不知道是什么时候写的,将就着看吧,也可以自行修改)
    //设置cookie
	setCookie:function(cname,cvalue,exdays){
		var d = new Date();
		d.setTime(d.getTime()+(exdays*24*60*60*1000));
		var expires = "expires="+d.toGMTString();
		document.cookie = cname + "=" + cvalue + "; " + expires;
	},
	//读取cookie
	getCookie:function(cname){
		var name = cname + "=";
		var ca = document.cookie.split(';');
		for(var i=0; i<ca.length; i++){
			var c = ca[i].trim();
			if (c.indexOf(name)==0) return c.substring(name.length,c.length);
		}
		return "";
	},
	//删除cookie
	delCookie:function(cname){
		this.setCookie(cname,"",-1);
	}
  • localStorage的用法:
   写入: localStorage.setItem(key:string, JSON.stringify(val:object[]));//key为字符串类型,val为存入的数据,数据必须转成json形式
   读取:JSON.parse(localStorage.getItem(key:string))//key为字符串类型
   删除:localStorage.removeItem(key:string)//key为字符串类型
   清空localStorage缓存:localStorage.clear();
  • sessionStorage的用法
   写入: sessionStorage.setItem(key:string, JSON.stringify(val:object[]));//key为字符串类型,val为存入的数据,数据必须转成json形式
   读取:JSON.parse(sessionStorage.getItem(key:string))//key为字符串类型
   删除:sessionStorage.removeItem(key:string)//key为字符串类型
   清空sessionStorage缓存:sessionStorage.clear(); 
  • cookie隔离:
    为什么要隔离:
    如果所有静态资源都放在主域名下,cookie会连同静态资源一并发送到服务器,这样的话十分浪费流量,不如将cookie进行隔离
    怎么隔离:
    cookie不能跨域发送,意思是放在非主域名下即可!!!(问题延伸到跨域)
  • link和@import的区别?
    1. link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
    2. 页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载
    3. link一般用于html文件引入css,@import一般用于组件中引入css
  • h5如何自适应设备宽度,并禁止页面缩放?
    自适应设备宽度:
        1. 百分比布局
        2. 媒体查询
        3. 用rem或者em作为单位
    禁止页面缩放:
        <meta name="viewport" content="width=device-width, initial-scale=1.0,maximum-scale=1.0, user-scalable=no"/>

javascript

关于对象的一些知识点:

  • 声明方式:(只概括几个常用的即可)
    字面量方式声明、构造函数方式声明、工厂模式声明、原型模式声明、混合模式
  • 继承的方式:
    原型链方式继承、组合方式继承、call()/apply()方法继承、对象冒充、原型式继承、es6关键字
  • 原型:
    对象中固有的__proto__属性,该属性指向对象的prototype原型属性。
  • 原型链:
    当访问某个对象的属性时,如果该对象没有此属性,则会到他的原型中去查找,它的原型属性中又有自己的原型属性,一直这样查找下去,这就构成了原型链
  • 闭包:(对垃圾回收机制以及内存管理做了扩展)
    定义:函数中可以访问上层函数中局部变量的函数叫做闭包
    代码示例:
    ```
    function fn(){
    	var num = 1;
    	return function(){
    		return num++;
    	}
    }
    ```
    优缺点:1. 会一直保存在内存中;2. 私有变量的存在;3. 避免全局环境的‘污染’!
    缺点:1. 会改变父函数中的值;2.滥用会导致内存泄漏
    为什么会导致内存泄漏?
    如果变量不再被引用就会被GC垃圾回收机制所回收,否则会一直保存在内存中!
    如何管理内存?
    1. 分代式回收;2. 增量GC;
    回收策略有哪些?
    1. 标记清除;2. 引用计数
    如何解决闭包内存泄漏的问题?
    在退出函数之前,将不再使用的变量,一一删除!
    应用场景:
    1. 计时器;2.回调函数
  • 深浅拷贝:(问到这里肯定会问相关的拷贝方法)
    深拷贝:则递归复制了所有层级,将数据中所有的数据都拷贝下来,而不仅仅是引用。拷贝下来的数据的修改,并不会影响原数据。
    浅拷贝:只复制一层对象属性,只是将数据中存放的引用拷贝下来,但依旧指向同一个存放地址。
  • 浅拷贝的方法:
    {...obj}和Object.assign{{},需要拷贝的对象名}
  • 深拷贝的方法:
    JSON.parse(JSON.stringify(obj))
  • this指向:(问到这里会问如何改变this指向)
    this指向其执行上下文环境(指向调用时的对象),call/apply/bind可以改变this指向
  • 改变this指向:(问到这里会问这三种方式有什么区别)
  1. 通过call方法来改变其this指向:

如果有参数call的参数

    function fn(){
        console.log(this);
    };
    var Obj = {
        name:'李四',
        getThis:function(){
            console.log(this);
        }
    }
    fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
    fn.call(Obj);//{name: "李四", getThis: ƒ}
  1. 通过apply方法来改变其this指向:
    function fn(){
        console.log(this);
    };
    var Obj = {
        name:'李四',
        getThis:function(){
            console.log(this);
        }
    }
    fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
    fn.apply(Obj);//{name: "李四", getThis: ƒ}
  1. 通过bind方法来改变其this指向:
    function fn(){
        console.log(this);
    };
    var Obj = {
        name:'李四',
        getThis:function(){
            console.log(this);
        }
    }
    fn();//Window {parent: Window, opener: null, top: Window, length: 0, frames: Window, …}
    fn.bind(Obj)();//{name: "李四", getThis: ƒ}
  • call、apply、bind的区别?
    call参数类似于函数参数,apply参数类似于数组,bind是创建一个新的函数,我们必须去手动调用它b.bind(a)()
  • 请说出对象的继承方式有哪些,并手写出你说的这些方式?(继承和声明方式混写)
    //方式:
    原型链方式继承、组合方式继承、call()/apply()方法继承、对象冒充、原型式继承、es6关键字
    //原型链方式继承+(工厂模式声明方式):
    var Obj = function(name){
        var O = new Object();
    	O.name = name;
        return O;
    };
    var newObj = function(){};
    newObj.prototype = new Obj('张三');//实现继承
    
    var O = new newObj;
    console.log(O.name);//'张三'
    //call方式继承:(apply()同理)+(构造函数声明)
    function FnA(){
    	this.name = "张三";
    }
    function FnB(){
    	FnA.call(this);
    }
    var newObj = new FnB;
    console.log(newObj.name);//张三
    //组合方式继承+(混合模式方式声明)
    function FnA(){
        this.name = '张三';
    }
    FnA.prototype.getName = function(){
        return this.name;
    }
    function FnB(){
        FnA.call(this);//继承name,无法继承FnA中原型链上的属性
    }
    FnB.prototype = new FnA;//继承getName方法
    var newFnB = new FnB;
    console.log(newFnB.getName());
    //对象冒充+(构造函数方式声明)
    function FnA(){
    	this.name = "张三";
    }
    function FnB(O){
    	this.Obj = O;
    	this.Obj();
    	delete this.Obj;
    }
    var newObj = new FnB(FnA);
    console.log(newObj.name);//张三
    //原型式+(字面量方式声明):
   var Obj = {
	name : "张三"
    }
    var newObj = function(O){
    	var F = function(){};
    	F.prototype = new O;
    	return new F();
    };
    var O = new newObj(Obj);
    console.log(O.name);//张三
    //class
    class A{}
    class B extends A{}//继承

注:面试只需记住这些概念,如果需要理解,请查阅我的另一篇博客:juejin.cn/post/684490… ,此篇博客对对象的描述较为详细

其他的一些问题:

  • 跨域原理及其解决办法:
    产生原因:页面访问地址与请求地址之间,受同源策略的影响,如果协议、域名、端口号有一个不同就会产生跨域。
    解决办法:(问到这里会问工作中是如何解决跨域的)
    1. jsonp
    2. proxy(反向代理)
    3. window.name
    4. CORS(跨域资源共享)
    5. nginx反向代理
  • 跨域实例——vue中解决跨域:

在vue-cli3.0中新建一个vue.config.js文件,在里面配置域名,协议,端口号,以及需要跨域的域名url

    module.exports = {
    	//反向代理
    	devServer: {
    		open: true, //浏览器自动打开页面
    		host:'localhost',//域名
    		port:8080,//端口号
    		https:false,//协议
    		hotOnly:false,
    		proxy: {
    			//配置跨域
    			'/api': {
    				target: '公共域名', //访问数据的计算机域名
    				ws: true,
    				changOrigin: true, //开启代理
    				pathRewrite: {
    					'^/api': ''
    				}
    			}
    		}
    	}
    }
    //注:并不能从根源上解决跨域的问题
  • 防抖与节流:(问到这里会问如何实现防抖或节流)
    防抖(debounce):是指一个事件在一定的时间内只执行一次,如果等待时间内再次执行,则等待时间会重新计算
    应用场景: onchange事件一定要做防抖
   节流(throttle):是指一个事件在一个时间段内执行了多次,将其执行频率降低。
   应用场景:鼠标移动
  • 用代码实现一次简单的防抖?
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>对任意函数进行防抖</title>
</head>
<body>
	<script>
	window.onload = function () {
		var btn = document.createElement('button');//创建HTML标签
		var btntxt = document.createTextNode('点击');//创建文本节点
		btn.appendChild(btntxt);//文本节点追加到HTML标签中
		btn.id = "btn";//给HTML标签添加id
		document.body.appendChild(btn);//将HTML标签追加到文档中
		
		var btnId = document.getElementById("btn");
		btnId.onclick = antiShake;
		function increase(min,max){
			let i = max-min+1;
			return Math.floor(Math.random()*i)+min;
		}
		//防抖: n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间		var state = true;
		function antiShake(){
			if(state){
				console.log(increase(1,100));
				state = false;
				setTimeout(()=>{
					state = true;
				},6000);
			}else{
				console.log("操作过于频繁,请6秒后重试")
			}
		}
	}
	</script>
</body>
</html>
  • 如何实现间隔60秒发送一次短信请求验证码?
    1. 请求按钮初始点击状态为true
    2. 给一个60秒的定时器,点击之后状态设置为false,并请求一次数据;
    3. 60秒之后点击状态又设置为true,清除定时器
    注:有一种特殊情况是用户刷新浏览器,定时器会归零,状态也会回归初始状态
    本来我想通过前端禁用用户刷新的,但是经测试浏览器刷新按钮禁用不了,只能禁用键盘刷新。
    所以必须通过后端判断用户是否刷新浏览器,若刷新接口返回提示信息给用户提示不能请求短信验证码数据。
  • 基本数据类型和引用数据类型都有哪些:
    基本数据类型:字符串、数字、null、Undefined、布尔值、Symbol
    引用数据类型:对象、数组、函数
  • 如何判断函数中是否包含某个属性?
    //hasOwnProperty() 方法会返回一个布尔值,判断对象是否有某个key值。
    var Obj = {
        name:'张三'
    }
    console.log(Obj.hasOwnProperty('name'));//true
  • 自执行函数为什么会加标点符号?
    防止浏览器进行预解析,将其放入堆内存中
  • new一个对象时发生了什么?(问题可以延伸到箭头函数为什么不能作为构造函数)
    1.实例化一个新对象;
    2.将函数中this上的值赋值给新对象;
    3.依次执行函数中的代码;
    4.返回一个新对象
  • 同步与异步:(问到这里会问到es6的相关知识)
    同步任务来说,会被推到执行栈按顺序去执行这些任务。
    异步任务来说,当其可以被执行时,会被放到一个 任务队列(task queue) 里等待JS引擎去执行。
    执行顺序:
    同步→异步里的微任务(Promise的then、Mutation、Observer)→异步里的宏任务(setTimeout、setInterval)
  • dom节点操作?

虽然现在的框架都是操作的虚拟dom,并不需要去操作真实dom,但是dom文档对象模型是js的重要组成部分之一,所以问dom也无可厚非,我会将其详细记录在此,我平时写一些小的demo也只要涉及到js还是会用dom节点的一些操作!

    获取节点:
        document:
            getElementById:通过元素ID获取节点
            getElementsByName:通过元素的name属性获取节点
            getElementsByTagName:通过元素标签获取节点
            getElementsByClassName:通过元素class获取节点
        节点指针:
            firstChild:获取元素的首个子节点
            lastChild:获取元素的最后一个子节点
            childNodes:获取元素的节点列表
            previousSibling:获取已知点的前一个节点
            nextSibling:获取已知接点的后一个节点
            parentNode:获取已知节点的父节点
    节点操作:
        创建节点:
            createElement:创建元素节点
            createAttribute:创建属性节点
            createTextNode:创建文本节点
        插入节点:
            appendChild:向节点的子节点列表的末尾添加新的子节点
            inserBefore:在已知的子节点前插入一个新的子节点
            replaceChild:将某个子节点替换为另一个
        复制节点:
            cloneNode:创建指定节点的副本
        删除节点:
            removeChild:删除指定的节点
  • 如何用js创建一个id为content的div dom节点,并给该标签添加一个data-id的自定义属性?
        //实际是用js操作dom写一个<div id="content" data-id="1">给该标签添加一个data-*的自定义属性</div>的html代码
	window.onload=function(){
		var btn = document.createElement('div');//创建HTML标签
		var btntxt = document.createTextNode('给该标签添加一个data-*的自定义属性');//创建文本节点
		btn.appendChild(btntxt);//文本节点追加到HTML标签中
		btn.id = "content";//给HTML标签添加id
		btn.setAttribute("data-id","1");//添加data-id的自定属性
		document.body.appendChild(btn);//将HTML标签追加到文档中
	}
  • ==和===区别?
    ==判断值是否相等
    ===判断值和类型是否相等
  • js绑定事件的三种方式:
    1.绑定到html元素上:<h1 onclick="this.innerHTML='Ooops!'">点击文本!</h1>
    2.dom0级事件:
    <h1>点击文本!</h1>
	<script>
	window.onload=function(){
		var h = document.getElementsByTagName("h1")[0];//返回的是一个数组
		function setTxt(){
			this.innerHTML='Ooops!';
		}
		h.onclick = setTxt;
	}
	</script>
	3.dom2级事件(在dom2级事件中新增了事件捕获和事件冒泡的概念):
    <h1>点击文本!</h1>
	<script>
	window.onload=function(){
		var h = document.getElementsByTagName("h1")[0];//返回的是一个数组
		function setTxt(){
			this.innerHTML='Ooops!';
		}
		h.addEventListener("click",setTxt,false);//第三个参数规定事件是否在捕获或者冒泡阶段执行
	}
	</script>
  • 事件冒泡和事件捕获区别以及如何阻止事件冒泡?
    事件捕获:事件从根元素向其内部元素依次触发
    事件冒泡:事件从某个元素向外依次触发,直到触发到根元素
    //阻止冒泡行为 
    function stopBubble(e) { 
    //如果提供了事件对象,则这是一个非IE浏览器 
    if ( e && e.stopPropagation ) 
        //因此它支持W3C的stopPropagation()方法 
        e.stopPropagation(); 
    else 
        //否则,我们需要使用IE的方式来取消事件冒泡 
        window.event.cancelBubble = true; 
    }
  • for...in和for...of的区别?
    for...in一般用于遍历对象(实际上数组,字符串也可以),for...of用于遍历一切可迭代的值
    for...in遍历对象会连原型上的属性和方法一起遍历,而for...of不会
  • 手写ajax:(我是请求的本地文件,是将js和请求的json数据文件都放在php的phpStudy\PHPTutorial\WWW文件目录下,并没有用后端代码开启任何服务,只需要启动phpStudy)
    function getData(requestType,url){
 		var xhr = new XMLHttpRequest();                 // 创建XMLHttpRequest对象
 		xhr.onload = function() {                       // 当加载响应时
 		if(xhr.readyState == 4){
 			var data=JSON.parse(xhr.responseText)//将请求的json数据转化为javascript对象
 			// 以下条件检查将无法在本地工作-仅在服务器上有效
 			if(xhr.status === 200) {                       // 如果服务器状态正常
 				document.getElementById('content').innerHTML = data.text; // 更新数据
 				console.log(data.text)
 				//xhr.responseXML xml数据类型;xhr.responseText text数据类型;
 			}
 		}
 		};
 		xhr.open(requestType,url);//参数说明:第一个为请求方式,第二个为请求地址,第三个为同步还是异步,第三个参数省略则默认是异步的
 		xhr.send(null);                                 //请求成功
 	}
 	getData('GET', './data/data.json')
  • 基于Token的身份验证:(最简单的Token:id+time当前时间戳+sign签名)
    1. 用户通过用户名和密码发送请求
    2. 服务器端验证
    3. 服务器端返回一个带签名的Token给客户端
    4. 客户端存储Token,并且每次用于发送请求(多用缓存进行存储)
    5. 服务器验证Token并返回数据
    每次请求都需要Token
  • http协议的理解?
    定义:
        1. 超文本传输协议,是用于从万维网服务器超文本传输到本地资源的传输协议
        2. 基于TCP/IP通信协议来传递数据(HTML,图片资源)
        3. 基于运用层的面向对象的协议,由于其简介、快速的方法、适用于分布式超媒体信息系统
    http请求信息(request):请求行+请求头+空行+请求数据(请求体)
        请求行:用来说明请求类型,要访问的资源以及所使用的http版本;
        请求头:用来说明客户端要是用的附加信息
        空行:请求头后面的空行是必须的
        请求数据:也叫主题,可以添加任意的其他数据
    http响应信息(response):状态行+消息报头+空行+响应正文
        状态行:有http协议版本号、状态码、状态消息三部分组成
        消息报头:用来说明客户端使用的一些附加信息
        空行:消息报头后面的空行是必须的
        响应正文:服务器返回给客户端文本信息
  • 数组的方法有哪些,请一一详细列举?(方法特别多,用法也不尽相同,后续会写一个相关博客详细说明)
   Array.from() 方法从一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。
   Array.isArray() 用于确定传递的值是否是一个 Array。
   Array.of() 方法创建一个具有可变数量参数的新数组实例,而不考虑参数的数量或类型。
   concat() 方法用于合并两个或多个数组。此方法不会更改现有数组,而是返回一个新数组。
   copyWithin() 方法浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度。
   entries() 方法返回一个新的Array Iterator对象,该对象包含数组中每个索引的键/值对。
   every() 方法测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。
   fill() 方法用一个固定值填充一个数组中从起始索引到终止索引内的全部元素。不包括终止索引。
   filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
   find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。
   findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。
   flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。
   flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 连着深度值为1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。
   forEach() 方法对数组的每个元素执行一次给定的函数。
   includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false。
   indexOf()方法返回在数组中可以找到一个给定元素的第一个索引,如果不存在,则返回-1。
   join() 方法将一个数组(或一个类数组对象)的所有元素连接成一个字符串并返回这个字符串。
   keys() 方法返回一个包含数组中每个索引键的Array Iterator对象。
   lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。
   map() 方法创建一个新数组,其结果是该数组中的每个元素是调用一次提供的函数后的返回值。
   pop()方法从数组中删除最后一个元素,并返回该元素的值。此方法更改数组的长度。
   push() 方法将一个或多个元素添加到数组的末尾,并返回该数组的新长度。
   reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
   reduceRight() 方法接受一个函数作为累加器(accumulator)和数组的每个值(从右到左)将其减少为单个值。
   reverse() 方法将数组中元素的位置颠倒,并返回该数组。数组的第一个元素会变成最后一个,数组的最后一个元素变成第一个。该方法会改变原数组。
   shift() 方法从数组中删除第一个元素,并返回该元素的值。此方法更改数组的长度。
   slice() 方法返回一个新的数组对象,这一对象是一个由 begin 和 end 决定的原数组的浅拷贝(包括 begin,不包括end)。原始数组不会被改变。
   some() 方法测试数组中是不是至少有1个元素通过了被提供的函数测试。它返回的是一个Boolean类型的值。
   sort() 方法用原地算法对数组的元素进行排序,并返回数组。默认排序顺序是在将元素转换为字符串,然后比较它们的UTF-16代码单元值序列时构建的
   splice() 方法通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。
   toLocaleString() 返回一个字符串表示数组中的元素。数组中的元素将使用各自的 toLocaleString 方法转成字符串,这些字符串将使用一个特定语言环境的字符串(例如一个逗号 ",")隔开。
   toString() 返回一个字符串,表示指定的数组及其元素。
   unshift() 方法将一个或多个元素添加到数组的开头,并返回该数组的新长度(该方法修改原有数组)。
   values() 方法返回一个新的 Array Iterator 对象,该对象包含数组每个索引的值
   
   //本来这个就多,不想写在面试这个版块,不过前几天有个面试官恰好问到数组的方法,让我把知道的全说出来,就只能做个大概的记录先了,怕你们会遇到类似的问题
  • 常见的web安全及防护原理:
    攻击方式:
        1. sql注入原理:是将sql代码伪装到输入参数中,传递到服务器解析并执行的一种攻击手法。
        也就是说在一些server端发起的请求参数中植入一些sql代码,server端在执行sql操作时,会拼接对应参数。同时也将一些sql注入攻击的sql拼接起来,导致会执行一些预期之外的操作。
        2.XSS(跨站脚本攻击):注web页面插入恶意的html标签或者js代码。例如在论坛防止一个看似安全的链接,窃取cookie中的用户信息
        3.CSRF(跨站请求伪装):通过伪装来自受信任用户的请求。
    防范方式:
        1.sql注入:对用户输入进行校验;不使用动态拼接的sql
        2.XSS:尽量采用post而不使用get提交表单;尽量避免cookie中泄漏用户的隐私
        3.CSRF:通过增加验证码
    XSS和CSRF的区别:
        1.XSS是获取信息,不需要提前知道其他用户页面的代码和数据包
        2.CSRF代替用户完成指定的动作,需要知道其他页面的代码和数据包
  • 数组去重:
  1. 方法一:

利用扩展运算符和set去重,扩展运算符将类数组转数组,set数据不能重复

    let arr = [1,2,3,1,2,3,4,5,6];
    arr = [... new Set(arr)];
    document.write(arr); //1,2,3,4,5,6
  1. 方法二:

利用Array.from将类数组转化成数组,set的数据不能重复的特性拿来去重

    let arr = [1,2,3,1,2,3,4,5,6];
    arr = [Array.from(new Set(arr))];
    document.write(arr);//1,2,3,4,5,6
  1. 方法三:

创建一个空数组,将已知数组中的变量赋值给for循环中声明的变量,然后将这个变量在空数组中进行检索,如果没有则push到空数组中

    var arr = [1,2,3,1,2,3,4,5,6];
    var newArr = [];
    for (let i = 0; i < arr.length; i++) {
    	let cur = arr[i];
    	if(newArr.indexOf(cur)===-1){
    		newArr.push(cur);
    	}
    }
    document.write(newArr);
  1. 方法四:

思路跟方法三一样,只是用的es6的语法

    var arr = [1,2,3,1,2,3,4,5,6];
    var newArr = [];
    arr.forEach(arr=>newArr.includes(arr)?'':newArr.push(arr));
    document.write(newArr);
  1. 方法五:

同时创建一个空数组和一个空map数据,如果map中没有则向map和空数组中同时添加该数据

    var arr = [1,2,3,1,2,3,4,5,6];
    var newArr = [];
    var newMap = new Map();
    arr.forEach(arr=>{
    	if(!newMap.has(arr)){
    		newMap.set(arr,true);
    		newArr.push(arr);
    	}
    })
    document.write(newArr);
  • 3种强制类型转化和2中隐式类型转化?
    强制类型转化:Number();String();Boolean();
    隐式类型:+;!;
  • 无缝轮播实现原理:(大学时写的代码,可能有的地方需要修改,还好之前确实用js实现过,不然真的被问倒了,只贴代码,文字叙述自行概括)
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style>
        *{ margin: 0; padding: 0; text-decoration: none;}
        body {padding: 20px;}
        #container { width: 600px; height: 400px; border: 3px solid #333; overflow: hidden; position: relative;}
        #list { width: 4200px; height: 400px; position: absolute; z-index: 1;}
        #list img { float: left;width: 600px;}
        #buttons { position: absolute; height: 10px; width: 100px; z-index: 2; bottom: 20px; left: 250px;}
        #buttons span { cursor: pointer; float: left; border: 1px solid #fff; width: 10px; height: 10px; border-radius: 50%; background: #333; margin-right: 5px;}
        #buttons .on {  background: orangered;}
        .arrow { cursor: pointer; display: none; line-height: 39px; text-align: center; font-size: 36px; font-weight: bold; width: 40px; height: 40px;  position: absolute; z-index: 2; top: 180px; background-color: rgba(0,0,0,.3); color: #fff;}
        .arrow:hover { background-color: rgba(0,0,0,.7);}
        #container:hover .arrow { display: block;}
        #prev { left: 20px;}
        #next { right: 20px;}
    </style>
    <script>
        window.onload=function() {
            // body... 
            var prev=document.getElementById("prev");
            var next=document.getElementById("next");
            var list=document.getElementById("list");
            var buttons=document.getElementById("buttons").getElementsByTagName("span");
            var container=document.getElementById("container");
            var index=1;
            var timer;
            var animated=false;
            function shownButton(){
                 for (var i = 0; i < buttons.length ; i++) {
                    if( buttons[i].className == 'on'){
                        buttons[i].className = '';
                       /* prev和next每click一次,
                        就会清除一次前一个class为on的span元素,
                        所以没有必要再去循环下面的span*/
                        break;
                    }
                    //  或者直接遍历清除  buttons[i].className="";
                }
                buttons[index -1].className="on";
            }
            function animate(offset){ 
                var time = 300;
                var inteval = 10;
                var speed = offset/(time/inteval);
                  animated=true;
                 var newLeft=parseInt(list.style.left) +offset;
                function go(){
                    if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
                        list.style.left = parseInt(list.style.left) + speed + 'px';
                        setTimeout(go, inteval);
                    }
                    else 
                    {
                        
                       animated=false;
                     // list.style.left=newLeft+"px";
                         if (newLeft >-600) {
                     list.style.left=-3000+"px";
                         };
                        if (newLeft <-3000) {
                     list.style.left=-600+"px";
                      };
                    }
                }
                go();
            };
               
            prev.onclick=function(){
                /*添加一个if判断index为1时,如果继续往前滚的话就让index返回第五个span
                但是当快速点击arrow时会出现一种span点亮延迟的情况。可以尝试把判断index是否大于1或小于5的情况放进
                判断是否animated的if语句中,先判断能不能点击,再点亮。
                */
                if (!animated) {
                if (index==1) {
                    index=5;
                }else {
                   index -=1; 
                }
                
                shownButton();
                     animate(600);
                }
              
               
            };
            next.onclick=function(){
                 
                
                
                if (!animated) {
                     if (index==5) {
                    index=1;
                }else {
                   index +=1; 
                }    
                     shownButton();
                     animate(-600);
                }
            };
            for (var i = 0; i < buttons.length; i++) {
                buttons[i].onmouseover=function(){
                    //无关紧要
                    if (this.className=="on") {
                        return;
                    }
                    var myIndex=parseInt(this.getAttribute("index"));
                    var offset=-600*(myIndex-index);
                     if (!animated) {
                     animate(offset);
                }
                    index=myIndex;
                     shownButton();
                
                }
            }
            
            function play(){
                timer=setInterval(function(){
                    next.onclick();
                },2000);
            }
            function stop(){
                clearInterval(timer);
            }
           play();
        container.onmouseover=stop;
        container.onmouseout=play;
        }
    </script>
</head>
<body>
	
<div id="container">
    <div id="list" style="left: -600px;">
        <img src="img/555.jpg" alt="1"/>
        <img src="img/111.jpg" alt="1"/>
        <img src="img/222.jpg" alt="2"/>
        <img src="img/333.jpg" alt="3"/>
        <img src="img/444.jpg" alt="4"/>
        <img src="img/555.jpg" alt="5"/>
        <img src="img/111.jpg" alt="5"/>
    </div>
    <div id="buttons">
        <span index="1" class="on"></span>
        <span index="2"></span>
        <span index="3"></span>
        <span index="4"></span>
        <span index="5"></span>
    </div>
    <a href="javascript:;" id="prev" class="arrow">&lt;</a>
    <a href="javascript:;" id="next" class="arrow">&gt;</a>
</div>
</body>
</html>
//注:请更换图片地址,否则看不到效果

这些问题只是js的冰山一角,有很多东西并没有涉及到,我的想法是将js的每一部分,例如:dom、bom、es(es中有许多内置对象)将这些内容全都以对象的形式:例如:data、number、sting、math写每一个点都写一个单独的博客!但这就不是涉及到面试了,而是对js基础的查漏补缺!!!!

es6

  • 你用到过哪些es6的知识?
    *声明方式——let、const
    *模板字符串——`${name}16岁`
    *箭头函数——let fn=()=>{}
    *增强对象字面量——fn(){}
    *函数参数默认值——function fn(num=1){console.log(num)}
    *展开运算符——
    let reduce=(...arr)=>{
        return arr.reduce((num,sum)=>{
            return sum + num;
        },0);
    }
    console.log(reduce(1,2,3,4,5));//15
    *解构——let [a, b, c] = [1, 2, 3];let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
    *class类——
    class Obj{
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }

        toString() {
            return `${this.x}${this.y}`;
        }
    }
    let newObj = new Obj(1,2);//12
    console.log(newObj.toString());
    *Map——可以保存键为任意类型的值
    let map = new Map();
    let [key1,key2,key3] = [{},function(){},null];
    map.set(key1,"123");
    map.set(key2,null);
    map.set(key3,true);
    console.log(map.get(key1),map.get(key2),map.get(key3));
    console.log(map);//Map(3) {{…} => "123", ƒ => null, null => true}
    *Set——类似数组,但数据不重复
    let arr = [1,1,2,3];
    function removalArr(arr){
        return [...new Set(arr)];
    }
    console.log(removalArr(arr));//[1, 2, 3]
    *Promise——异步操作均可用
    new Promise((resolve, reject)=>{
        let x = 1|2;
        resolve(x+1);
    }).then(r => console.log(r)).catch(e => console.log(e));//4
  • 普通函数和箭头函数的区别?
    普通函数:
    1.this指向执行上下文环境,在哪个环境中执行则指向哪个环境
    2.可以当作构造函数,也就是说,可以使用new命令
    3.可以使用arguments对象
    4.可以使用yield命令,因此箭头函数能用作 Generator 函数
    箭头函数:
    1.函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。(指向父级作用域)
    2.不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
    3.不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
    4.不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
  • 箭头函数可以用作构造函数吗,可以或不可以请说明原因?
    不能,不能使用new命令去实例化出一个新对象,当使用new命令时会报错
  • 扩展运算符的应用场景:
    1. 数组去重——[...new Set(arr)];
    2. 求最值——Math.max(...arr);
    3. 浅拷贝—— {...obj}
    4. 合并数组——[...arr1, ...arr2, ...arr3]
    5. 字符串转数组——[...'hello']
  • let、const、var的区别?
    let: 块级作用域、无变量提升、有暂时性死区
    const:声明常量(一旦声明就必须立即初始化)、无变量提升、暂时性死区、块级作用域
    var:函数作用域和全局作用域、有变量提升、无暂时性死区
  • 遍历数组的所有方式?(今天又问到这个问题了,本来这是之前那个笔试思考题的解决方法的)
    1. do...while;
    2. while;
    3. for...in;
    4. for...of;
    5. forEach;
    6. map;
    7. 递归
    8. for循环
  • forEach和map的区别?
    forEach是单纯的循环,而map则是数组的映射;
    map的应用场景:
    [1,2,3].map(item=>item+1);//[2,3,4]
    [{name:'张三',id:1},{name:'李四',id:2}].map(item=>item.name);//["张三", "李四"]
  • map和forEach如何提前退出?
    有且仅有一种方法,那就是抛出异常
    [1,2,3].map(item=>{
		console.log(item);
		throw "提前退出----";
	})
	[1,2,3].forEach(item=>{
		console.log(item);
		throw "提前退出----";
	})

vue:

  • computed(计算属性)和data属性有啥区别?
    data中的属性不会赋值值变量的改动而改动(类似于num:a.b)
    computed则不一样
  • v-if和v-for为什么要避免同时使用,正确做法应该怎么做?
    v-for 比 v-if 具有更高的优先级
    1. 情况一:为了过滤一个列表中的项目 (比如 v-for="user in users" v-if="user.isActive")。
    正确做法:
    <ul>
      <li
        v-for="user in activeUsers"
        :key="user.id"
      >
        {{ user.name }}
      </li>
    </ul>
    computed: {
        activeUsers: function () {
            return this.users.filter((user)=>{
                return user.isActive
            })
        }
    }
    2. 情况二:为了避免渲染本应该被隐藏的列表 (比如 v-for="user in users" v-if="shouldShowUsers")。
    正确做法:
    <ul v-if="shouldShowUsers">
     <li
        v-for="user in users"
        :key="user.id"
     >
        {{ user.name }}
      </li>
    </ul>
  • v-for中key的作用?
    为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。key属性的类型只能为 string或者number类型。
  • vue中v-for的key值为什么要绑定item.id而不是index?
    diff算法默认使用“就地复用”的策略,是一个首尾交叉对比的过程。
    用index作为key和不加key是一样的,都采用“就地复用”的策略
    “就地复用”的策略,只适用于不依赖子组件状态或临时 DOM 状态 (例如:表单输入值) 的列表渲染输出。
    如果数据项的顺序被改变,vue不会移动dom元素来匹配数据项的顺序,而是简单的复用此处的每个元素
    将与元素唯一对应的值作为key,可以最大化利用dom节点,提升性能
    
    简单的归纳:数据的顺序如果发生改变,diff会就地复用,不会移动dom来匹配数据项的顺序。元素唯一的id做为key可以最大化提升性能
  • 单页面应用加载首页白屏如何解决?
    1. 路由懒加载
    2. 骨屏架构加载
    3. 首屏采用服务端渲染
    4. 加一个loading图,优化用户体验
  • vue数据已经更新,但视图不更新的产生原因及解决办法?

分为两种情况:

  1. this指向有问题,用axios请求数据的时候将回调函数写成了普通函数
    解决办法:改用箭头函数
  1. 受现代 JavaScript 的限制,Vue 无法检测到对象属性的添加或删除
    使用vue.set方法
  • vue页面刷新,数据丢失?
    这种情况多半是vuex的数据丢失,一般情况下:
    1. 使用缓存将数据存储起来(推荐使用,可以降低服务器压力)
    2. 重新获取接口数据
  • 如何实现一个vue的自定义指令,以及说一下它的作用?
    作用:自定义指令是用来操作DOM的,不是所有情况都适合数据驱动!!!
    <span v-rainbow></span>
    Vue.directive("rainbow",{
    	bind(el,binding,vnode){
    		el.style.color="#"+Math.random().toString(16).slice(2,8);
    	}
    })
  • 如何实现一个vue的过滤器,以及说一下过滤器的作用?
    作用:文本过滤
    <sapn>{{数据 | snippet}}</span>
    Vue.filter('snippet', (value)=>{
        return value.slice(0,100)+"...";
    })
  • $route$router 的区别?
    前者是路由信息对象,主要是用于设置或获取路由参数;
    后者是路由实例,包括路由的跳转方法和路由实例
  • vue-router怎么重定向页面?
    配置redirect属性
  • vue 路由去掉#?
    配置mode: 'history'
  • vue跳转新路由 滚动到固定位置?
    export default new Router({
      // mode: 'history',  //可以去掉url中的#。但是打包后需要后台配置,否则会404
      routes: routerMap,
      scrollBehavior(to, from, savedPosition) { //设置回到顶部
        if (savedPosition) {
            return savedPosition
        }
        return {x: 0, y: 0}
      }   
    })
  • 第一次页面加载会触发哪几个钩子?
    第一次加载会触发 beforeCreate、created、beforeMount、mounted
  • vue-router传参?
    this.$router.push({
        path:'/xxx',
        query:{
          id:id
        }
    })
  • v-show和v-if的区别?
    v-show:是css的渲染,频繁切换时用v-show。
    v-if:是完整的销毁和重新创建,较少改变时用v-if,v-if是条件渲染,为false时不会渲染。
  • computed(计算属性)和watch(监听属性)的区别?
    computed:是自动监听依赖值的变化,从而动态返回内容。
    watch:此方法是需要知道值改变后执行业务逻辑。
  • vue生命周期?
    beforeCreate:类型为:Function,在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。(创建前,元素和数据都为undefined,未初始化。)
    created:类型为:Function,数据观测 (data observer),属性和方法的运算,watch/event 事件回调。(创建后,数据有了,元素还是为undefined,用于请求数据)
    beforeMount:类型为:Function,载入前,在挂载开始之前被调用:相关的 render 函数首次被调用。(元素和数据都初始化了,但是还是挂在真实的dom节点上)
    mounted:类型:Function,vue实例挂载完成,数据成功渲染(mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick)
    beforeUpdate:类型为:Function,数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。(更新前,当data变化时会触发该方法)
    updated:类型为:Function,由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。(更新后,当data变化时会触发该方法)
    beforeDestroy:vue实例销毁前触发,需要解除手动绑定的事件。
    destroyed:vue实例销毁后触发该事件
  • 组件通信,请用代码实现?
  • 缺具体代码,后续实现!!!
    父子组件通信:props/$emit | ref与$parent/$children
    隔代组件通信:$attrs/$listeners | provide/inject
    兄弟组件通信:vuex | EventBus
  • 父子组件通信:props/$emit 例子:

props:父传子

    父组件:
    //组件引入和组件注册已省略
    <template>
        <ChildOne :msg="msg" />
    </template>
    <script>
    export default {
      data() {
        return {
          msg: "我是父组件,我给你发消息"
        }
      }
    }
    </script>
    子组件:
    <template>
        <div>我接受到的父组件的消息是:{{msg}}</div>
    </template>
    
    <script>
    export default {
      props: {
        msg: {
          type: String
        }
      }
    }
    </script>

子传父$emit:

    父组件:
    //组件注册和组件引入已省略
    <template>
        <div>
            <div>我即将接收第二组件传值是:{{child2Msg}}</div>
            <ChildTwo @toParent="getMag" />
        </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          child2Msg: ""
        }
      },
      methods: {
        getMag(msg) {
          this.child2Msg = msg;
        }
      }
    };
    </script>

子组件:

    <template>
      <div>
        <div>我要发送给父组件的值:{{msg}}</div>
        <button @click="toParent">向父组件发送信息</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          msg: "我是第二组件,我要给父组件传值"
        };
      },
      methods: {
        toParent() {
          this.$emit("toParent", this.msg);
        }
      }
    };
    </script>
  • 兄弟组件EventBus

兄:

    <template>
        <button @click="toBrother">点我给兄弟传值</button>
    </template>
    
    <script>
    export default {
      data() {
        return {
          to: "哈喽老二"
        };
      },
      methods: {
        toBrother() {
          this.bus.$emit("toBrother", this.to);
        }
      }
    };
    </script>

弟:

    <template>
      <div>
        <div>我得到的兄弟组件信息是:{{get}}</div>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          get: ""
        };
      }
      beforeCreate() {
        this.bus.$on("toBrother", msg => {
          this.get = msg;
        });
      }
    };
    </script>
  • vuex中的属性:
    1. state:定义初始数据与数据存储;
    2. getters:获取数据;
    3. Mutation:改变数据;
    4. Action:异步操作;
    5. Module:将单一的数据产分成多个、
  • 解释一下mvvm模式?
    m:数据模型:后端提供的api接口。
    v:视图层:html和css构建的用户界面。
    vm:视图数据层:交互逻辑。
  • 解释一下vue的数据双向绑定原理?
    1. 创建虚拟dom树
    2. 一旦被检测的数据改变会通过Object.defineProperty定义数据拦截,截取到数据的变化。
    3. 截取到数据变化从而通过订阅--发布者模式触发观察者,从而改变虚拟dom中的具体数据
    4. 通过更新虚拟dom的元素值,从而改变最后渲染dom的值,完成双向绑定的实现
  • vue中的data为什么是一个函数,请说明原因?`
  对象为引用类型,当复用组件时,由于数据对象都指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改;
  而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题。
  • vue为什么组件中只能有一个根元素?
    是为了指定单页面的入口
  • vue组件继承?
    import Vue from 'vue'
    
    const component = {
      props: {
        active: Boolean,
        propOne: {
          required: true
        }
      },
      template: `
        <div>
          <input type="text" v-model="text"/>
          <span>{{propOne}}</span>
        </div>
      `,
      data () {
        return {
          text: 0
        }
      },
      mounted () {
        console.log('comp mounted')
      }
    }
    
    const CompVue = Vue.extend(component)
    
    new CompVue({
      el: '#root',
      propsData: {
        propOne: 'xxx'
      },
      data: {
        text: '123'
      },
      mounted () {
        console.log('instance mounted')
      }
    })
  • vue初始化页面闪动问题的产生原因及解决办法?
    使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于{{message}}的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。
    在css中添加:
    ```
    [v-cloak] {
        display: none;
    }
    ```
    如果不管用的话在根元素上添加:
    ```
    style="display: none;" :style="{display: 'block'}"
    ```
  • vue项目优化怎么做?
(1)代码层面的优化
    v-if 和 v-show 区分使用场景
    computed 和 watch  区分使用场景
    v-for 遍历必须为 item 添加 key,且避免同时使用 v-if
    长列表性能优化
    事件的销毁
    图片资源懒加载
    路由懒加载
    第三方插件的按需引入
    优化无限列表性能
    服务端渲染 SSR or 预渲染
(2)Webpack 层面的优化
    Webpack 对图片进行压缩
    减少 ES6 转为 ES5 的冗余代码
    提取公共代码
    模板预编译
    提取组件的 CSS
    优化 SourceMap
    构建结果输出分析
    Vue 项目的编译优化
(3)基础的 Web 技术的优化
    开启 gzip 压缩
    浏览器缓存
    CDN 的使用
    使用 Chrome Performance 查找性能瓶颈
  • 什么是服务端渲染(ssr)?
    ssr可以将同一个组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器的一种渲染方式
  • 服务端渲染的优势?
    1. 更好的 SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
    2. 更快的内容到达时间 (time-to-content),特别是对于缓慢的网络情况或运行缓慢的设备。
  • 服务端渲染的权衡之处:
    1. 开发条件所限。
    2. 涉及构建设置和部署的更多要求。
    3. 更多的服务器端负载。
  • 如何用ssr去做项目优化?(这个涉及项目的话相对来说太复杂了,描述比较困难,可以从如何使用ssr来描述,这样要简单一点)
    需要的指令:
        1. npm install vue vue-server-renderer --save
        2. npm install express --save
    具体代码:(需要有node基础)
        const Vue = require('vue');
        const server = require('express')();
        
        const template = require('fs').readFileSync('./index.template.html', 'utf-8');
        
        const renderer = require('vue-server-renderer').createRenderer({
          template,
        });
        
        const context = {
            title: 'vue ssr',
            metas: `
                <meta name="keyword" content="vue,ssr">
                <meta name="description" content="vue srr demo">
            `,
        };
        
        server.get('*', (req, res) => {
          const app = new Vue({
            data: {
              url: req.url
            },
            template: `<div>访问的 URL 是: {{ url }}</div>`,
          });
        
          renderer
          .renderToString(app, context, (err, html) => {
            console.log(html);
            if (err) {
              res.status(500).end('Internal Server Error')
              return;
            }
            res.end(html);
          });
        })
        
        server.listen(8080);
  • 路由和页面解耦如何做?
    1、只有动态路由才能用路由解耦
    2、在定义路由的时候通过/:属性的方式来定义传递参数的属性
    3、需要在定义路由的时候设置属性props:true
    4、在进行路由跳转的时候通过/值得方式进行传递数据
    5、在需要接收参数的组件中通过props进行接收即可
    具体做法:
    {path:"/:id",name:'',component:'',props:true}
    <router-link :to="{name:'',params:{id:item.id,name:item.name}}"></router-link>
    props:[id,name];
  • 如何跳转到详情页:
    1. 点击的时候获取元素id;
    2. 将id push到url上,跳转到详情页,详情页的路由要拼接上:id;
    3. 跳转到详情页后,获取url上的id,并根据id请求数据
    具体做法:
    <li @click="Fn(item.id)"></li>
    Fn(id){
        this.$route.push({
            path:'路由地址',
            query:{
                id:id
            }
        })
    }
    
    {path:"路由地址/:id",name:'',component:''}
    id:this.$route.query;
    this.$axios.get("请求地址/" + this.id);
  • vue-router有哪几种导航钩子,及作用?
    作用:主要用来作用是拦截导航,让他完成跳转或取消。
    三种:
        1. 全局导航钩子:
            const router = new VueRouter({ ... });
            router.beforeEach((to, from, next) => {
                // do someting
            });
        2. 路由独享的钩子beforeEnter
            cont router = new VueRouter({
                routes: [
                    {
                        path: '/file',
                        component: File,
                        beforeEnter: (to, from ,next) => {
                            // do someting
                        }
                    }
                ]
            });
        3.组建内的导航钩子
        const File = {
            const File = {
                template: `<div>This is file</div>`,
                beforeRouteEnter(to, from, next) {
                    // do someting
                    // 在渲染该组件的对应路由被 confirm 前调用
                },
                beforeRouteUpdate(to, from, next) {
                    // do someting
                    // 在当前路由改变,但是依然渲染该组件是调用
                },
                beforeRouteLeave(to, from ,next) {
                    // do someting
                    // 导航离开该组件的对应路由时被调用
                }
            }
        }
  • 模块儿化的理解及模块儿化的规范?
    模块儿化:就是将一些功能封装成一些小的代码模块儿,提高代码的复用性
    模块儿化规范:目前没找到相关答案!!!!!!!!!!!!!!!!
  • 缓存可以解决首屏加载白屏吗,为什么?
    不可以,一般是首屏加载之后才缓存的数据,缓存的数据也只能解决第二次加载速度快慢的问题,用缓存的话首次加载依旧会白屏
  • 如何将父子组件所传的值绑定,子组件变化父组件也会变化?
  • 有做过支付功能吗,支付的话大概是用什么支付,说说具体都是怎么实现的?

注:有很多东西项目里都用过,不过我懒得去找,有很多代码都是网上搜的,可能有错。所以如果有的话可以提出来,我好更正,谢谢各位!

微信小程序:

  • 组件传值:

父传子:

  1. wxml:(父组件)
   <view>
     <componentB paramAtoB='{{paramAtoB}}'></componentB>
   </view>
  1. json:(父组件)
   {
     "navigationBarTitleText": "父子传值",
     "usingComponents": {
       "componentB": "../../components/son/son"
     }
   }
  1. js:(父组件)
   Page({
     data: {
       paramAtoB: "我是A向B传值"
     }
   })
  1. wxml:(子组件)
   <view class="inner">
     {{paramAtoB}}
   </view>
  1. js:(子组件)
   Component({
     //B在这里接收与data类似可以直接在wxml上用
     properties: {
       paramAtoB: {
         type: String,//类型
         value: 'default value'//默认值
       }
     },
     data: {
       
     }
   })
  1. json(子组件)
   {
     "component": true,
     "usingComponents": {}
   }

子传父:

  • 生命周期
    1. onLoad:页面加载完成时
    2. onReady:页面渲染完成时
    3. onShow:页面显示时
    4. onHide:页面隐藏时
    5. onUnload:页面关闭时
  • 小程序如何请求数据?
  function request(url, data = {}, method = "GET") {
     return new Promise(function (resolve, reject) {
       wx.request({
         url: url,
         data: data,
         method: method,
         header: {
           'Content-Type': 'application/json',
           'X-Nideshop-Token': wx.getStorageSync('token')
         },
         success: function (res) {
           resolve(res);
         },
         fail: function (err) {
           reject(err);
         }
       })
     })
   }
  • 小程序如何将数据绑定到自定义属性data上?
    元素上设置:
    data-id="{{item.id}}";
    获取id:(一般是通过点击事件,通过里面自带的event对象获取)
    let id = e.currentTarget.dataset.id;
  • 小程序如何将数据写入js文件中的data?
    this.setData({
        key:val
    })

移动端:

  • click的300ms延迟问题
    产生原因: 由于移动端会有双击缩放的这个操作,因此浏览器在click之后要等待300ms,看用户有没有下一次点击,也就是这次操作是不是双击。
    解决方案:
        方案一:禁用缩放
        方案二:更改默认的视口宽度
        方案三:CSS touch-action
        方案四:FastClick
  • 点击穿透?
    解释:假如页面上有两个元素A和B。B元素在A元素之上。我们在B元素的touchstart事件上注册了一个回调函数,该回调函数的作用是隐藏B元素。我们发现,当我们点击B元素,B元素被隐藏了,随后,A元素触发了click事件。
    解决方案:
        方案一:只用touch
        方案二:只用click
        方案三:tap后延迟350ms再隐藏mask
        方案四:pointer-events
  • 圆角bug
    某些Android手机圆角失效 background-clip:padding-box;
  • 1px border问题
    用小数写边框
  • active兼容处理 即 伪类:active失效
    方法一:body添加ontouchstart
    方法二:js给document绑定touchstart或touchend事件

开放性问题:

  • 说说你的编码习惯?(实际上是问编码规范)
    1. 驼峰命名;
    2. 文件夹命名推荐使用减号(-)连接
    3. 不要指定引入资源所带的具体协议。
    4. 代码缩进一次缩进两个空格
    5. 注释应该不要写你的代码都干了些什么,而要写你的代码为什么要这么写,背后的考量是什么
    6. 必须要给文档声明
    7. 最好不要将无内容元素[1] 的标签闭合,例如:使用 <br> 而非 <br />
    8. 脚本引用写在 body 结束标签之前,并带上 async 属性。
    9. 推荐使用语义化html
    10. HTML 内容至上
    11. 图片推荐加alt属性
    12. HTML 引号推荐使用""
    13. 变量必须要用关键字声明
    14. 总是使用带类型判断的比较判断,推荐使用==
    15. 分号需要用在表达式的结尾,而并非函数声明的结尾。
    16. 不要在语句块内写函数声明,正确的是将函数写成表达式赋值给变量
    17. 切勿在循环中创建函数
    18. 合理的避免使用ID
    19. CSS选择器中避免标签名
    20. CSS提供了各种缩写属性(如 font 字体)应该尽可能使用,即使在只设置一个值的情况下。使用缩写属性对于代码效率和可读性是有很有用的
    21. 省略“0”值后面的单位
    22. 用减号连接class或者id(.ads-sample)
    23. 声明顺序:
    ```
        结构性属性:
        display
        position, left, top, right etc.
        overflow, float, clear etc.
        margin, padding
        表现性属性:
        background, border etc.
        font, text
    ```
    24. 为了保证一致性和可扩展性,每个声明应该用分号结束,每个声明换行。
    25. 属性名的冒号后使用一个空格。
    26. 选择器和声明分离
    27. 规则之间始终有一个空行(双换行符)分隔。
    28. 属性选择器或属性值用双引号(””),而不是单引号(”)括起来
    29. 嵌套选择器和CSS属性之间空一行。
  • 说说你的竞争优势?(可以从学习能力;抗压能力;技能覆盖度;以及技能熟练程度来讨论)
    //示例:(请结合自身条件,本示例仅供参考)
    1. 学习能力:之前学了三天node,成功的写了一个数据接口,具有增删查改,批量删除批量修改批量增加以及分页,数据排序,数据搜索等功能
    2. 抗压能力:我能承受连续...天的加班(不推荐)
    3. 技能覆盖度:我会ps切图以及node+mysql(除前端以外有用的技能)
    4. 技能熟练程度:大学就是本专业的,大学就学过html、css、javascript等相关技术,相对来说基础要好一些
  • 你在编程的过程中遇到过哪些问题,你又是如何解决的这些问题?
    //示例:(开放性问题,照着这博客可以随便拖几个问题来答,挑自己会的)
    1. 跨域
    2. 由于采用的浮动布局,父元素高度塌陷导致滚动插件无法滚动
    3. 滚动插件首次加载不能滚动
    4. vue初始化页面闪动问题
    5. vue数据已更新,但视图不更新
    6. vue刷新页面,数据丢失
    ....
  • 动画效果你有做过吗?(个人认为这是一个开放性问题)
    1. css可以做
    2. js可以做
    3. jquery也可以做
    //注:能用css实现的基本上不要用js和query来实现,css性能和流畅度都较js和jquery要高

思考?(此部分是我留给读者的思考,也是我面试所做的笔试题,各位有兴趣可以尝试一下!概念性的问题是我需要征集答案的问题,也贴在这儿吧!)

  1. 请在脑海中运行出下列代码的结果?(结合同步和异步):
    async function async1(){
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
    async function async2(){
        console.log('async2');
    }
    console.log('script start');
    setTimeout(function(){
        console.log('setTimeout');
    },0);
    async1();
    new Promise(function(resolve){
        console.log('promise1');
        resolve();
    }).then(function(){
        console.log('promise2');
    });
    console.log('script end');
  1. 下列代码的输出结果是什么?(请在脑海中运行)
    var a = 10;
    (function(){
        console.log(a);
        a = 5;
        console.log(window.a);
        var a = 20;
        console.log(a);
    })();
  1. 用你知道的方式改写下列代码,写出你能想到的所有方式!(可以添加数组、也可以改写for循环):
    for(let i=0;i < 10;i++){
        setTimeout(()=>{
            console.log(i);
        },100);
    }
  1. 请运行出下列代码的结果:(在脑海中运行)
    function Foo(){
        Foo.a = function(){
            console.log(1)
        };
        this.a = function(){
            console.log(2);
        }
    }
    Foo.prototype.a = function(){
        console.log(3);
    }
    Foo.a = function(){
        console.log(4);
    }
    Foo.a();
    let obj = new Foo();
    obj.a();
    Foo.a();
  1. 写出下列代码的执行结果:(在脑海中运行)
    ['1','2','3'].map(parseInt);
  1. 请输出每位学生的总分及评级,并按照评级排序,评级规则:总分320以上为A,250-320为B,250以下为C,判断评级为C级的学生及他们得分最高的一门课程在其总分中的占比?
    //数据:
    let data = [
		{"name":"张三","subject":"英语","score":98},
		{"name":"张三","subject":"语文","score":113},
		{"name":"张三","subject":"数学","score":88},
		{"name":"李四","subject":"英语","score":102},
		{"name":"李四","subject":"语文","score":139},
		{"name":"李四","subject":"数学","score":98},
		{"name":"王五","subject":"英语","score":82},
		{"name":"王五","subject":"语文","score":104},
		{"name":"王五","subject":"数学","score":93},
		{"name":"赵六","subject":"语文","score":124},
		{"name":"赵六","subject":"数学","score":99}
	];
  1. 请用你知道的所有方式实现以下布局,要求是添加一个item元素布局不会发生改变?
  2. parseInt和patseFloat是什么形式的类型转化?
  3. 同步任务执行完毕再执行异步方法?
  4. 事件循环机制?

hr问答时间:(技术过了,立马就是hr复试,说明这场面试你已通过百分之五十,这只针对社招。实习的话是先hr后技术)

技术版块儿我相信已经没有太大的问题,缺答案的问题我也会在后续补全,不过对于hr版块儿经过昨天那位大佬的批评教育,我发现有许多不足之处,我想今天就专注修改这个部分的错误,毕竟hr在求职过程中也有举足轻重的作用

  1. 上家公司你为什么离职?
    切忌:不要怼之前的公司,要心存感激才能走的更远,而不是一昧的抱怨
    动机:1.用以判断面试者陈述离职原因的真实性; 2.可以作为全面判断面试者的参考因素
    该从哪些地方回答不会被pass?
    1. 发展空间;
    2. 学习空间
    3. 地域交通
    4. 和生活或是家庭产生了重大矛盾
    5. 不可控力(破产、被收购、换领导、业务重组等等)
    老司机式的回答:
    1. 公司搬家了/我搬家了,上班太远,不方便。
    2. 原来单位比较求稳,我是一个追求进步的人,想寻找更有发展的平台。(之前的公司类似于养老公司那种)
    3. 贵司的某某产品/某某文化令我心生仰慕。我对公司企业文化特别向往,希望可以加入(如果能表现出对老东家的认可,对过去经历的感恩,就是加分项了)
  1. 那你上家公司薪资大概多少呢?
    动机:1. hr为了了解行业的大概薪资;2. hr为了排除简历水分
    报薪资大概要怎么报?
    如果要报的话,报综合年收入而不要报月薪,尽可能算上你所有的收入。
    综合年收入=固定工资x12+绩效奖金+各种补贴福利+年终奖+加班费
    而月薪=固定工资x12+绩效奖金
    如果不报?
    这个不太方便透露,我只能说以前的公司薪资理想或者不理想
    能不能说假话:(这只是一个大概的参考数据)
    小公司,90%不做背调
    大公司,90%都要薪酬调查
    高薪该如何要?
    从工作量、业绩量、工作内容、工作价值和能力方面去为自己涨薪提供合理的理由,而不是干巴巴的报个价完事
  1. 那你离职就没有其他原因了吗?
    如果你怼之前公司,那你就入套了。直接说没有就行了
  1. 你住哪里?
    动机:了解你离公司的远近,好判断你的通勤时间
    怎样回答?
    1.目前里公司较远,如果入职的话会考虑搬到公司附近
    2.离公司不远,30分钟之内就可以到公司
  1. 你为什么选择前端这个职业?
    动机:了解你从事这个行业的动机
    //回答第一点和第五点基本上这个问题就没什么毛病了
    1. 对前端工作的热爱
    2. 因为自己专业对口
    3. 当实现某种效果时非常有成就感
    4. 喜欢带着耳机边听歌边敲代码的感觉(纯个人喜好)
    5. 喜欢做一些富有挑战性的事情
    糟糕的回复:
    1. 为了生活
    2. 这个行业薪资普遍较高
    3. 父母让我选择的这个行业
  1. 你的职业规划是什么?
    动机:
        1. 求职者的自我认知
        2. 求职者对岗位、行业的认知度,人岗是否匹配
        3. 求职者的求职态度是否真诚,目标感和稳定性
    从哪些方面进行回答:
        1. 对自己有一个清晰的自我认知与定位,结合性格、兴趣爱好、特长、知识能力等方面
        2. 了解应聘公司的背景、现状与未来,适当与公司发展相贴合;
        3. 更注重专业技能方面的提升,不要说太多薪酬、职位晋升这些外在的东西
        4. 表明自己有长远规划的能力,着眼于最近的3-5年
    答题公式:
        感谢您提出这么深刻的问题。我的兴趣是XXX,优势是XXX,因此我选择了XXX行业/职业,这是一个可以将我的兴趣和工作结合起来的行业,是我非常喜欢的,所以我会很用心对待XXX岗位
  1. 你的性格如何,有没有什么爱好?
    动机:判断你是否能快速融入这个团队;判断你是否全面发展;判断你是团队型or独立型
    判断你是否不断强化自己的技能
    性格一般外向的话比较容易融入团队
    爱好:1.下象棋(逻辑思维类);2.阅读(自我提升类);3.打篮球(团队类)
  1. 你的家庭情况能大概说一下吗?
    动机:1. 判断你的家庭教育情况;2. 判断你是否急需用钱,从而判断你工作的稳定性
    ...每个人的家庭情况都不一样,这个就结合实际情况回答吧
  1. 你对加班是如何看待的?(每当问到这个问题,我都是表面笑嘻嘻,心里mmp)
    这个无需了解动机,因为我讨厌加班。直说的拒绝无意义的加班,如果当天的事情完成了加班,我觉得是无意义的
  1. 你觉得你在之前的公司学到了什么?或者有哪些成长?
    动机:大概是了解你的能力提升
    从哪些方面回答:行业内专业知识的扩充;个人能力的提升
    回答:
        1.在上一个公司学到了xx新技术(雪地能力)
        2.在之前的公司担任过团队组长(管理能力)
  1. 你对我们公司有什么想要了解的吗?
    1. 试用期大概多久?试用期的薪资是如何计算的?
    2. 公司的福利待遇
    3. 公司主要做什么方面的业务?
    4. 公司用的什么技术栈?
    5. 上下班时间?
    6. 加班情况?
    7. 面试结束后回复周期大概是多久?
    8. 薪资构成?
    ...

好文推荐:

  1. 正则表达式
  2. 对象

参考文献:

  1. 史上最强vue总结~万字长文---面试开发全靠它了
  2. web前端面试总结(自认为还算全面哈哈哈哈哈!!!!)
  3. 数组去重12种方案(经典面试必问)
  4. 面试官:请实现三栏布局,尽可能多的方式。
  5. 30 道 Vue 面试题,内含详细讲解(涵盖入门到精通,自测 Vue 掌握程度)
  6. 你要的Vue面试题都在这里
  7. 为什么使用v-for时必须添加唯一的key?
  8. Vue:v-for 与 v-if 的优先级,以及避免同时使用
  9. Vue.js 服务器端渲染指南
  10. 面试题
  11. 前端编码规范

后记:

面试当然是答案越简单越通俗易懂越好,我面试的时候就希望自己能够阐述这种简单易懂的概念,但今天并没有做到,于是乎写下了此篇博客,如果后续去其他公司面试,我会将面试题一一记录在此,以供需要面试的小伙伴参考学习。如果此文对你的面试有帮助,还请帮忙点个赞谢谢!