前端面试题总结-初级

HTTP协议

说一下 http 和 http ?

http  是超文本传输协议,信息是明文传输
Https 是加密的、协议需要 ca 证书,费用较高。

https缺点:
https 握手阶段比较费时,会使页面加载时间延长 50%,增加 10%~20%的耗电。
https 缓存不如 http 高效,会增加数据开销。
SSL 证书也需要钱,功能越强大的证书费用越高。
SSL 证书需要绑定 IP,不能再同一个 ip 上绑定多个域名,ipv4 资源支持不了这种消耗。


tcp 三次握手,一句话概括
TCP 和 UDP 的区别
TCP 是面向连接的,udp 是无连接的即发送数据前不需要先建立链接。
TCP 提供可靠的服务。面向连接,不会丢失数据因此适合大数据量的交换。

TCP 只能是 1 对 1 的,UDP 支持 1 对 1,1 对多。

TCP 是面向连接的可靠性传输,而 UDP 是不可靠的
说一下 http2.0
说一下 http2.0

提升了速度
内容安全,应为 http2.0 是基于 https 的
允许多路复用: 
传输信息进行二进制编码和分帧
服务器端推送


多路复用允许同时通过单一的 HTTP/2 连接发送多重请求-响应信息。改
善了:在 http1.1 中,浏览器客户端在同一时间,针对同一域名下的请求有一定数量限
制(连接数量),超过限制会被阻塞。
:HTTP2.0 会将所有的传输信息分割为更小的信息或者帧,并对他们进行二进制编码
首部压缩

状态码:

200 表示请求成功

301 永久重定向
302 临时重定向
304 get请求被允许但是,但是内容和请求条件没有改变

400 请求无效,前端提交数据的字段名称和字段类型与后台不一致,将 obj 对象通过 JSON.stringify
401 当前请求需要用户验证
403 虽然服务器已经得到请求,但是拒绝执行请求被拒绝
404 找不到资源或者接口不存在

5XX 表示服务端错误
500 服务器端的未知错误
502 网关错误
503 服务暂时无法使用

肯定会碰到: 101/200/301/302/304/400/404/502
补充 400 和 401、403 、304状态码
(1)400 状态码:请求无效
产生原因:前端提交数据的字段名称和字段类型与后台的实体没有保持一致
前端提交到后台的数据应该是 json 字符串类型,但是前端没有将对象 JSON.stringify 转化成字符串。

解决方法:
对照字段的名称,保持一致性,将 obj 对象通过 JSON.stringify 实现序列化

(2)401 状态码:当前请求需要用户验证
(3)403 状态码:服务器已经得到请求,但是拒绝执行

304:如果客户端发送了一个带条件的 GET 请求且该请求已被允许,内容和请求条件并没有改变,就会返回304
对 HTML 语义化标签的理解
双闭合标签,便于阅读,比如 nav表示导航条,类似的还有 article、header、footer 等等标签
GET 和 POST 的区别 参考回答
get 参数通过 url 传递,
post 放在 request body 中。 
get 请求参数会被完整保留在浏览历史记录里,而 post 中的参数不会被保留

GET 产生一个 TCP 数据包;POST 产生两个 TCP
HTTP 支持的方法
get、post,这两个用的是最多的,还有很多比如 patch、delete、put、options 等等
描述一下 XSS 和 CRSF 攻击?防御方法?
XSS(跨站脚本攻击): 向网站注入JS代码,然后执行,篡改网站的内容
 1. 输入过滤 限制输入框文本长度,过滤特殊字符( <> ... )
 2. 在HTTP头部上配置,set-cookie
	Httponly  :禁止Js访问Cookie。
	Secure  : 仅当在https请求时发送Cookie
 

CSRF 跨站请求伪造 是利用网站本身的漏洞请求网站的api。
   验证 HTTP Referer 字段;
   在请求地址中添加 token 并验证;
   在 HTTP 头中自定义属性并验
   

SQL注入
用户输入的文本框中不可以有特殊符号( 引号、空格 )


面试题基础篇

1.1 HTML面试题

行内元素有哪些?块级元素有哪些? 空(void)元素有哪些?
行内元素:span、img、input...
块级元素:div、footer、header、section、p、h1...h6...
空元素:br、hr...


元素之间的转换问题:
display: inline;  		把某元素转换成了行内元素     ===> 不独占一行的,并且不能设置宽高
display: inline-block; 	把某元素转换成了行内块元素   ===> 不独占一行的,可以设置宽高
display: block;			把某元素转换成了块元素		 ===> 独占一行,并且可以设置宽高

HTML5新增标签:

增加了 header,footer,nav,aside,section 等语义化标签
为 input 增加了 color,emial,data ,range 等类型,
提供了 sessionStorage,localStorage
多媒体 audio 和 vedio
另外还有地理定位,canvas画布,canvas 绘图,支持SVG


css3:
border-radius,box-shadow;
background-size,background-origin;
CSS3 2D,3D 转换、transform;animation 动画
页面导入样式时,使用link和@import有什么区别?
区别一:link先有,后有@import(兼容性link比@import兼容);
区别二:加载顺序差别,浏览器先加载的标签link,后加载@import
title与h1的区别、b与strong的区别、i与em的区别?
title与h1的区别:

定义:
	title:概括了网站信息,可以告诉搜索引擎或者用户关于这个网站的内容主题是什么
	h1:文章主题内容,告诉蜘蛛我们的网站内容最主要是什么
区别:
	title他是显示在网页标题上、h1是显示在网页内容上
	title比h1添加的重要 (title > h1 ) ==》对于seo的了解
场景:
	网站的logo都是用h1标签包裹的	
b与strong的区别:

定义:
	b:实体标签,用来给文字加粗的。
	strong:逻辑标签,用来加强字符语气的。
区别:
	b标签只有加粗的样式,没有实际含义。
	strong表示标签内字符比较重要,用以强调的。
	
题外话:为了符合css3的规范,b尽量少用该用strong就行了。
i与em的区别:

定义:
	i:实体标签,用来做文字倾斜的。
	em:是逻辑标签,用来强调文字内容的
区别:
	i只是一个倾斜标签,没有实际含义。
	em表示标签内字符重要,用以强调的。
场景:
	i更多的用在字体图标,em术语上(医药,生物)。
img标签的title和alt有什么区别?
区别一:
	title : 鼠标移入到图片显示的值
	alt   : 图片无法加载时显示的值
区别二:
	在seo的层面上,蜘蛛抓取不到图片的内容,所以前端在写img标签的时候为了增加seo效果要加入alt属性来描述这张图是什么内容或者关键词。
png、jpg、gif 这些图片格式解释一下,分别什么时候用?
png:无损压缩,尺寸体积要比jpg/jpeg的大,适合做小图标。
jpg:采用压缩算法,有一点失真,比png体积要小,适合做中大图片。
gif:一般是做动图的。
webp:同时支持有损或者无损压缩,相同质量的图片,webp具有更小的体积。兼容性不是特别好。

1.2 CSS面试题

介绍一下CSS的盒子模型
CSS的盒子模型有哪些:标准盒子模型、IE盒子模型
CSS的盒子模型区别:
	标准盒子模型:margin、border、padding、content
	IE盒子模型 :margin、content( border +  padding  + content )
通过CSS如何转换盒子模型:
	box-sizing: content-box;	/*标准盒子模型*/
	box-sizing: border-box;	  /*IE盒子模型*/
line-height和heigh区别【大厂】
line-height  是每一行文字的高,如果文字换行则整个盒子高度会增大(行数*行高)。
height  是一个死值,就是这个盒子的高度。
CSS选择符有哪些?哪些属性可以继承?
CSS选择符:
    通配(*)
    id选择器(#)
    类选择器(.)
    标签选择器(div、p、h1...)
    相邻选择器(+)
    后代选择器(ul li)
    子元素选择器( > )
    属性选择器(a[href])
    
CSS属性哪些可以继承:
		文字系列:font-size、color、line-height、text-align...
***不可继承属性:border、padding、margin...
CSS优先级算法如何计算?
优先级比较:!important > 内联样式 > id > class > 标签 > 通配
CSS权重计算:
第一:内联样式(style)  权重值:1000
第二:id选择器  		  权重值:100
第三:类选择器 	     权重值:10
第四:标签&伪元素选择器   权重值:1
第五:通配、>、+         权重值:0
用CSS画一个三角形
用边框画(border),例如:
{
		width: 0;
		height: 0;
		border-left:100px solid transparent;
		border-right:100px solid transparent;
		border-top:100px solid transparent;
		border-bottom:100px solid #ccc;
}
画一条 0.5px 的线
 1. 采用 meta viewport 的方式 (缩放0.5 移动端才有效果)
 

  3.transform: scale()
垂直居中的方法
定位为上下左右为 0,margin:0 可以实现脱离文档流的居中.
margin 负值法 -height 的一半 -width 的一半
transform:translateX(-50%)和 transform:translateY(-50%)

垂直居中

设置line-height 等于height
display:flex + align-items: center
display:table+display:table-cell + vertical-align: middle;

一个盒子不给宽度和高度如何水平垂直居中?
方式一:弹性盒
main
.container
{ display: flex; justify-content: center; align-items: center; width: 300px; height: 300px; border:5px solid #ccc; } .main{ background: red; }
方式二: transform
main
.container
{ position: relative; width: 300px; height: 300px; border:5px solid #ccc; } .main{ position: absolute; left:50%; top:50%; background: red; transform: translate(-50%,-50%); }
方式二:grid 网格布局 (用的少)
main
.container
{ display: grid; justify-content: center; align-items: center; width: 300px; height: 300px; border:5px solid #ccc; } .main{ background: red; }
display有哪些值?说明他们的作用。
none     			隐藏元素
block    			把某某元素转换成块元素
inline   			把某某元素转换成内联元素
inline-block 	    把某某元素转换成行内块元素
BFC(块级格式化上下文,用于清楚浮动,防止 margin 重叠等)
BFC 是页面上的一个独立容器,子元素不会影响到外面元素


2. BFC的原则:如果一个元素具有BFC,那么内部元素再怎么弄,都不会影响到外面的元素。
3. 如何触发BFC:
		float的值非none
		overflow的值非visible
		display的值为:inline-block、table-cell...
		position的值为:absoute、fixed
清除浮动有哪些方式?
1. 触发BFC
2. 多创建一个盒子,添加样式:clear: both;
3. after方式
	ul:after{
			content: '';
			display: block;
			clear: both;
	}
在网页中的应该使用奇数还是偶数的字体?为什么呢?
偶数 : 让文字在浏览器上表现更好看。

另外说明:ui给前端一般设计图都是偶数的,这样不管是布局也好,转换px也好,方便一点。
position有哪些值?分别是根据什么定位的?
static [默认]  没有定位
fixed  固定定位,相对于浏览器窗口进行定位。
relative  相对于自身定位,不脱离文档流。
absolute	相对于第一个有relative的父元素,脱离文档流。


relative和absolute区别
1. relative不脱离文档流 、absolute脱离文档流
2. relative相对于自身 、 absolute相对于第一个有relative的父元素
3. relative如果有left、right、top、bottom ==》left、top
	 absolute如果有left、right、top、bottom ==》left、right、top、bottom
写一个左中右布局占满屏幕,其中左、右俩块固定宽200,中间自适应宽,要求先加载中间块,请写出结构及样式。
双飞翼:
left、center、right三种都设置左浮动
设置center宽度为100%
设置负边距,left设置负边距为100%,right设置负边距为自身宽度
设置content的margin值为左右两个侧栏留出空间,margin值大小为left和right宽度
什么是CSS reset?
reset.css   		是一个css文件,用来重置css样式的。
normalize.css 	为了增强跨浏览器渲染的一致性,一个CSS 重置样式库。
css sprite 精灵图 是什么,有什么优缺点
1. 是什么
	把多个小图标合并成一张大图片。
2. 优缺点
	优点:减少了http请求的次数,提升了性能。
	缺点:维护比较差(例如图片位置进行修改或者内容宽高修改)
display: none;与visibility: hidden;的区别
1. 占用位置的区别
display: none; 				是不占用位置的
visibility: hidden;   虽然隐藏了,但是占用位置

2. 重绘和回流的问题
display: none;     页面产生重绘+回流
visibility: hidden;   产生重绘


display: none 会影响计数器
visibility: hidden 不会影响计数器,且具有继承性,比如父盒子设置了visibility: hidden,子元素会继承该属性,当子元素再次设置 visibility: visible,元素又会显示。

产生回流一定会造成重绘,但是重绘不一定会造成回流。

产生回流的情况:改变元素的位置(left、top...)、显示隐藏元素....
产生重绘的情况:样式改变、换皮肤
重绘和回流

什么是重绘?

样式改变不影响文档流时, background、boder-color、visibility等。

什么是回流?

元素的尺寸、布局、隐藏等改变时候、造成浏览器重新渲染部分DOM或全部DOM的过程。

如何减少回流和重绘?
在css中:
	在dom的最末端改变class
	避免设置多层内联样式
	避免使用table布局
	使用 transfrom、opacity、filter等动画效果不会造成重绘问题
在js中:
	避免一个样式修改完接着下一个样式 (应该一次性改好,或者定义class类)
	避免重复操作dom,(使用文档创建子树,然后拷贝到文档中)
	复杂动画使用绝对定位让其脱离文档流,否则会引起父元素和后续元素大量回流。
	
opacity 和 rgba区别
共同性:实现透明效果

1. opacity 取值范围0到1之间,0表示完全透明,1表示不透明
2. rgba   R表示红色,G表示绿色,B表示蓝色,取值可以在正整数或者百分数。A表示透明度取值0到1之间

区别:继承的区别
opacity会继承父元素的opacity属性,而RGBA设置的元素的后代元素不会继承不透明属性。

1.3 JavaScript基础面试题

延迟加载JS有哪些方式?

延迟加载:async、defer
		例如:
		
defer : 等html全部解析完成,才会执行js代码,顺次执行js脚本。
async : async是和html解析同步的(一起的),不是顺次执行js脚本(谁先加载完谁先执行)。

JS数据类型有哪些?

基本类型:string、number、boolean、undefined、null、symbol、bigint

引用类型:object   (arr、fun是引用类型的小类,也是object)

NaN是一个数值类型,但是不是一个具体的数字。

JS数据类型考题

考题一:
  • 布尔值和num相加 布尔会转换成 1/2

  • 字符串和其他类型相加 另一个都会变为字符串类型

  • typeof(null) 是一个特殊的对象类型

console.log( true + 1 );     			//2
console.log( 'name'+true );  			//nametrue
console.log( undefined + 1 ); 		//NaN
console.log( typeof undefined ); //undefined
考题二:
console.log( typeof(NaN) );       //number
console.log( typeof(null) );      //object
null 和 undefined的区别
1. 作者在设计js的都是先设计的null(为什么设计了null:最初设计js的时候借鉴了java的语言)
2. null会被隐式转换成0,很不容易发现错误。
3. 先有null后有undefined,出来undefined是为了填补之前的坑。

具体区别:JavaScript的最初版本是这样区分的:null是一个表示"无"的对象(空对象指针),转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
=有什么不同?
==  :  比较的是值
		
		string == number || boolean || number ....都会隐式转换
		通过valueOf转换(valueOf() 方法通常由 JavaScript 在后台自动调用,并不显式地出现在代码中。)

=== : 除了比较值,还比较类型

JS微任务和宏任务

就是异步的事件队列里面分为宏任务和微任务。

1. js是单线程的语言。
2. js代码执行流程:同步执行完==》事件循环
	同步的任务都执行完了,才会执行事件循环的内容
	进入事件循环:请求、定时器、事件....

3. 事件循环中包含:【微任务、宏任务】  
宏任务:setTimeout、异步ajax请求、文件操作等
微任务:Promise.then、.catch 和 .finally 


要执行宏任务的前提是清空了所有的微任务

流程:先执行同步的==》再执行事件循环里的微任务和宏任务 ==》微任务==》宏任务=》微任务...

JS作用域考题

1. 除了函数外,js是没有块级作用域。

2. 作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。
	 注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。

3. 注意声明变量是用var还是没有写(window.)
    (function(){
    	var a = b = 10
    })()
    console.log(a)  // 报错
    console.log(b)  // 10  因为b没有被var定义,是全局变量(window.b)
    
4. 注意:js有变量提升的机制【变量悬挂声明】
5. 优先级:声明变量 > 声明普通函数 > 参数 > 变量提升

面试的时候怎么看:

1. 本层作用域有没有此变量【注意变量提升】
2. 注意:js除了函数外没有块级作用域
3. 普通声明函数时不看写函数的时候顺序
考题一:
function c(){
	var b = 1;
	function a(){
		console.log( b );
		var b = 2;
		console.log( b );
	}
	a();
	console.log( b );
}
c();

//	undefind 2 1  注意变量提升
考题二:
var name = 'a';
(function(){
	if( typeof name == 'undefined' ){
		var name = 'b';
		console.log('111'+name);
	}else{
		console.log('222'+name);
	}
})()   

// 222a 错误 js除了函数外没有块级作用域,fun 里面有定义b
// 正确应该是 111b 
考题三:
function fun( a ){
	var a = 10;
	function a(){}
	console.log( a );
}
fun( 100 );  // 10

// 优先级:声明变量 > 声明普通函数 > 参数 > 变量提升

JS对象考题

JS对象注意点:

1. 对象是通过new操作符构建出来的,所以对象之间不相等(除了引用外);
2. 对象注意:引用类型(共同一个地址);
3. 对象的key都是字符串类型;
4. 对象如何找属性|方法;
	查找规则:先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找
考题一:
 [1,2,3] === [1,2,3]   //false
考题二:
var obj1 = {
	a:'hellow'
}
var obj2 = obj1;
obj2.a = 'world';
console.log(obj1); 	//{a:world}
(function(){
	console.log(a); 	//undefined
	var a = 1;
})();
考题三:
var a = {}
var b = {
	key:'a'
}
var c = {
	key:'c'
}

a[b] = '123';  //key 不应该是一个对象,如果是对象会被转换成字符串'object Object '
a[c] = '456';  // 替换[b]

console.log( a[b] ); // 456
 var a = {};
    var b = { key: "a" };
    var c = { key: "c" };
    
    //b要作为属性名先转为字符串,相当于:a[object Object]:="123"
    a[b] = "123";
    //同上,c要作为属性名先转为字符串,相当于:a[object Object]:="456"
    a[c] = "456";

	//上面的a[c] = "456"只是给a[object Object]重新赋值而已。
	//打印a[b]其实就是在打印a[object Object],由于他的最一次的赋值为456。
	//故:
    console.log(a[b]);//456

因为key名称只能是字符串,b/c单做键会调用toString得到的都是[object Object],a[b],a[c]都等价于a["[object Object]"],所以后面的赋值会覆盖前一次操作,打印的时候a[b]也是同理,那不就是更新[object Object]这个键的值了。

JS作用域+this指向+原型的考题

考题一:
function Foo(){
	getName = function(){console.log(1)} //注意是全局的window.
	return this;
}

Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){
	console.log(5)
}

Foo.getName();    //2
getName(); 		  //4

Foo().getName();  //1
getName();		  //1

new Foo().getName();//3
考题二:
var o = {
	a:10,
	b:{
		a:2,
		fn:function(){
			console.log( this.a ); // 2
			console.log( this );   //代表b对象
		}
	}
}
o.b.fn();  // 2 {a:2,fn{}}
考题三:
window.name = 'ByteDance';
function A(){
	this.name = 123;
}
A.prototype.getA = function(){
	console.log( this );
	return this.name + 1;
}
let a = new A();
let funcA = a.getA;
funcA();  //this代表window
考题四:
var length = 10;
function fn(){
	return this.length + 1;
}
var obj = {
	length:5,
	test1:function(){
		return fn();
	}
}
obj.test2 = fn;
console.log( obj.test1() ); 							//1
console.log( fn()===obj.test2() ); 				//false
console.log( obj.test1() == obj.test2() ); //false

JS判断变量是不是数组,你能写出哪些方法?

方式一:isArray
var arr = [1,2,3];
console.log( Array.isArray( arr ) );
方式二:instanceof 【如果网页中使用多个框架会有问题,可能出现不同的数组构造函数】
var arr = [1,2,3];
console.log( arr instanceof Array );
方式三:原型prototype
var arr = [1,2,3];
console.log( Object.prototype.toString.call(arr).indexOf('Array') > -1 );
方式四:isPrototypeOf()
var arr = [1,2,3];
console.log(  Array.prototype.isPrototypeOf(arr) )
方式五:constructor
var arr = [1,2,3];
console.log(  arr.constructor.toString().indexOf('Array') > -1 )

slice是干嘛的、splice是否会改变原数组

1. slice是来截取的
	参数可以写slice(3)、slice(1,3)、slice(-3)
	返回的是一个新的数组
2. splice 功能有:插入、删除、替换
	返回:删除的元素
	该方法会改变原数组

数组排序

arr.sort((n1,n2)=>n1-n2) //正序排序
arr.sort((n1,n2)=>n2-n1)  // 降序排序

Math.max(...arr) // 求最大值
Math.min(...arr) // 求最小值

arr.splice(9, 1);删除后数组中索引9的元素 并返回删除的值

arr.splice(arr.findIndex((e) => e.id === 1), 1)  //数组包含对象

arr.splice(arr.findIndex((e,index) => index === 2), 1) //返回的是删除后的数组

JS数组去重

方式一:new set
var arr1 = [1,2,3,2,4,1];

// new set返回的是一个对象,把它转换成数组,两种方法

console.log(Array.from(new Set(arr1)));

function unique(arr){
	return [...new Set(arr)]
}
console.log(unique(arr1) );
方式二:indexOf
var arr2 = [1,2,3,2,4,1];
function unique( arr ){
	var brr = [];
	for( var i=0;i<arr.length;i++){
		// 等于-1说明没找到
		if(  brr.indexOf(arr[i]) == -1 ){
			brr.push( arr[i] );
		}
	}
	return brr;
}
console.log( unique(arr2) );
方式三:sort
var arr3 = [1,2,3,2,4,1];
function unique( arr ){
	arr = arr.sort();
	var brr = [];
	for(var i=0;i<arr.length;i++){
		if( arr[i] !== arr[i-1]){
			brr.push( arr[i] );
		}
	}
	return brr;
}
console.log( unique(arr3) );

找出多维数组最大值

function fnArr(arr){
	var newArr = [];
	arr.forEach((item,index)=>{
		newArr.push( Math.max(...item)  )
	})
	return newArr;
}
console.log(fnArr([
	[4,5,1,3],
	[13,27,18,26],
	[32,35,37,39],
	[1000,1001,857,1]
]));

给字符串新增方法实现功能

给字符串对象定义一个addPrefix函数,当传入一个字符串str时,它会返回新的带有指定前缀的字符串,例如:

console.log( ‘world’.addPrefix(‘hello’) ) 控制台会输出helloworld

解答:
String.prototype.addPrefix = function(str){
	return str  + this;
}
console.log( 'world'.addPrefix('hello') )

找出字符串出现最多次数的字符以及次数

找出字符串出现次数返回一个对象:

var str = 'abccbaam'
function funique(){
    let obj = {};
    for(let i = 0; i<str.length; i++){
        obj[str[i]] ? obj[str[i]] += 1 : obj[str[i]] = 1
    }
    return obj;
}
console.log(funique(str));

找出字符串出现最多次数的字符以及次数

var str = 'aaabbbbbccddddddddddx';
var obj = {};
for(var i=0;i<str.length;i++){
	var char = str.charAt(i);  //str[i]
	if( obj[char] ){
		obj[char]++;
	}else{
		obj[char] = 1;
	}
}
console.log( obj );

//统计出来最大值
var max = 0;
for( var key in obj ){
	if( max < obj[key] ){
		max = obj[key];
	}
}

//拿最大值去对比
for( var key in obj ){
	if( obj[key] == max ){
		console.log('最多的字符是'+key);
		console.log('出现的次数是'+max);
	}
}

js解析url参数为一个对象

function querUrlparms(url) {
    let obj = {}
    if (url.indexOf('?') < 0) return obj
    let arr = url.split('?')[1].split('&')
    for (let i = 0; i < arr.length; i++) {
        const arr2 = arr[i].split('='); 
        obj[arr2[0]] = arr2[1]    // 组合成键值对的形式
    }
    return obj
}

console.log(querUrlparms('https://www.baidu.com/s?wd=js&rsv_spt=1&rsv_iqid=0xfa41b9e2000013a3&issp=1&f=8&rsv_bp=1&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_dl=tb&rsv_sug3=4&rsv_sug2=0&rsv_btype=i&inputT=397&rsv_sug4=855'));

使用 正则+ …arg

function queryURLparamsRegEs6(url) {
    let obj = {}
    let reg = /([^?=&]+)=([^?=&]+)/g
    url.replace(reg, (...arg) => {
        obj[arg[1]] = arg[2]
    })
    return obj
}

new操作符具体做了什么

1. 创建了一个空的对象
2. 将空对象的原型,指向于构造函数的原型(原型赋值)
3. 将空对象作为构造函数的上下文(改变this指向,指向于新的对象)
4. 对构造函数有返回值的处理判断 (如果构造函数返回基本类型,则构造函数的return无效,返回对象则new操作符无效)
function Fun( age,name ){
	this.age = age;
	this.name = name;
}
function create( fn , ...args ){
	//1. 创建了一个空的对象
	var obj = {}; //var obj = Object.create({})
	//2. 将空对象的原型,指向于构造函数的原型
	Object.setPrototypeOf(obj,fn.prototype);
	//3. 将空对象作为构造函数的上下文(改变this指向)
	var result = fn.apply(obj,args);
	//4. 对构造函数有返回值的处理判断
	return result instanceof Object ? result : obj;
}
console.log( create(Fun,18,'张三')   )

闭包

普通一个函数,执行完后,函数以及内部的变量就被销毁了, 如果在这个函数里面又新建了一个函数,然后在普通函数内调用了外部函数的变量,此时就形成了一个闭包,当函数执行完毕,外部函数不被销毁,造成了变量驻留在内存中,实现了无意的环境共享。

1. 闭包是什么
	闭包的实质是因为函数嵌套而形成的作用域链
	闭包是一个函数加上到创建函数的作用域的连接,闭包“关闭”了函数的自由变量。
	
2. 闭包可以解决什么问题【闭包的优点】  
	2.1 内部函数可以访问到外部函数的局部变量
	2.2 闭包可以解决的问题
	  var lis = document.getElementsByTagName('li');
      for(var i=0;i<lis.length;i++){
        (function(i){
          lis[i].onclick = function(){
            alert(i);
          }
        })(i)
      }
3. 闭包的缺点
	3.1 变量会驻留在内存中,造成内存损耗问题。
				解决:把闭包的函数设置为null
  3.2 内存泄漏【ie】 ==> 可说可不说,如果说一定要提到ie

原型链

1. 什么是原型? 原型可以解决什么问题
	实现 对象属性和方法共享
	
2. 谁有原型
函数拥有:prototype
对象拥有:__proto__

3. 原型链是什么?
	就是把原型串联起来(对象的属性和方法可以在对象本身也可以放在原型中)
	先在对象本身查找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型中 --> 当前原型的原型中查找
	4.2 原型链的最顶端是null(查找到null会返回undefined)
	
原型链的数据结构:
链表结构,通过__proto__指针把每个原型串联起来。

先在对象本身查找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型中 --> 当前原型的原型中查找

function Fun(){
	//this.run = '1' 		-> 2.构造函数中查找
}	
//Fun.prototype.run = '2'   -> 4.构造函数的原型中

var obj = new Fun();

//obj.run = '3';    		-> 1.先在对象本身查找
//obj.__proto__.run = '4'   -> 3. 对象的原型


Object.prototype.run = '5'; // -> 5. 当前原型的原型中查找


console.log( obj.run )
// console.log( Fun.prototype , obj.__proto__ )  
// console.log( obj.__proto__.__proto__.__proto__  ); // null

JS继承有哪些方式

方式一:ES6 的class继承
class Parent{
	constructor(){
		this.age = 18;
	}
}

class Child extends Parent{
	constructor(){
		super();  //虽然语法没问题,但是不加super(),浏览器会报错
		this.name = '张三';
	}
}
let o1 = new Child();
console.log( o1,o1.name,o1.age );
方式二:原型链继承

这里会出现一个问题,类似于浅拷贝,是地址的引用,所有属性和方法都来自于原型,所有new 出来的对象都共用一个方法或属性,改变一个属性值会互相影响.

function Parent(){
	this.age = 20;
}
function Child(){
	this.name = '张三'
}
Child.prototype = new Parent();
let o2 = new Child();
console.log( o2,o2.name,o2.age );
方式三:借用构造函数继承

所有属性和方法都是独立的。

function Parent(){
	this.age = 22;
}
function Child(){
	this.name = '张三'
	Parent.call(this);
}
let o3 = new Child();
console.log( o3,o3.name,o3.age );
方式四:组合式继承

提取了原型继承和借用构造函数继承的优点。不共享的用call,共享的则指向原型。

function Parent(){
	this.age = 100;
}
function Child(){
	Parent.call(this);
	this.name = '张三'
}
Child.prototype = new Parent();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Child.prototype.constructor = Son;
let o4 = new Child();
console.log( o4,o4.name,o4.age );

说一下call、apply、bind区别

共同点:功能一致
可以改变this指向

语法: 函数.call()、函数.apply()、函数.bind()
区别:
1. call、apply可以立即执行。bind不会立即执行,因为bind返回的是一个函数需要加入()执行。
2. 参数不同:apply第二个参数是数组。call和bind有多个参数需要挨个写。
场景:
1. 用apply的情况
var arr1 = [1,2,4,5,7,3,321];
console.log( Math.max.apply(null,arr1) )

2. 用bind的情况
var btn = document.getElementById('btn');
var h1s = document.getElementById('h1s');
btn.onclick = function(){
	console.log( this.id );
}.bind(h1s)

sort背后原理是什么?

V8 引擎 sort 函数只给出了两种排序 InsertionSort 和 QuickSort,数量小于10的数组使用 InsertionSort,比10大的数组则使用 QuickSort。

之前的版本是:插入排序和快排,现在是冒泡

原理实现链接:https://github.com/v8/v8/blob/ad82a40509c5b5b4680d4299c8f08d6c6d31af3c/src/js/array.js

***710行代码开始***

深拷贝和浅拷贝

共同点:复制

1. 浅拷贝:只复制引用,而未复制真正的值。
var arr1 = ['a','b','c','d'];
var arr2 = arr1;

var obj1 = {a:1,b:2}
var obj2 = Object.assign(obj1);

2. 深拷贝:是复制真正的值 (不同引用)
var obj3 = {
	a:1,
	b:2
}
var obj4 = JSON.parse(JSON.stringify( obj3 ));

//递归的形式
function copyObj( obj ){
	Array.isArray(obj) ? var newObj = [] : var newObj = {}
	for( var key in obj ){
		if( typeof obj[key] == 'object' ){
			newObj[key] = copyObj(obj[key]);
		}else{
			newObj[key] = obj[key];
		}
	}
	return newObj;
}
console.log(  copyObj(obj5)  );

localStorage、sessionStorage、cookie的区别

公共点:在客户端存放数据
区别:
1. 数据存放有效期
		sessionStorage : 会话存储,当前窗口关闭后就会删除。
		localStorage   : 持久化存储,始终有效,窗口或者浏览器关闭也一直保存。
		cookie		   : 只在设置的cookie过期时间之前有效,即使窗口或者浏览器关闭也有效。
2. localStorage、sessionStorage不可以设置过期时间
	 cookie 有过期时间,可以设置过期,使用时需要环境(把时间调整到之前的时间,就过期了)
3. 存储大小的限制
	cookie存储量不能超过4k
	localStorage、sessionStorage不能超过5M
	
	****根据不同的浏览器存储的大小是不同的。

1.4 H5/C3面试题

什么是语义化标签
1. 易读性和维护性更好。
2. seo成分会更好,蜘蛛抓取更好。
3. IE8不兼容HTML5标签的。解决:可以通过html5shiv.js去处理。
::before 和 :after中双冒号和单冒号 有什么区别?解释一下这2个伪元素的作用。
1. 区别
	:是伪类、::伪元素  ===》是为了做区分

2.是什么?作用
	元素before之前 、 元素after之后
	作用:清除浮动、样式布局上也有作用
怎么让Chrome支持小于12px 的文字?
Chrome默认字体大小是:16px
**每个浏览器默认字体大小可能都不一样


rem和em区别

相对于font-size

em针对于父元素的font-size
rem针对于根(html)元素的font-size

webkit表单输入框placeholder的颜色值能改变吗?

自适应
淘宝无限适配【移动端】:淘宝无限适配 + 布局单位使用rem
响应式
1. 是什么?
	一个URL可以响应多端
2. 语法结构
	@media only screen and (max-width: 1000px){
		ul li:last-child{
			display: none;
		}
	}

	only : 可以排除不支持媒体查询的浏览器
	screen : 设备类型
	max-width | max-height
	min-width | min-height 
3. 响应式图片【性能优化】
	
		"1.jpg" media='(min-width:1000px)'>
		"2.jpg" media='(min-width:700px)'>
		"3.jpg">
	

布局方案

一、什么情况下采用响应式布局
	
	数据不是特别多,用户量不是特别大,纯展示类的项目适合响应式布局
	
	例如:公司的官网、专题页面
	
	特别追求性能的项目,不太适合响应式,因为如果添加了很多的响应式就会造成加载速度变慢。

二、pc + 移动端应该做什么样的布局方案
	注意:访问量还可以或者比较大,类似于淘宝网。
	
	pc是一套,会加入一点点响应式。
	移动端是一套,会使用自适应的布局方式。

三、pc的设计图

	ui:1980
	笔记本电脑:1280
	ui图的宽度和电脑的宽度不对应该怎么办?
		1. 把ui图进行等比缩放,缩放成和电脑一样的尺寸
		2. 换1980的电脑
		
四、移动端的设计图

	宽度:750
	因为750设计图/2就是375,正好是iphone6的尺寸,我们要把iphone6的尺寸做为基准点。

1.5 移动端页面样式兼容

移动端样式重置

Normalize.css 跨浏览器端样式重置,所有浏览器显示一致。

解决移动端300ms延迟问题

为什么存在300ms延迟?

因为移动端双击屏幕默认会有放大效果,所有存在300ms延迟 (等待点击第二次)。

在移动端使用click事件有300ms延迟的问题 解决方式:

  1. 禁止双击缩放

    // html头部 meta 标签加入:
    mate:user-scalable=no
    
  2. 使用插件 fastclick.js

    // 引入js文件写入代码:
    
    if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); }
    
    
移动端touch事件有穿透(点透)的问题,该怎么解决?

移动端的事件 (touch)

  • touchstart :开始触摸事件

  • touchmove : 手指滑动事件

  • touchend : 触摸结束事件

解决方式:

1、阻止默认行为 e.preventDefault();

2、fastclick.js

// 引入js文件 2.2 写入代码
if ('addEventListener' in document) { document.addEventListener('DOMContentLoaded', function() { FastClick.attach(document.body); }, false); 
ios 样式问题
如何关闭IOS键盘首字母自动大写
"text" autocapitalize='off'>
ios日期转换NAN问题
具体就是,new Date('2020-11-12 00:00:00')  在ios中会为NAN
解决方案:用new Date('2020/11/12 00:00:00') 的日期格式,或者写个正则转换
ios系统中元素被触摸时产生的半透明灰色遮罩怎么去掉

禁止ios长按时触发系统的菜单,禁止ios&android长按时下载图片
禁止ios 长按时触发系统的菜单,禁止ios&android长按时下载图片
html,body{
	touch-callout: none;
	-webkit-touch-callout: none;
	
	user-select:none;
	-webkit-user-select:none;
}
禁止ios和android用户选中文字
html,body{
	user-select:none;
	-webkit-user-select:none;
}
安卓部分版本input的placeholder偏上
input{
	line-height:normal;
}

ES6面试题

ES6用过那些:

let const
解构赋值、模板字符串、箭头函数、promise、async await 、class、函数默认值
拓展运算符(...name)
map&set数据结构、模块化语法

数组方法:
map 如果想要返回一个数组
reduce 如果需要一个结果,比如累加求和
find 找到后立即返回满足条件的第一个值
findindex 返回索引

map&set数据结构 map有key和value  set只有value(不允许值重复)


filter 过滤一个结果是否存在(可以为空,所以需要判断) Es5
var、let、const区别
varletconst 共同点都是可以声明变量的

区别一:
	var 具有变量提升的机制
	letconst没有变量提升的机制
区别二:
	var 可以多次声明同一个变量
	letconst不可以多次声明同一个变量
区别三:
	varlet声明变量的
	const声明常量
	
	varlet声明的变量可以再次赋值,但是const不可以再次赋值了。
区别四:
	var声明的变量没有自身作用域
	letconst声明的变量有自身的作用域
作用域考题

考题一:let和const没有变量提升性

console.log( str );//undefined
var str = '你好';

console.log( num );//报错
let num = 10;

考题二:

function demo(){
	var n = 2;
	if( true ){
		var n = 1;
	}
	console.log( n );//1
}
demo();


function demo(){
	let n = 2;
	if( true ){
		let n = 1;
	}
	console.log( n );//2
}
demo();

考题三:可以修改

const obj = {
	a:1
}
obj.a = 11111;
console.log( obj )

const arr = ['a','b','c'];
arr[0]= 'aaaaa';
console.log( arr );
将下列对象进行合并

方式一:Object.assign

const a = {a:1,b:4};
const b = {b:2,c:3};

let obj1 = Object.assign(a,b);
console.log( obj1 );

方式二:…

let obj2 = {...a,...b};
console.log( obj2 );

方式三:自己封装方法

function extend( target,  source ){
	for(var key in source){
		target[key] = source[key];
	}
	return target;
}
console.log( extend(a,b) );
箭头函数和普通函数有什么区别?
1. this指向的问题
	箭头函数中的this只在箭头函数定义时就决定的,	
	箭头函数继承来的this指向不会改变(call、apply、bind无效)
	
	箭头函数不能作为构造函数
	没有arguments、prototype
	
(call、apply、bind)
	****箭头函数的this定义时候、指向外层第一个普通函数的this
	
2. 箭头函数不能new(不能当作构造函数)
3. 箭头函数prototype
4. 箭头函数arguments
Promise有几种状态
有三种状态:
pending(进行中)
fulfilled(已成功)
rejected(已失败)
find和filter的区别
区别一:返回的内容不同
	filter 返回是新数组
	find   返回具体的内容
区别二:
	find :匹配到第一个即返回
	filter : 返回整体(没一个匹配到的都返回)
some和every的区别
some  ==》 如果有一项匹配则返回true
every ==》 全部匹配才会返回true
for in 和 for of 的区别?
for..in    用于循环可迭代对象,虽然可以用于字符串和数组,但不建议。

for...of   用于用于循环字符串或数组

第三章 Vue

Vue 基础

介绍一下SPA以及SPA有什么缺点?
SPA是什么?单页面应用
缺点:
	1. SEO优化不好
	2. 性能不是特别好
	3. 首次加载慢
	
多页面SEO比单页面SEO好 (方便蜘蛛抓取),收入得多。

讲一下MVVM

把一个大的网页拆分成多个组件。


在vue中我们通过插值表达式渲染页面数据,M就是这个data(model层),v就是这个展示的数据即(view视图层)。

MV 就是数据展示到页面过程,这个时候是单向的
VM就是理解为v-model原理实现,通过视图去更新数据
双向绑定原理

什么是响应式数据? 视图发生修改data中的数据也发生修改。

vue数据双向绑定原理通过`数据劫持`结合`发布订阅模式`的方式来实现的。
核心就是使用 Object.defineProperty()劫持数据 的 getset 监听数据的变化

首先我们要有一个`数据监听器`,用来劫持并监听所有属性,如果改变,就通知订阅者Watcher。
然后还需要一个`指令解析器`,她用于节点遍历和重新渲染以及绑定相应的更新函数。
还要实现一个`订阅者Watcher`,作为数据监听器和指令解析器的桥梁,数据变化时执行相应函数,从而更新视图。

在使用vue时候,明显能体验到一个点: 数据是在data中定义的,然后能直接通过this.xx获取数据,而且一个修改数据就会互相通知跟着一起改变。所以这里一定不是通过直接赋值和深浅拷贝实现的,而通知的实现就是通过Object.defineProperty()里的get和set方法,监控是获取还是修改。

什么是虚拟DOM
其实就是数据,把dom变成数据结构。
vue的优缺点:

优点:

响应式、组件化、插件化、
响应式 MVVM 一个大网页可以拆分成多个组件合并成一个大的,利于维护。
只要整理好数据结构,通过数据驱动DOM

缺点:

原理还是DOM操作,只是vue有数据驱动, 初次加载耗时多,而且可能会造成重绘,性能没前后端不分离好。
由于是单页面应用,不能使用浏览器前进后退功能,所有页面切换切换需要自己建立管理栈。
因为是数据驱动,所以页面源码中很少有内容,所以不利于seo。
v-if和v-show区别
1. 展示形式不同
v-if是 创建一个dom节点
v-show 是display:none 、 block

2. 使用场景不同
初次加载v-if要比v-show好,页面不会做加载盒子
频繁切换v-show要比v-if好,创建和删除的开销太大了,显示和隐藏开销较小
v-if和v-for优先级
v-for的优先级要比v-if高
***是在源码中体现的:function genElement
ref是什么?
来获取dom的
nextTick是什么?
获取更新后的dom内容
scoped原理
1. 作用:让样式在本组件中生效,不影响其他组件。
2. 原理:给节点新增自定义属性,然后css根据属性选择器添加样式。
Vue中如何做样式穿透
stylus样式穿透使用:>>>
sass和less使用:/deep/
通用使用:  :v-deep
Vue组件传值
父组件-->子组件:

	1. 父组件:
		
    
    export default {
        components: {
            UserDetail
        }
        ......
    }
  2. 在子组件中使用props(可以是数组也可以是对象)接收即可。可以传多个属性。
  	export default {
      props: ['myName']
 		}

子组件-->父组件:

		1. 子组件
      
      export default {
          methods: {
              //子组件的事件
              changeParentName: function() {
                  this.$emit('handleChange', 'Jack')
              }
          }
      }
    2. 父组件
      

      methods: {
          changeName(name) {  
              this.name = name
          }
      }

兄弟组件之间:bus.js
props和data优先级谁高?
props ===>  methods ===> data ===> computed ===>watch
computed、methods、watch有什么区别?

相同点: 都可以对data数据进行二次修改。

执行问题:computed有缓存,只会执行一次,以后都会走缓存,methods无缓存,所以每次调用都会重新执行。

  • computed 计算属性
  • methods 存放方法的
  • watch 监听数据变化
1. computed 、methods区别
	如果在值不修改的情况下,computed有缓存,methods无缓存
	computed应用场景: 例如计算价格时需要在页面多次展示,它执行一次,剩下n次走缓存。而使用methods会被执行多次。
	
2. computed vs watch区别
    watch 在不做任何的配置,数据不改变的情况下,进入组件是不会直接执行的。
	watch可以深度监听,可以监听数据、路由的变化 数据或者路由发生了改变才可以响应(执行)
	
	computed计算某一个属性的改变,如果某一个值改变了,计算属性会监听到进行返回,
	如果涉及到多值可能修改的情况,使用computed是最好的,watch是需要监听多个值太麻烦了。

你有碰到或点击按钮后页面数据不更新的问题吗,怎么解决?
<template>
  <div >
    {{ obj }}
    <button @click="btnShow">点击更新obj</button>    
  </div>
</template>

<script>
export default {
  data() {
    return {
      obj: { a: '你好啊',b: '2022'}
    }
  },
  methods: {
    btnShow() {
      // this.obj.c = 'fsdfsd' //这样写发现点击无法更新页面数据
      this.$set(this.o, 'c', 'liaoyi')  // 使用$set 可以完美解决 (点击就可以更新了)
    }
  }
}
</script>

Vue2.x 生命周期

生命周期:组件从创建到销毁的一个过程,4个阶段:创建、挂载、更新、销毁。

vue的功能都是围绕生命周期进行的,在周期不同的阶段调用对应的钩子函数,实现组件数据的管理和DOM的渲染

4461

1. 有哪些生命周期

系统自带:
创建前后:
  beforeCreate    → 可以加loading事件
  created      → 发起异步请求、结束loading事件      
挂载前后:
  beforeMount
  mounted     → 操作DOM、发送请求
更新前后:  
  beforeUpdate   → 可以在这里访问dom,删除一些事件监听器
  updated
销毁前后:  
  beforeDestroy   销毁前,删除一些提示
  destroyed
  
2. 一旦进入到页面或者组件,会执行哪些生命周期,顺序。
 beforeCreate、created、beforeMount、mounted
 
3. 在哪个阶段有$el,在哪个阶段有$data
	beforeCreate 啥也没有
	created  有data没有el
	beforeMount 有data没有el
	mounted 都有
	
4. 如果加入了keep-alive会多俩个生命周期
	activated、deactivated
	
5. 如果加入了keep-alive,第一次进入组件会执行哪些生命?

  第一次:
		beforeCreate
		created
		beforeMount
		mounted
		activated 

6. 如果加入了keep-alive,第二次或者第N次进入组件会执行哪些生命周期?
   只执行一个生命周期: 第二次或第N次  
        activated
你在什么情况下用过哪些生命周期?

项目中使用最多的就是 createdmounted

created ==》 请求接口 (因为有data没有el,mounted会造成重绘或回流)
mounted ==》 获取DOM(做效果,获取dom的高度,用插件)

其他问题:链接:https://pan.baidu.com/s/1Uo-jUGyxBlYDwjRadtnBWQ 密码:tr5c

谈谈你对keep-alive的了解
1. 是什么
vue系统自带的一个组件,功能:是来缓存组件的。===》提升性能
2. 使用场景
就是来缓存组件,提升项目的性能。具体实现比如:首页进入到详情页,如果用户在首页每次点击都是相同的,那么详情页就没必要请求N次了,直接缓存起来就可以了,当然如果点击的不是同一个,那么就直接请求。

vue-router

路由模式:

history  http://localhost:8080/mine
hash     http://localhost:8080#/mine

1. 样式不同

2. 请求 
	如果在找不到对应这个路由的情况下 (比如在链接后面随便输入了东西, 解决:可以配置404页面)
	history会发送一次get请求、hash不会发送

3.打包后前端环境自测
	history无内容(空白页),hash有内容。
路由跳转
push 跳转并新增一条历史记录
replace 替换掉当前页面,并替换掉当前的历史记录
go(n)  浏览历史中前进和后退
back() 后退到上一个页面
forward() 前进到下一个页面
路由传值
有两种传值方式: 一个是通过query显示传值, 一个是通过参数params隐式传值。
因为使用隐式传值跳转刷新界面后参数问题无法解决,所以路径传值一定是显示的。
1. 显式  ==> 参数在url上

	http://localhost:8080/about?a=1
  传:this.$router.push({
  			path:'/about',
  			query:{
  				a:1
  			}
  		})
  接:this.$route.query.a
  
2. 隐式  ==> 参数不在url上

	http://localhost:8080/about
	传:this.$router.push({
  			name:'About',  //传name
  			params:{
  				a:1
  			}
  		})
    接:this.$route.params.a

路由导航守卫

全局、路由独享、组件内
1. 全局
	beforeEach、beforeResolve、afterEach
    
2. 路由独享
	beforeEnter   在路由vue-router配置的路由单独设置  beforeEnter(){}

3. 组件内  - 不好维护,一般不用
	beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

    使用场景:判断是否登录,如果登录就next否则就跳转到登录页面
子路由、路由嵌套、动态路由
子路由: 好维护,不用一直新建一级路由
动态路由: 值路由很多(999+),这时候使用动态路由方便

比如商城的商品点击详情页数据的渲染 -> 首页传id,详情页接收id,在请求id

使用动态路由: http://localhost:8080/detail/123323?*** 首页传id,

不使用动态路由: http://localhost:8080/detail

Vuex

什么时候用vuex,什么时候用 modules ?

什么时候用vuex?

1. 传值复杂
2. 数据多,需要更好的去管理数据(方便,项目好维护)

什么时候用 modules?
modules是为了把项目再次细分,方便后期维护
【例如:商城项目有很多state】, 购物车,我的,订单管理,地址管理...为了更好的维护和管理,采用modules
Vuex有哪些属性?
state、getters、mutations、actions、modules

state      存放数据,类似于组件的data
getters    计算属性,类似于组件的computed
mutations  存放方法,类似于组件的methods

actions    存放方法,用于提交mutations,不建议是直接在actions中写入方法,actions可以包含异步操作(这个是mutaitons做不了的)

modules    把以上4个属性再细分,让仓库更好管理
Vuex是单向数据流还是双向数据流?
Vuex是单向数据流 不能直接修改vuex的数据,只能在mutaitons中更改。
组件使用vuex数据直接修改会报错,那么mutations不会报错为什么?
因为是vuex是单向数据流
Vuex中的mutaitons和actions区别
mutaitons   :  必须是同步函数
actions     :  可以包含任意异步操作

使用的时候,方法就写在mutations中(逻辑)。
actions是来提交mutaitons的,不建议直接在actions里面写

Vuex如何做持久化存储

如果在组件修改了vuex的数据,刷新页面为什么会到之前没有修改过的值?

因为Vuex本身不是持久化存储:

1. 使用localStorage、  自己写
       cookie 但是cookie需要环境,指向域名或ip地址。
       
2. 使用vuex-persist 插件( 这个插件的原理也是localStorage)
vuex 存储的数据虽然是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。

配置和打包上线

vue打包成多页面使用插件  : prerender-spa-plugin

项目打包时遇到的问题:

***打包出现空白页
解决:1. 打包后路径问题 : (run build)默认在电脑的根目录查找

			module.exports = {
				  publicPath:'./',  //改为当前根目录
			}
			
 	 2. 内容不显示【路由问题】路由切换无法加载

		这时候前端想要正常切换页面,路由模式修改成hash模式即可(#)
       【后端】打包后如果要是history模式,需要后端做重定向

	 3. 如果是代理请求的数据,打包后不生效
你有没有配置过代理 ?
vue中的代理是来解决跨域的问题的!
注意:代理在生产环境不生效(axios的url写的是什么,就是什么,不用代理的前缀)
解决开发前配置了代理 打包后不生效问题

在项目根目录 新建 .env.development.env.production配置文件

​ .env.development ==>开发环境

# 页面标题
VUE_APP_TITLE = 开发环境
# 开发环境配置
VUE_APP_ENV = 'development'
# 开发环境代理
VUE_APP_BASE_API = 'http://localhost:3000'

​ .env.production ===>生产环境

# 页面标题
VUE_APP_TITLE = 生产环境
# 生产环境配置
VUE_APP_ENV = 'production'
# 生产环境代理
VUE_APP_BASE_API = 'http://localhost:3000'

开发和打包的时候会vue自动找这个配置文件。

前端面试题总结-初级_第1张图片

后台搭建和跨域解决

一、搭建后端目录

全局命令:npm install express-generator -g
进入项目目录:express --view=ejs server

二、node — express 跨域

router.all('*', function (req, res, next) {
  res.header('Access-Control-Allow-Origin', '*');
  res.header('Access-Control-Allow-Headers', 'Content-Type');
  res.header('Access-Control-Allow-Methods', '*');
  res.header('Content-Type', 'application/json;charset=utf-8');
  next();
});

微信小程序面试题

如何自定义头部?
app.json进行配置

"window":{
    "navigationStyle":"custom",
}
如何自定义底部?
不校验URL
工具==》详情==》本地设置==》不校验合法域名  : 项目上线前URL一定要请求到(不勾选也可以请求到数据)

uni-app面试题

生命周期
应用生命周期、页面生命周期、组件生命周期
条件编译
在工具中,打if出现的条件编译

例如:

  	

这是h5端

性能优化篇

加载优化
1. http请求
	 能不能减少(能不能合并)
2. 图片的雪碧图
3. script标签位置
4. link标签(css引入)
图片优化
1. 图片懒加载
2. 响应式图片 (如果是开发响应式网站)
3. webp代替其他格式
4. 小图标可以改用字体图标
渲染优化
1. 减少重绘和回流
2. 改变位置使用transform
3. 动画尽量用requestAnimationFrame,不要用定时器
首屏优化
计算首屏加载时间: 
(performance.timing,domComplete  - performance.timing.navigationStart) / 1000
1. 长列表 (1000条数据,如何展示到页面上)
2. 项目的html文件、css文件、图片、js文件压缩打包
vue优化
1. keep-alive 缓存组件
2. 路由懒加载
3. 方法的正确使用
	v-if和v-show
	computed、watch、methods
	v-for循环的时候,尽量别用index,而是用id
4. Object.freeze :冻结对象
	纯展示类的接口数据,冻结就可以了
5. 使用ui组件按需引入

webpack面试题

webpack是一个模块打包工具,用于管理项目模块依赖,并编译出所需的静态资源。

功能:

 代码转换: ts编译成js,scss编译成css
 文件优化: 压缩代码、图片
 代码分割: 提取多页面的公共代码,比如提取首页不需要执行部分的代码让它异步加载。
 代码校验、自动发布。
file/ css/ style / less / ts / babel-loader
mini-css-extaact-plugin  提取css为单独文件
clean-webpack-plugin  目录清理
copy-webpack-plugin   拷贝文件
webpack-bundle-analyzer 可视化输出打包后各文件大小

Git面试题

分布式代码托管平台

分布式:大家可以提交代码, (本地也有暂存区,即使断网了也可以运行git add . 和 git commit先提交到本地)。

git常用命令
git init 		初始化仓库(生成.git文件夹--隐藏文件夹)
git config -l   查看配置 (配置的用户名,邮箱、可以用来追溯是谁提交的代码)
git status      查看状态 (标记为红色说明文件没有被git管理,需要把文件添加到暂存区,绿色说明已被管理)

git add .  把当前项目所有文件添加到暂存区   (让git接管当前项目的文件)
git add index.js 指定文件上传到暂存区

git diff   查看修改的文件 
git log    查看修改历史(详细输出,谁修改的,几点修改,以及提交时间)
git reflog 查看修改历史(简单输出,只输出提交了几次和修改的文件)

回到之前的版本:
git reset --hard HEAD^
git reset --hard 版本号 回到指定版本 ( 执行git reflog 最开头的[f781dee] 就是版本号)


git commit -m '备注内容' 添加到分支中 (默认添加到master主分支)
git push 推送到云端


分支的操作:

 ***默认的主分支 : master 
 
git branch            (查看本地分支)
git branch 分支名称    (新建分支)
git checkout 分支名称  (切换分支) 

如何查看远程仓库的分支 
 git branch -r 
 git push --set-upstream origin 分支名称   (本地分支提交到远程仓库) 
 git branch -d 分支名称   (删除本地分支)

如何删除远程仓库的分支 
git push origin --delete 分支名称
解决冲突
git push为什么报错?
如果远程仓库有人更新了代码,那我们不能直接 git push
解决: 必须先拉取远程仓库的代码(执行 git pull ),然后再push

但是,有的时候还是会出现问题,多人同时修改了一个文件,导致代码冲突,后一个人提交时报错:

前端面试题总结-初级_第2张图片

后提交的人解决问题:手动解决冲突代码,协商保留或者删除。

工作中应该写一个模块就提交,避免自己碰到代码冲突!。

跨域面试题

前端:会碰到jsonp跨域问题、vue的项目可以设置代理(打包后无效。解决:.ENV文件)
后端:CORS

http和https的区别?

1. 端口不同
	http :80端口
	https :443端口
	
2. https比http更加安全

	***https就是证书

token

token是后端生成的

token + cookie  			: 前端判断是否过期
token + localStorage        : 后端判断是否过期给前端返回code码,前端判断code码等于多少

SEO - 搜索引擎优化

1. 网站一定要多页面
2. title、描述、关键字
3. 图片、音频、视频、的标签属性特别关键
4. 网站不能出现死链接

前端常用工具库:

nanoid 生成唯一标识

nanoid库和uuid库一样都可以生成uuid,但是nanoid相比uuid要更轻量级。

npm i nanoid -S
import {nanoid} from 'nanoid'
直接调用nanoid(),即可生成一个uuid

Vue-Lazyload 图片懒加载

图片懒加载,添加自定义指令。

cnpm i vue-lazyload -S
import VueLazyload from 'vue-lazyload'

// 传入一个配置对象,设置懒加载默认的 loading图片
Vue.use(VueLazyload, {
  loading: require('@/assets/images/loding.gif'), 
})

在组件中使用:
:src 替换成 v-lazy 即可

vee-validate 表单验证插件

下载:高版本问题太多,建议下载指定版本

cnpm i vee-validate@2  -S

使用插件:

避免 main.js 杂乱,我们在src目录新建 plugins/validate.js 文件

在mian.js引入:

import "@/plugins/validate"; //引入表单校验插件

编写 validate.js 文件:


import Vue from "vue";
import VeeValidate from "vee-validate";
import zh_CN from "vee-validate/dist/locale/zh_CN"; //中文提示信息
Vue.use(VeeValidate);

// 表单验证和设置提示信息
VeeValidate.Validator.localize('zh_CN', {
    messages: {
        ...zh_CN.messages,
        is: (field) => `${field}必须与密码相同` // 修改内置规则的 message,让确认密码和密码相同
    },
    attributes: { // 给校验的 field 属性名映射中文名称
        phone: '手机号',
        code: '验证码',
        password:'密码',
        password1:'确认密码',
        isCheck:'协议'
    }
})

//自定义校验规则 (协议必须打勾同意)
VeeValidate.Validator.extend('agree', {
    validate: value => {
        return value
    },
    getMessage: field => field + '必须同意'
})

在组件中使用


第三步:基本使用

{{ errors.first("phone") }}

点击按钮提交:

const success = await this.$validator.validateAll(); //保证全部表单验证成功后才发请求

你可能感兴趣的:(Vue,前端,http,https,vue.js,面试)