前端面试题,整理,自用

1:你是怎么理解 HTML 标签语义化

HTML 语义化简单来说就是用正确的标签来做正确的事。
比如表示段落用 p 标签、表示标题用 h1-h6 标签、表示文章就用 article 等。

2:行内元素、块级元素、 空元素有那些?

1) CSS规定,每个元素都有display属性,确定该元素的类型,每个元素都有默认的display值,比如 div 默认 display属性值为“block”,成为“块级元素”;span默认display属性值为“inline”,是“行内”元素。
2) 行内元素有:a ,b , span, img, input, select, strong,
3) 块级元素有:div , ul, ol, li, dl, dt, dd, h1, h2, h3, h4, h5, h6, p
4)知名的空标签:hr, br, img, input, link, meta
5)可以通过 display 修改 inline-block, block, inline

3:介绍一下H5的新特性

1)语义化标签, header, footer, nav, aside,article,section
2)增强型表单
3)视频 video 和音频 audio
4)Canvas 绘图
5)SVG绘图
6)地理定位
7)拖放 API
8)WebWorker
9)WebStorage( 本地离线存储 localStorage、sessionStorage )
10)WebSocket

4:css3新特征

1、圆角效果;2、图形化边界;3、块阴影与文字阴影;4、使用 RGBA 实现透明效果;5、渐变效果;6、使用“@Font-Face”实现定制字体;7、多背景图;8、文字或图像的变形处理;9、多栏布局;10、媒体查询等。
1、颜色:新增RGBA、HSLA模式
2、文字阴影:(text-shadow)
3、边框:圆角(border-radius)边框阴影:box-shadow
4、盒子模型:box-sizing
5、背景:background-size,background-origin background-clip(削弱)
6、渐变:linear-gradient(线性渐变):
eg: background-image: linear-gradient(100deg, #237b9f, #f2febd);
radial-gradient (径向渐变)
7、过渡:transition可实现动画
8、自定义动画: animate@keyfrom
9、媒体查询:多栏布局@media screen and (width:800px)
10、border-image
11、2D转换:transform:translate(x,y) rotate(x,y)旋转 skew(x,y)倾斜 scale(x,y)缩放
12、3D转换
13、字体图标:Font-Face
14、弹性布局:flex

5:css 选择器

id 选择器( #myid)
类选择器(.myclassname)
标签选择器(div, h1, p)相邻选择器(h1 + p)
子选择器(ul > li)后代选择器(li a)
属性选择器(a[rel = “external”])
伪类选择器(a: hover, li:nth-child)
通配符选择器( * )
!Important > 行内式 > id > 类/伪类/属性 > 标签选择器 > 全局
(对应权重:无穷大∞ > 1000> 100 > 10 > 1 > 0)

6:盒模型

一个盒子,会用 content,padding,border,margin 四部分,
标准的盒模型的宽高指的是 content 部分
ie 的盒模型的宽高包括了 content+padding+border
我们可以通过 box-sizing 修改盒模型,box-sizing border-box content-box

7:margin 合并 与 margin 塌陷

margin 合并
在垂直方向上的两个盒子,他们的 margin 会发生合并(会取最大的值),比如上边盒子设置margin-bottom:20px,下边盒子设置margin-top:30px;,那么两个盒子间的间距只有30px,不会是50px
解决 margin 合并,我们可以给其中一个盒子套上一个父盒子,给父盒子设置 BFC

margin 塌陷
效果: 一个父盒子中有一个子盒子,我们给子盒子设置margin-top:xxpx结果发现会带着父盒子一起移动(就效果和父盒子设置margin-top:xxpx的效果一样)
解决: 1、给父盒子设置 border,例如设置border:1px solid red; 2、给父盒子设置 BFC

8:什么是rem、px、em区别

rem是一个相对单位,rem的是相对于html元素的字体大小,没有继承性
em是一个相对单位,是相对于父元素字体大小有继承性
px是一个“绝对单位”,就是css中定义的像素,利用px设置字体大小及元素的宽高等,比较稳定和精确。

9:响应式布局有哪些实现方式?什么是响应式设计?响应式设计的基本原理是什么?

1.百分比布局,但是无法对字体,边框等比例缩放
2.弹性盒子布局 display:flex
3.rem布局,1rem=html的font-size值的大小
css3媒体查询 @media screen and(max-width: 750px){}
5.vw+vh
6.使用一些框架(bootstrap,vant)
什么是响应式设计:响应式网站设计是一个网站能够兼容多个终端,智能地根据不同设备环境进行相对应的布局
响应式设计的基本原理:基本原理是通过媒体查询检测不同的设备屏幕尺寸设置不同的css样式 页面头部必须有meta声明的

10:水平垂直居中

11:DOM 事件机制/模型

DOM0 级模型、IE 事件模型、DOM2 级事件模型

window.addEventListener(
  "click",
  function (event) {
    event = event || window.event /*ie*/;

    const target = event.target || event.srcElement; /*ie*/ // 拿到事件目标
    
    // 阻止冒泡
    // event.stopPropagation()
    // event.cancelBubble=true; // ie
    
    // 阻止默认事件
    // event.preventDefault();
    // event.returnValue=false; // ie
  },
  /* 是否使用捕获,默认是fasle, */ fasle
);

在这里插入图片描述

12:事件委托

简介:事件委托指的是,不在事件的发生地(直接 dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的
触发,通过判断事件发生元素 DOM 的类型,来做出不同的响应。
举例:最经典的就是 ul 和 li 标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在 li 标签上直接添加,而是在 ul 父元素上添加。
好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制

13:link和@inport的区别

①:从属关系区别
link是HTML提供的标签,不仅可以加载CSS文件,还可以定义RSS、rel连接属性等
@import 是CSS提供的语法规则,只能加载CSS
②:加载顺序的区别
link标签引入的CSS会在网页加载的时候同时加载
@import只能等页面加载完毕后被加载
③:兼容性区别
link标签作为HTML元素,不存在兼容问题
@import是CSS2.1才有的语法,只有IE5以上才能够识别
④:DOM可操作性的区别
link标签引入的样式可以通过JS操作DOM去改变样式
由于DOM是基于文档的,无法使用@import的方式插入样式

14:常见的浏览器兼容问题

第一类:块状元素 float后,又添加横向的margin值,在 IE6下比设置的值要大(属于双倍浮动的 bug)
解决方案:给 float标签添加display:inline,将其转化为行内元素
第二类:表单元素行高不一致
解决方案:给表单元素添加 float:left(左浮动);或者是 vertical-align:middle(垂直对齐方式:居中)
第三类:图片默认有间隙
解决方案:1)给 img标签添加左浮动
2)给 img标签添加 display:block;
第四类:设置较小高度的容器(小于10px),在 IE6,IE7中超出自己设置的高度
解决方案:给容器添加 overflow:hidden;
第五类:不同浏览器的标签默认的margin和padding值不一样
解决方案:通配符 *{margin:0;padding:0}
第六类:鼠标指针,cursor:hand;只有ie浏览器识别,其他浏览器不识别
解决方案:cursor:pointer;IE6以上浏览器及其他内核浏览器都识别;
第七类:获取自定义属性
解决方案:统一使用getAttribute获取属性
第八类:被点击过后的超链接不再具有hover和active属性
解决办法:按lvha的顺序书写css样式,
“a:link”: a标签还未被访问的状态;
“a:visited”: a标签已被访问过的状态;
“a:hover”: 鼠标悬停在a标签上的状态;
“a:active”: a标签被鼠标按着时的状态;

15:什么是媒体查询

媒体查询是CSS3新语法。
使用媒体查询,可以针对不同的媒体类型定义不同的样式
媒体查询可以针对不同的屏幕尺寸设置不同的样式
当你重置浏览器大小的过程中,页面也会根据浏览器的宽度和高度重新渲染页面
目前针对很多苹果手机、Android手机,平板等设备都用得到多媒体查询

15:JS 八种数据类型

Number String Boolean undefined null Object Symbol BigInt

16:闭包

闭包是指有权访问另一个函数作用域中的变量的函数 ——《JavaScript 高级程序设计》
当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行 ——《你不知道的 JavaScript》
1)闭包用途:
能够访问函数定义时所在的词法作用域(阻止其被回收)
私有化变量
模拟块级作用域
创建模块
2)闭包缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏

17:原型、原型链

原型: 对象中固有的__proto__属性,该属性指向对象的prototype原型属性。
原型链: 当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是Object.prototype所以这就是我们新建的对象为什么能够使用toString()等方法的原因。
特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。

18:this 指向、new 关键字

this对象是是执行上下文中的一个属性,它指向最后一次调用这个方法的对象,在全局函数中,this等于window,而当函数被作为某个对象调用时,this 等于那个对象。 在实际开发中,this的指向可以通过四种调用模式来判断。
1:函数调用,当一个函数不是一个对象的属性时,直接作为函数来调用时,this指向全局对象。
2:方法调用,如果一个函数作为一个对象的方法来调用时,this指向这个对象。
3:构造函数调用,this指向这个用new新创建的对象。
4:第四种是 apply 、 call 和 bind调用模式,这三个方法都可以显示的指定调用函数的 this 指向。apply接收参数的是数组,call接受参数列表,`` bind方法通过传入一个对象,返回一个this绑定了传入对象的新函数。这个函数的this指向除了使用new `时会被改变,其他情况下都不会改变。

19:websocket和ajax的区别

本质不同
Ajax,即异步JavaScript和XML,是一种创建交互式网页应用的网页开发技术;
WebSocket是HTML5一种新的协议,实现了浏览器与服务器全双工通信。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接,服务端与客户端通过此TCP连接进行实时通信。
生命周期不同
websocket建立的是长连接,在一个会话中一直保持连接;而ajax是短连接,数据发送和接受完成后就会断开连接
适用范围不同
websocket一般用于前后端实时数据交互,而ajax前后端非实时数据交互。
发起人不同
Ajax技术需要客户端发起请求(自己请求回来的数据用户自己看),而WebSocket服务器和客户端可以相互推送信息。(用户A请求返回来的东西A用户可以看B用户也可以看;如果是属于公共的那大家都可以看
用法不同

ajax:

$.ajax(
  {
	type:"post",
	url:"http://localhost:8080/target",
	data:"state = yes",
	dataType:"json",
	success:funciont(data){
	}
});

websocket:

var monitor = new WebSocket("ws://"+ip+path)
onOpen()、onMessage()、onClose()

19:继承

function Animal(name) {
  // 属性
  this.name = name || "Animal";
  // 实例方法
  this.sleep = function () {
    console.log(this.name + "正在睡觉!");
  };
}
// 原型方法
Animal.prototype.eat = function (food) {
  console.log(this.name + "正在吃:" + food);
};

(1)第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。

// 原型链继承
function Cat() {}
Cat.prototype = new Animal("小黄"); // 缺点 无法实现多继承 来自原型对象的所有属性被所有实例共享
Cat.prototype.name = "cat";

(2)第二种方式是使用借用构造函数的方式,这种方式是通过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。

// 借用构造函数继承
function Cat() {
  Animal.call(this, "小黄");
  // 缺点 只能继承父类实例的属性和方法,不能继承原型上的属性和方法。
}

3)第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。
(4)第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。

function object(o){
	function F(){}
	F.prototype = o;
	return new F();
}

(5)第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是我们的自定义类型时。缺点是没有办法实现函数的复用。

function createAnother(original){
	var clone = object(original);//通过调用object函数创建一个新对象
	clone.sayHi = function(){//以某种方式来增强这个对象
		alert("hi");
	};
	return clone;//返回这个对象
}

(6)第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。

function extend(subClass,superClass){
	var prototype = object(superClass.prototype);//创建对象
	prototype.constructor = subClass;//增强对象
	subClass.prototype = prototype;//指定对象
}

20:Object.is()与比较操作符=====的区别?

==会先进行类型转换再比较
===比较时不会进行类型转换,类型不同则直接返回 false
Object.is()在===基础上特别处理了NaN,-0,+0,保证-0 与+0 不相等,但 NaN 与 NaN 相等

21:对ES6总结

1)新增 Symbol 类型 表示独一无二的值,用来定义独一无二的对象属性名;
2)const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,不存在变量提升。(const 一般用于声明常量);
3)变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(…rest);
4)模板字符串(${data});
5)…扩展运算符(数组、对象);;
6)箭头函数;
7)Set 和 Map 数据结构;
8)Proxy/Reflect;
9)Promise;
10)async 函数;
11)1Class;
12)Module 语法(import/export)。

22:cookie、sessionStorage、localStorage

①:cookie数据始终在同源的http请求中携带(即使不需要),也就是说cookie在浏览器和服务器之间来回传递;而sessionStorage与localStorage不会自动把数据发送给服务器,仅在本地存储;cookie数据还有路径(path)的概念,可限制cookie只属于某个路径下
②:存储大小限制不同
cookie数据大小不超过4Kb;而另外两种虽然也有存储大小限制,但是比cookie大的多,可达5Mb或者更多
③:数据有效期不同
Cookie 在设置的cookie过期之前之前一直有效,及时浏览器窗口关闭
localStorage 存储持久数据,浏览器关闭后数据不丢失除非手动删除
sessionStorage 数据在浏览器关闭后会自动删除
④:作用域不同
sessionStorage 不在不同的浏览器窗口中共享,即使是同一个页面
Cookie 和 localStorage 在所有的同源页面中都是共享的
⑤:web Storage支持事件通知机制,可以将数据更新的通知发送给监听者
⑥:web Storage的api接口使用更方便

23:require与import的区别和使用

1、import是ES6中的语法标准也是用来加载模块文件的,import函数可以读取并执行一个JavaScript文件,然后返回该模块的export命令指定输出的代码。export与export default均可用于导出常量、函数、文件、模块,export可以有多个,export default只能有一个
2、require 定义模块:module变量代表当前模块,它的exports属性是对外的接口。通过exports可以将模块从模块中导出,其他文件加载该模块实际上就是读取module.exports变量,他们可以是变量、函数、对象等。在node中如果用exports进行导出的话系统会系统帮您转成module.exports的,只是导出需要定义导出名。
require与import的区别
1,require是CommonJS规范的模块化语法,import是ECMAScript 6规范的模块化语法;
2,require是运行时加载,import是编译时加载;
3,require可以写在代码的任意位置,import只能写在文件的最顶端且不可在条件语句或函数作用域中使用;
4,require通过module.exports导出的值就不能再变化,import通过export导出的值可以改变;
5;require通过module.exports导出的是exports对象,import通过export导出是指定输出的代码;
6,require运行时才引入模块的属性所以性能相对较低,import编译时引入模块的属性所所以性能稍高。

24:map和forEach的区别

相同点
都是循环遍历数组中的每一项 forEach和map方法里每次执行匿名函数都支持3个参数,参数分别是item(当前每一项)、index(索引值)、arr(原数组),需要用哪个的时候就写哪个 匿名函数中的this都是指向window 只能遍历数组
注意:forEach对于空数组是不会调用回调函数的。

不同点
map方法返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。(原数组进行处理之后对应的一个新的数组。) map()方法不会改变原始数组 map()方法不会对空数组进行检测 forEach()方法用于调用数组的每个元素,将元素传给回调函数.(没有return,返回值是undefined)

25:promise的解释

1、Promise 是异步编程的一种解决方案,主要用于异步计算,支持链式调用,可以解决回调地狱 的问题,自己身上有all、reject、resolve、race 等方法,原型上有then、catch等方法。
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果,可以在对象之间传递和操作 promise,帮助我们处理队列
3、promise 有三个状态:pending[待定]初始状态,fulfilled[实现]操作成功,rejected[被否决]操作失败
4、Promise 对象状态改变:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了
5、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部,但是写了then 和 catch ,会被then的第二个参数 或 catch所捕获

26:promise 的 then 为什么可以支持链式调用

promise 的then会返回一个新的 promise 对象,能保证 then 方 可以进行链式调用

27:async、await的原理

1)Async 和 await 是一种同步的写法,但还是异步的操作,两个必须配合一起使用
2)函数前面的async关键字,表明该函数内部有异步操作。调用该函数时,会立即返回一个Promise对象。
3)await 是个运算符,用于组成表达式,await 表达式的运算结果取决于它等的东西,如果是promise则会等待promaise 返回结果,接普通函数直接进行链式调用.
4)await 能够获取promise执行的结果 await必须和async一起使用才行,async配合await使用是一个阻塞的异步方法
5)如果await后面不是Promise对象, 就直接返回对应的值,只能在async函数中出现, 普通函数直接使用会报错
6)await语句后的Promise对象变成reject状态时,那么整个async函数会中断,后面的程序不会继续执行

28:说说var、let、const之间的区别

1)变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
2)暂时性死区
var不存在暂时性死区
let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
3)块级作用域
var不存在块级作用域
let和const存在块级作用域
4)重复声明
var允许重复声明变量
let和const在同一作用域不允许重复声明变量
5)修改声明的变量
var和let可以
const声明一个只读的常量。一旦声明,常量的值就不能改变
6)使用
能用const的情况尽量使用const,其他情况下大多数使用let,避免使用var

29:ES6 数组some()和every()使用

some 英语翻译为一些,every翻译为所有,每个,所以some方法 只要其中一个为true 就会返回true的,相反,every()方法必须所有都返回true才会返回true,哪怕有一个false,就会返回false;every()和 some()目的:确定数组的所有成员是否满足指定的测试

29:说说你对Vue生命周期的理解?

在Vue中实例从创建到销毁的过程就是生命周期,即指从创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程
1)Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后,以及一些特殊场景的生命周期
生命周期

beforeCreate -> created
初始化vue实例,进行数据观测
created
完成数据观测,属性与方法的运算,watch、event事件回调的配置
可调用methods中的方法,访问和修改data数据触发响应式渲染dom,可通过computed和watch完成数据计算
此时vm.$el并没有被创建
created -> beforeMount
判断是否存在el选项,若不存在则停止编译,直到调用vm.$mount(el)才会继续编译
优先级:render > template > outerHTML
vm.el获取到的是挂载DOM的
beforeMount
在此阶段可获取到vm.el
此阶段vm.el虽已完成DOM初始化,但并未挂载在el选项上
beforeMount -> mounted
此阶段vm.el完成挂载,vm.$el生成的DOM替换了el选项所对应的DOM
mounted
vm.el已完成DOM的挂载与渲染,此刻打印vm.$el,发现之前的挂载点及内容已被替换成新的DOM
beforeUpdate
更新的数据必须是被渲染在模板上的(el、template、render之一)
此时view层还未更新
若在beforeUpdate中再次修改数据,不会再次触发更新方法
updated
完成view层的更新
若在updated中再次修改数据,会再次触发更新方法(beforeUpdate、updated)
beforeDestroy
实例被销毁前调用,此时实例属性与方法仍可访问
destroyed
完全销毁一个实例。可清理它与其它实例的连接,解绑它的全部指令及事件监听器
并不能清除DOM,仅仅销毁实例

使用场景
使用场景

30:Vue组件间通信方式都有哪些?

https://mp.weixin.qq.com/s/uFjMz6BByA5eknBgkvgdeQ
1)通过 props 传递
适用场景:父组件传递数据给子组件
子组件设置props属性,定义接收父组件传递过来的参数
父组件在使用子组件标签中通过字面量来传递值
2)通过$emit 触发自定义事件
适用场景:子组件传递数据给父组件
子组件通过$emit触发自定义事件,$emit第二个参数为传递的数值
父组件绑定监听器获取到子组件传递过来的参数
3)使用 ref
父组件在使用子组件的时候设置ref
父组件通过设置子组件ref来获取数据
4)EventBus
使用场景:兄弟组件传值
创建一个中央时间总线EventBus
兄弟组件通过$emit触发自定义事件,$emit第二个参数为传递的数值
另一个兄弟组件通过$on监听自定义事件
5)parent或root
通过共同祖辈$parent或者$root搭建通信侨联
6)attrs 与 listeners
7)Provide 与 Inject
8)Vuex
小结:
父子关系的组件数据传递选择 props$emit进行传递,也可选择ref
兄弟关系的组件数据传递可选择$bus,其次可以选择$parent进行传递
祖先与后代组件数据传递可选择attrslisteners或者 ProvideInject
复杂关系的组件数据传递可以通过vuex存放共享的变量

31:Vue中的v-show和v-if怎么理解?

v-show与v-if的区别

控制手段不同
编译过程不同
编译条件不同
性能消耗不同

控制手段:v-show隐藏则是为该元素添加css–display:none,dom元素依旧还在。v-if显示隐藏是将dom元素整个添加或删除
编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换
编译条件:v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。只有渲染条件为假时,并不做操作,直到为真才渲染
1)v-show 由false变为true的时候不会触发组件的生命周期
2)v-if由false变为true的时候,触发组件的beforeCreate、create、beforeMount、mounted钩子,由true变为false的时候触发组件的beforeDestroy、destroyed方法
性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗

32:为什么Vue中的v-if和v-for不建议一起用?

v-for优先级是比v-if高

33:Vue的双向数据绑定原理是什么?

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

34:请说出vue.cli项目中src目录每个文件夹和文件的用法?

assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置;view视图;app.vue是一个应用主组件;main.js是入口文件

35:怎样使用自定义的组件?

• 第一步:在components目录新建你的组件文件(indexPage.vue),script一定要export default {}
• 第二步:在需要用的页面(组件)中导入:import indexPage from ‘@/components/indexPage.vue’
• 第三步:注入到vue的子组件的components属性上面,components:{indexPage}
• 第四步:在template视图view中使用,
例如有indexPage命名,使用的时候则index-page

36:SPA(单页应用)首屏加载速度慢怎么解决?

常见的几种SPA首屏优化方式
1)减小入口文件积
常用的手段是路由懒加载,把不同路由对应的组件分割成不同的代码块,待路由被请求的时候会单独打包路由,使得入口文件变小,加载速度大大增加
2)静态资源本地缓存
后端返回资源问题:
采用HTTP缓存,设置Cache-Control,Last-Modified,Etag等响应头
采用Service Worker离线缓存
3)UI框架按需加载
4)图片资源的压缩
对页面上使用到的icon,可以使用在线字体图标,或者雪碧图,将众多小图标合并到同一张图上,用以减轻http请求压力。
5)组件重复打包
在webpack的config文件中,修改CommonsChunkPlugin的配置,minChunks为3表示会把使用3次及以上的包抽离出来,放进公共依赖文件,避免了重复加载组件
6)开启GZip压缩
安装compression-webpack-plugin
7)使用SSR
SSR(Server side ),也就是服务端渲染,组件或页面通过服务器生成html字符串,再发送到浏览器
从头搭建一个服务端渲染是很复杂的,vue应用建议使用Nuxt.js实现服务端渲染

37:Vue常用的修饰符有哪些?

1)表单修饰符
lazy:在我们填完信息,光标离开标签的时候,才会将值赋予给value,也就是在change事件之后再进行信息同步
trim:自动过滤用户输入的首空格字符,而中间的空格不会过滤
number:自动将用户的输入值转为数值类型,但如果这个值无法被parseFloat解析,则会返回原来的值
2)事件修饰符
stop:阻止了事件冒泡,相当于调用了event.stopPropagation方法
prevent:阻止了事件的默认行为,相当于调用了event.preventDefault方法
self:只当在 event.target 是当前元素自身时触发处理函数
once:只当在 event.target 是当前元素自身时触发处理函数
capture:使事件触发从包含这个元素的顶层开始往下触发
passive:在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符
不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。
passive 会告诉浏览器你不想阻止事件的默认行为

native:让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用 v-on 只会监听自定义事件
使用.native修饰符来操作普通HTML标签是会令事件失效的
3)鼠标按钮修饰符
left 左键点击
right 右键点击
middle 中键点击
4)键盘修饰符
键盘修饰符是用来修饰键盘事件(onkeyup,onkeydown)的,有如下:
keyCode存在很多,但vue为我们提供了别名,分为以下两种:
普通键(enter、tab、delete、space、esc、up…)
系统修饰键(ctrl、alt、meta、shift…)
// 只有按键为keyCode的时候才触发
<input type="text" @keyup.keyCode="shout()">
还可以通过以下方式自定义一些全局的键盘码别名
Vue.config.keyCodes.f2 = 113
5)v-bind修饰符 v-bind修饰符主要是为属性进行操作
async:能对props进行一个双向绑定

38:什么是虚拟DOM?

只是一层对真实DOM的抽象,以JavaScript 对象 (VNode 节点) 作为基础的树,用对象的属性来描述节点,最终可以通过一系列操作使这棵树映射到真实环境上
在Javascript对象中,虚拟DOM 表现为一个 Object对象。并且最少包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,不同框架对这三个属性的名命可能会有差别
创建虚拟DOM就是为了更好将虚拟的节点渲染到页面视图中,所以虚拟DOM对象的节点与真实DOM的属性一一照应
通过VNode,vue可以对这颗抽象树进行创建节点,删除节点以及修改节点的操作, 经过diff算法得出一些需要修改的最小单位,再更新视图,减少了dom操作,提高了性能
虚拟 DOM 最大的优势是 diff 算法,减少 JavaScript 操作真实 DOM 的带来的性能消耗。虽然这一个虚拟 DOM 带来的一个优势,但并不是全部。虚拟 DOM 最大的优势在于抽象了原本的渲染过程,实现了跨平台的能力,而不仅仅局限于浏览器的 DOM,可以是安卓和 IOS 的原生组件,可以是近期很火热的小程序,也可以是各种GUI

39:Vue项目中有封装过axios吗?怎么封装的?

封装的同时,你需要和 后端协商好一些约定,请求头,状态码,请求超时时间…
设置接口请求前缀:根据开发、测试、生产环境的不同,前缀需要加以区分
请求头 : 来实现一些具体的业务,必须携带一些参数才可以请求(例如:会员业务)
状态码: 根据接口返回的不同status , 来执行不同的业务,这块需要和后端约定好
请求方法:根据get、post等方法进行一个再次封装,使用起来更为方便
请求拦截器: 根据请求的请求头设定,来决定哪些请求可以访问
响应拦截器:这块就是根据 后端`返回来的状态码判定执行不同业务
1)设置接口请求前缀
用node环境变量来作判断,用来区分开发、测试、生产环境
在本地调试的时候,还需要在vue.config.js文件中配置devServer实现代理转发,从而实现跨域
2)设置请求头与超时时间
大部分情况下,请求头都是固定的,只有少部分情况下,会需要一些特殊的请求头,这里将普适性的请求头作为基础配置。当需要特殊请求头时,将特殊请求头作为参数传入,覆盖基础配置
3)封装请求方法
4)请求拦截器
请求拦截器可以在每个请求里加上token,做了统一处理后维护起来也方便
5)响应拦截器
响应拦截器可以在接收到响应后先做一层操作,如根据状态码判断登录状态、授权

40:父组件和子组件的执行顺序

加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父beforeUpdate->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

41:HTTPS是什么

HTTPS即加密的HTTP,HTTPS并不是一个新协议,而是HTTP+SSL(TLS)。原本HTTP先和TCP(假定传输层是TCP协议)直接通信,而加了SSL后,就变成HTTP先和SSL通信,再由SSL和TCP通信,相当于SSL被嵌在了HTTP和TCP之间

42:进程和线程是什么

线程是最小的执行单元,而进程由至少一个线程组成。如何调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间。
进程指计算机中已运行的程序。
线程指操作系统能够进行运算调度的最小单位。

43:前端面试题

前端面试题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值