目录
- 1. vue双向数据绑定(响应式)原理
- 2. HTML 语义化(语义化标签)
- 3. 标签上 title 与 alt 属性
- 4. CSS单位:1px、1em、1rem、1vh / 1vw 的含义
- 5. 网页前端性能优化的方式
- 6. HTTP常见的状态码
- 7. Vuex是什么(有哪些模块)
- 8. v-if 和 v-show 有什么区别
- 9. 对 SPA 单页面的理解,它的优缺点分别是什么
- 10. async/await 的理解与使用
- 11. display:none 和 visibility:hidden的区别
- 12. 什么是浏览器 重排(回流)和重绘
- 13. js 的数据类型
- 14. 什么是 DOM 和 BOM?
- 15. 什么是JSON
- 16. 同步和异步
- 17. 浏览器的同源政策?
- 18. js 的节流与防抖?
- 19. JS对象的浅拷贝与深拷贝
- 20. **apply和call**
- 21. 输入一个URL到页面过程中发生了什么
- 22. script标签中defer和async的区别
- 23. flex常用属性
- 24. CSS中 transition和animation的区别
- 25. CSS样式优先级
- 26. http 和 https 的基本概念
- 27. http 和 https 的区别
- 28. 浏览器本地存储
- 29. 闭包
- 30. promise
- 31. 事件捕获
- 32. 事件冒泡
- 33. 事件委托
- 34. 如何添加、移除、移动、复制、创建和查找节点
- 35. 模板字符串(ES6)
- 36. 解构赋值
- 37. vue中的data为什么是一个函数?
- 38. var let const 区别
- 39. 如何利用es6快速的去重
- 40. 什么是BFC
- 41. for in 和 for of的区别详解以及为for in的输出顺序
- 42. vue 第一次页面加载会触发哪几个钩子?
- 43. vue几种常用的指令
- 44. 什么是js的冒泡?Vue中如何阻止冒泡事件?
- 45. vue中$nextTick是什么
- 46. axios的特点有哪些
- 47. document.write和innerHTML的区别
- 48. 盒子模型详解
- 49. Vue实例的生命周期讲一下, mounted阶段真实DOM存在了嘛?
- 50. vue路由的两种模式
- 51. css3新的特性
- 52. vue中组件keep-alive生命周期
- 53. computed和watch的区别
- 54. diff算法的作用?
- 55. vue项目中:首屏加载空白的解决方案?
- 56. 谈谈对keep-alive的理解
1. vue双向数据绑定(响应式)原理
vue2: 通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。
let data = {
name:'张三',
age:18
}
//创建一个监视的实例对象,用于监视data中属性的变化
const obs = new Observer(data)
//准备一个vm实例对象
let vm = {}
vm._data = data = obs
function Observer(obj){
//汇总对象中所有的属性形成一个数组
const keys = Object.keys(obj)
//遍历
keys.forEach((k)=>{
Object.defineProperty(this,k,{
get(){
console.log('读取数据', obj[k])
return obj[k]
},
set(val){
console.log('修改数据', val)
obj[k] = val
}
})
})
}
vue3:
对于基本类型的数据,响应式依然是靠Object.defineProperty()的get与set完成的
对于对象类型的数据
- 通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
- 通过Reflect(反射): 对源对象的属性进行操作。
let person = {
name:'张三',
age:18
}
person = p = new Proxy(person, {
// 拦截读取属性值
get (target, propName) {
console.log(`有人读取了p身上的${propName}属性`)
// return target[propName]
return Reflect.get(target, propName)
},
// 拦截设置属性值或添加新属性
set (target, propName, value) {
console.log(`有人修改了p身上的${propName}属性`)
// target[propName] = value
Reflect.set(target,propName,value)
},
// 拦截删除属性
deleteProperty (target, propName) {
console.log(`有人删除了p身上的${propName}属性`)
// return delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})
2. HTML 语义化(语义化标签)
HTML中的语义化标签_html语义化标签_勇敢小陈的博客-CSDN博客
3. 标签上 title 与 alt 属性
4. CSS单位:1px、1em、1rem、1vh / 1vw 的含义
5. 网页前端性能优化的方式
6. HTTP常见的状态码
7. Vuex是什么(有哪些模块)
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式, 采用集中式存储管理应用的所有组件的状态,解决多组件数据通信。
包括以下几个模块:
State => 基本数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态。
Getter => 从基本数据派生的数据,允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
Mutation => 是唯一更改 store 中状态的方法,且必须是同步函数。
Action => 像一个装饰器,包裹mutations,使之可以异步。用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
Module => 模块化Vuex,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
更多
8. v-if 和 v-show 有什么区别
v-if 是真正的条件渲染,会控制这个 DOM 节点的存在与否。因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
9. 对 SPA 单页面的理解,它的优缺点分别是什么
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页> 面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 > HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
基于上面一点,SPA 相对对服务器压力小;
前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一> 加载,部分页面按需加载;
前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所> 有的页面切换需要自己建立堆栈管理;
SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
10. async/await 的理解与使用
async用于申明一个function是异步的;
而await则可以认为是 async await的简写形式,是等待一个异步方法执行完成的。
11. display:none 和 visibility:hidden的区别
都是元素隐藏,在文档流中,display:none不占位置。visibility:hidden占位置。
性能上,display比visibility差。display控制显示隐藏时,页面会产生回流(当页面中的一部分元素需要改变规模尺寸、布局、显示隐藏等,页面重新构建,此时就是回流。所有页面第一次加载时需要产生一次回流)
12. 什么是浏览器 重排(回流)和重绘
重绘(repaints)是一个元素外观的改变所触发的浏览器行为,例如改变vidibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随回流。
回流(reflow)是更明显的一种改变,可以理解为渲染树需要重新计算。触发条件:添加或者删除可见的DOM元素,元素尺寸改变——边距、填充、边框、宽度和高度
13. js 的数据类型
共有六种基本数据类型,分别是 Undefined、Null、Boolean、Number、String,还有在 ES6 中新增的 Symbol 类型(创建后独一无二且不可变)
复杂类型:Object、Array、Function
14. 什么是 DOM 和 BOM?
DOM 指的是文档对象模型,它指的是把文档当做一个对象来对待,这个对象主要定义了处理网页内容的方法和接口。
BOM 指的是浏览器对象模型,它指的是把浏览器当做一个对象来对待,这个对象主要定义了与浏览器进行交互的法和接口。
BOM的核心是 window,而 window 对象具有双重角色,它既是通过 js 访问浏览器窗口的一个接口,又是一个 Global(全局)对象。这意味着在网页中定义的任何对象,变量和函数,都作为全局对象的一个属性或者方法存在。window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象。
15. 什么是JSON
JSON 是一种基于文本的轻量级的数据交换格式。它可以被任何的编程语言读取和作为数据格式来传递。
在项目开发中,我们使用 JSON 作为前后端数据交换的方式。在前端我们通过将一个符合 JSON 格式的数据结构序列化为 JSON 字符串,然后将它传递到后端,后端通过 JSON 格式的字符串解析后生成对应的数据结构,以此来实现前后端数据的一个传递。
因为 JSON 的语法是基于 js 的,因此很容易将 JSON 和 js 中的对象弄混,但是我们应该注意的是 JSON 和 js 中的对象不是一回事,JSON 中对象格式更加严格,比如说在 JSON 中属性值不能为函数,不能出现 NaN 这样的属性值等,因此大多数的 js 对象是不符合 JSON 对象的格式的。
在 js 中提供了两个函数来实现 js 数据结构和 JSON 格式的转换处理,
一个是 JSON.stringify 函数,通过传入一个符合 JSON 格式的数据结构,将其转换为一个 JSON 字符串。如果传入的数据结构不符合 JSON 格式,那么在序列化的时候会对这些值进行对应的特殊处理,使其符合规范。在前端向后端发送数据时,我们可以调用这个函数将数据对象转化为 JSON 格式的字符串。
另一个函数 JSON.parse() 函数,这个函数用来将 JSON 格式的字符串转换为一个 js 数据结构,如果传入的字符串不是标准的 JSON 格式的字符串的话,将会抛出错误。当我们从后端接收到 JSON 格式的字符串时,我们可以通过这个方法来将其解析为一个 js 数据结构,以此来进行数据的访问。
16. 同步和异步
同步(阻塞):简单理解:一个执行完再执行下一个。可以理解为在执行完一个函数或方法之后,一直等待系统返回值或消息,这时程序是处于阻塞的,只有接收到返回的值或消息后才往下执行其他的命令。
异步(并发):简单理解:可同时进行。执行完函数或方法后,不必阻塞性地等待返回值或消息,只需要向系统委托一个异步过程,那么当系统接收到返回值或消息时,系统会自动触发委托的异步过程,从而完成一个完整的流程。
17. 浏览器的同源政策?
我对浏览器的同源政策的理解是,一个域下的 js 脚本在未经允许的情况下,不能够访问另一个域的内容。这里的同源的指的是两个域的协议、域名、端口号必须相同,否则则不属于同一个域(跨域)。
同源政策主要限制了三个方面
第一个是当前域下的 js 脚本不能够访问其他域下的 cookie、localStorage 和 indexDB。
第二个是当前域下的 js 脚本不能够操作访问操作其他域下的 DOM。
第三个是当前域下 ajax 无法发送跨域请求。
同源政策的目的主要是为了保证用户的信息安全,它只是对 js 脚本的一种限制,并不是对浏览器的限制,对于一般的 img、或者script 脚本请求都不会有跨域的限制,这是因为这些操作都不会通过响应结果来进行可能出现安全问题的操作。
18. js 的节流与防抖?
函数防抖: 在事件被触发 n 秒后再执行回调,如果在这 n 秒内事件又被触发,则重新计时。
函数节流: 规定一个单位时间,在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。
// 函数防抖的实现
function debounce(fn, wait) {
var timer = null;
return function() {
var context = this,
args = arguments;
// 如果此时存在定时器的话,则取消之前的定时器重新记时
if (timer) {
clearTimeout(timer);
timer = null;
}
// 设置定时器,使事件间隔指定事件后执行
timer = setTimeout(() => {
fn.apply(context, args);
}, wait);
};
}
// 函数节流的实现;
function throttle(fn, delay) {
var preTime = Date.now();
return function() {
var context = this,
args = arguments,
nowTime = Date.now();
// 如果两次时间间隔超过了指定时间,则执行函数。
if (nowTime - preTime >= delay) {
preTime = Date.now();
return fn.apply(context, args);
}
};
}
19. JS对象的浅拷贝与深拷贝
浅拷贝:
自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象;但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象。
深拷贝:
浅拷贝只是创建了一个新的对象,复制了原有对象的基本类型的值,而引用数据类型只拷贝了一层属性,再深层的还是无法进行拷贝。深拷贝则不同,对于复杂引用数据类型,其在堆内存中完全开辟了一块内存地址,并将原有的对象完全复制过来存放。
扩展:实现示例
// 浅拷贝的实现;
function shallowCopy(object) {
// 只拷贝对象
if (!object || typeof object !== "object") return;
// 根据 object 的类型判断是新建一个数组还是对象
let newObject = Array.isArray(object) ? [] : {};
// 遍历 object,并且判断是 object 的属性才拷贝
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] = object[key];
}
}
return newObject;
}
// 深拷贝的实现;
function deepCopy(object) {
if (!object || typeof object !== "object") return;
let newObject = Array.isArray(object) ? [] : {};
for (let key in object) {
if (object.hasOwnProperty(key)) {
newObject[key] =
typeof object[key] === "object" ? deepCopy(object[key]) : object[key];
}
}
return newObject;
}
20. apply和call
官方定义:调用一个对象的一个方法,用另一个对象替换当前对象(简单来说:是用于解决this指向问题,将this指向调用者)
apply:B.apply(A, arguments);即A对象调用B对象的方法。(arguments 参数数组形式)
call:B.call(A, args1,args2);即A对象调用B对象的方法。(args1,args2 参数1,参数2依次逗号隔开形式)
var A = {
name: "AAA",
fn: function(skill) {
this.skill = skill;
console.log("我的名字是 " + this.name + ", 我的技能是 " + this.skill);
}
}
var B = {
name: "BBB"
}
A.fn("唱歌"); // 我的名字是 AAA, 我的技能是 唱歌
B.fn("跳舞"); // Uncaught TypeError: B.fn is not a function;
// 使用apply解决报错
A.fn.apply(B,["跳舞"])//我的名字是 BBB, 我的技能是 唱歌
// 使用call解决报错
A.fn.call(B,'跳舞21')//我的名字是 BBB, 我的技能是 唱歌21
21. 输入一个URL到页面过程中发生了什么
- 首先在浏览器中输入URL
- 查找缓存:浏览器先查看浏览器缓存-系统缓存-路由缓存中是否有该地址页面,如果有则显示页面内容。如果没有则进行下一步。
- DNS域名解析:浏览器向DNS服务器发起请求,解析该URL中的域名对应的IP地址。DNS服务器是基于UDP的,因此会用到UDP协议。
- 建立TCP连接:解析出IP地址后,根据IP地址和默认80端口,和服务器建立TCP连接
- 发起HTTP请求:浏览器发起读取文件的HTTP请求,,该请求报文作为TCP三次握手的第三次数据发送给服务器
- 服务器响应请求并返回结果:服务器对浏览器请求做出响应,并把对应的html文件发送给浏览器
- 关闭TCP连接:通过四次挥手释放TCP连接
- 浏览器渲染:客户端(浏览器)解析HTML内容并渲染出来,浏览器接收到数据包后的解析流程为:
- 构建DOM树:词法分析然后解析成DOM树(dom tree),是由dom元素及属性节点组成,树的根是document对象
- 构建CSS规则树:生成CSS规则树(CSS Rule Tree)
- 构建render树:Web浏览器将DOM和CSSOM结合,并构建出渲染树(render tree)
- 布局(Layout):计算出每个节点在屏幕中的位置
- 绘制(Painting):即遍历render树,并使用UI后端层绘制每个节点。
22. script标签中defer和async的区别
script标签带async属性的标签,不能保证加载的顺序;
script标签带defer属性的标签,按照加载顺序执行;
async属性,表示后续文档的加载和执行与js脚本的加载和执行是并行进行的,即异步执行;defer属性,加载后续文档的过程和js脚本的加载(此时仅加载不执行)是并行进行的(异步),js脚本需要等到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。
23. flex常用属性
1.flex-direction属性决定主轴的方向(即项目的排列方向)。
2. flex-wrap属性定义,如果一条轴线排不下,如何换行。
3.flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
4.justify-content属性定义了项目在主轴上的对齐方式。
5.align-items属性定义项目在交叉轴上如何对齐。
6.align-content属性定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。
更多参考:
http://c.biancheng.net/css3/flex.html
24. CSS中 transition和animation的区别
transition是过度属性,强调过度,它的实现需要触发一个事件(比如鼠标移动上去,焦点,点击等)才执行动画。它类似于flash的补间动画,设置一个开始关键帧,一个结束关键帧。
animation是动画属性,它的实现不需要触发事件,设定好时间之后可以自己执行,且可以循环一个动画。它也类似于flash的补间动画,但是它可以设置多个关键帧(用@keyframe定义)完成动画。
25. CSS样式优先级
- !important,如color: red!important
- 内联样式,如style=“”
- ID 选择器, 如 #id{}
- 类选择器, 如 .class{}
属性选择器, 如 a[href=“segmentfault.com”]{}
伪类选择器, 如 :hover{}
- 标签选择器, 如 span{}
伪元素选择器, 如 ::before{}
- 通配选择器, 如 *{}
26. http 和 https 的基本概念
http: 是一个客户端和服务器端请求和应答的标准(TCP),用于从 WWW 服务器传输超文本到本地浏览器的超文本传输协议。
https:是以安全为目标的 HTTP 通道,即 HTTP 下 加入 SSL 层进行加密。其作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性。
27. http 和 https 的区别
1.HTTP
的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头
2.HTTP
是不安全的,而 HTTPS 是安全的
3.HTTP
标准端口是80 ,而 HTTPS 的标准端口是443
4.在OSI
网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层
5.HTTP
无法加密,而HTTPS 对传输的数据进行加密
6.HTTP
无需证书,而HTTPS 需要CA机构的颁发的SSL证书
28. 浏览器本地存储
浏览器的本地存储主要分为Cookie、localStorage和sessionStorage。
共同点: 都是保存在浏览器端、且同源的
不同点:
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
存储大小限制也不同,
cookie数据不能超过4K,sessionStorage和localStorage可以达到5M
sessionStorage:仅在当前浏览器窗口关闭之前有效;
localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据;
cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
作用域不同
sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面;
localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在
cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在
29. 闭包
标准回答:
闭包: 一个函数和词法环境的引用捆绑在一起,这样的组合就是闭包,
一般就是一个函数A,return其内部的函数B, 被return出去的B函数能够在外部访问A函数内部的变量,这时候就形成了一个B函数的变量背包,A函数执行结束后这个变量背包也不会被销毁,并且这个变量背包在A函数外部只能通关B函数访问,
闭包形成的原理:作用域链,当前作用域可以访问上级作用域中的变量,闭包解决的问题: 由于垃圾回收器不会将闭包中的变量销毁,于是就造成了内存泄露,内存泄漏积累多了就容易导致内存溢出,
加分回答:闭包的应用,能够模仿块级作用域,能够实现柯里化、在构造函数中定义特权方法,Vue种数据响应式Observer中使用闭包等
30. promise
标准回答:
promise的作用:promise是异步微任务,解决了异步多层嵌套回调的问题,让代码的可读性更高,更容易维护
promise的使用: promise是ES6提供的一个构造函数,可以使用promise构造函数new一个实例,promise构造函数接受一个函数作为参数,这个函数又两个参数,分别是‘resolve’和‘reject’,‘resolve’将promise由等待pending变为成功,将异步操作的结果作为参数传递过去,‘reject’则将状态由等待pending变成失败,在异步操作失败时调用,将异步操作报出的错误作为参数传递过去。
实例创建完成后,可以使用’then’方法分别指定成功或失败的回调函数,可以使用catch捕捉失败。
then和catch最终返回的也是一个promise,所以可以链式调用,
promise的特点:1. 对象的状态不受外界影响,promise对象代表一个异步操作,有三种状态, pending(执行中) resolved(成功,又称fulfilled)。rejected(拒接),pending为初始状态。resolved和rejected为结束状态,结束状态代表promise生命周期已结束。2.一旦状态改变,就不会在变,任何时候都可以得到这个结果, promise对象的状态改变,只能有两个可能, 从pending变为resolved | 从pending变成rejected。3.resolve方法的参数是then中回调函数的参数,reject方法种的参数是catch中的参数 4. then方法和catch方法只要不报错,返回的都是一个fulfilled状态的promise
加分回答:
promise.resolve() 返回的promise对象状态变成fulfilled。并且将value传递给对应的then方法。
promise.reject() 返回一个状态为失败状态的promise对象,并将给定的失败信息传递给对应的处理方法。
promise.all() 返回一个新的promise对象,该promise对象的参数对象里面所有的promise对象都成功的时候才会触发,一旦有任何一个promise对象失败则立即触发该promise对象的失败。
promise.any() 接受一个promise对象的集合,当其中一个promise成功,就返回那个成功的promise的值。
promise.race() 当参数里面的任意一个promise对象成功或者失败后,父promise马上也会用子promise的成功返回或者失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象
31. 事件捕获
当事件发生在 DOM 元素上时,该事件并不完全发生在那个元素上。在捕获阶段,事件从 window 开始,一直到触发事件的元素。(是事件从顶部元素到目标元素的开始。现代浏览器默认情况下不支持事件捕获,但是我们可以通过JavaScript中的代码来实现)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Event Capturing</title>
</head>
<body>
<div id="parent">
<button id="child">Child</button>
</div>
<script>
var parent = document.querySelector('#parent');
var child = document.querySelector('#child');
parent.addEventListener('click', function(){
console.log("Parent clicked");
},true);
child.addEventListener('click', function(){
console.log("Child clicked");
});
</script>
</body>
</html>
备注:addEventListener的参数解析
参数 | 描述 |
event | 必须。字符串,指定事件名。 |
注意: 不要使用 “on” 前缀。 例如,使用 “click” ,而不是使用 “onclick”。 | |
提示: 所有 HTML DOM 事件,可以查看我们完整的 HTML DOM Event 对象参考手册。 | |
function | 必须。指定要事件触发时执行的函数。 |
当事件对象会作为第一个参数传入函数。 事件对象的类型取决于特定的事件。例如, “click” 事件属于 MouseEvent(鼠标事件) 对象。 | |
useCapture | 可选。布尔值,指定事件是否在捕获或冒泡阶段执行。 |
可能值: |
- true - 事件句柄在捕获阶段执行
- false- false- 默认。事件句柄在冒泡阶段执行
|
console 打印
Parent clicked
Child clicked
32. 事件冒泡
事件冒泡是指事件从最深层的元素或目标元素到其父元素,然后是其所有由下而上的祖先 开始的事件。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Event Bubbling</title>
</head>
<body>
<div id="parent">
<button id="child">Child</button>
</div>
<script>
var parent = document.querySelector('#parent');
<!-- Add click event on parent div -->
parent.addEventListener('click', function(){
console.log("Parent clicked");
});
var child = document.querySelector('#child');
<!-- Add click event on child button -->
child.addEventListener('click', function(){
console.log("Child clicked");
});
</script>
</body>
</html>
console 打印:
Child clicked
Parent clicked
33. 事件委托
事件委托本质上是利用了浏览器事件冒泡的机制。事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到 目标节点。
因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
<ul>
<li>111111</li>
<li>222222</li>
<li>333333</li>
<li>444444</li>
<li>555555</li>
</ul>
<script>
var li = document.querySelectorAll('li');
for(var i=0;i<li.length;i++){
li[i].onclick = function(){
this.style.color = 'green';
}
}
</script>
34. 如何添加、移除、移动、复制、创建和查找节点
创建新节点
createDocumentFragment(); // 创建一个DOM片段
createElement(); // 创建一个具体的元素
createTextNode(); // 创建一个文本节点
添加、移除、替换、插入
appendChild(node);
removeChild(node);
replaceChild(newNode,oldNode);
insertBefore(newNode,oldNode);
查找
getElementById();
getElementsByName();
getElementsByTagName();
getElementsByClassName();
querySelector();
querySelectorAll();
属性操作
getAttribute(key);
setAttribute(key, value);
hasAttribute(key);
removeAttribute(key)
35. 模板字符串(ES6)
模板字符串是在 JavaScript 中创建字符串的一种新方法。
我们可以通过使用反引号使模板字符串化
// ES5 Version
var greet = 'Hi I\'m leo';
// ES6 Version
let greet = `Hi I'm leo`;
在 ES5 中我们需要使用一些转义字符来达到多行的效果,在ES6模板字符串,不需要这么麻烦
// ES5 Version
var str = '\n'
+ ' I \n'
+ ' Am \n'
+ 'Iron Man \n';
// ES6 Version
let str = `
I
Am
Iron Man
`;
在 ES5 版本中,我们需要添加 \n 以在字符串中添加新行。在模板字符串中,我们不需要这样做
// ES5 Version
function greet(name) {
return 'Hello ' + name + '!';
}
// ES6 Version
function greet(name) {
return `Hello ${name} !`;
}
36. 解构赋值
假设有如下的对象
let employee = {
firstName: "leo",
lastName: "ggj",
position: "Software Developer",
age: 18
};
从对象获取属性,早期方法是创建一个与对象属性同名的变量。这种方法很麻烦,因为我们要为每个属性创建一个新变量。假设我们有一个对象,它有很多属性和方法,用这种方法提取属性会很麻烦,形如
let firstName = employee.firstName;
let lastName = employee.lastName;
let position = employee.position;
let age = employee.age;
使用解构方式语法就变得简洁多了
let { firstName, lastName, position, age } = employee;
我们还可以为属性取别名
let { firstName: fName, lastName: lName, position, age } = employee;
console.log(fName) // leo
console.log(lName) // ggj
当然如果属性值为 undefined 时,我们还可以指定默认值
// skill默认值: dance
let { skill = "dance", lastName: lName, position, age } = employee;
console.log(skill) // dance
37. vue中的data为什么是一个函数?
Vue 中的 data 必须是个函数,因为当 data 是函数时,组件实例化的时候这个函数将会被调用,返回一个对象,计算机会给这个对象分配一个内存地址,实例化几次就分配几个内存地址,他们的地址都不一样,所以每个组件中的数据不会相互干扰,改变其中一个组件的状态,其它组件不变。
简单来说,就是为了保证组件的独立性和可复用性,如果 data 是个函数的话,每复用一次组件就会返回新的 data,类似于给每个组件实例创建一个私有的数据空间,保护各自的数据互不影响
38. var let const 区别
var: 存在变量提升;存在变量覆盖,已经被定义且赋值的变量,如果再次被赋值,则以后一次值为准;没有块级作用域;
const:定义的是常量,声明之后必须赋值;定义的值不能去修改,否则报错;有块级作用域;不存在变量提升和变量覆盖;对于数组和对象的元素修改,不算做对常量的修改,不会报错。
let: 有块级作用域;不存在变量提升和变量覆盖;let不允许在相同的作用域中重复声明,注意是相同作用域,不同作用域重复声明不会报错
39. 如何利用es6快速的去重
利用set
let arr = [23, 12, 13, 33, 22, 12, 21]
let item = [...new Set(arr)]
40. 什么是BFC
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
产生BFC的方式
- float的值不为none。
- position的值不为static或者relative。
- display的值是inline-block、table-cell、flex、table-caption或者inline-flex
- overflow的值不为visible
BFC的作用
- 解决高度坍塌
在一个没有高度的div内,嵌套了一个设置浮动的div,会出现下面的情况
外层div出现了高度坍塌的现象,这时候给它加上一个overflow: hidden的css属性,就产生了BFC
- 解决margin重叠问题
里面的三个div都设置了margin: 10px,但是网页中的相邻的div之间距离也是10px,原因就是同一个BFC容器内的兄弟元素会产生垂直方向上的margin重叠,,会取两个相邻元素之间最大的marign作为之间的间隔。可以通过给每个子元素包裹一个BFC容器来解决。
41. for in 和 for of的区别详解以及为for in的输出顺序
https://zhuanlan.zhihu.com/p/139262299
42. vue 第一次页面加载会触发哪几个钩子?
触发 下面这几个beforeCreate, created, beforeMount, mounted ,并在mounted的时候DOM渲染完成
43. vue几种常用的指令
v-for 、 v-if 、v-bind、v-on、v-show、v-else
44. 什么是js的冒泡?Vue中如何阻止冒泡事件?
js冒泡概念:当父元素内多级子元素绑定了同一个事件,js会依次从内往外或者从外往内(?)执行每个元素的该事件,从而引发冒泡
js解决冒泡:event.stopPropagation()
vue解决冒泡: 事件.stop,例如:@click.stop=“” ,@mouseover.stop=“”
45. vue中$nextTick是什么
vue实现响应式并不是数据发生变化后dom立即变化,而是按照一定的策略来进行dom更新。
nextTick,则可以在回调中获取更新后的 DOM
46. axios的特点有哪些
● axios是一个基于promise的HTTP库,支持promise的所有API;
● 它可以拦截请求和响应;
● 它可以转换请求数据和响应数据,并对响应回来的内容自动转换为json类型的数据;
● 它安全性更高,客户端支持防御XSRF;
47. document.write和innerHTML的区别
document.write是直接写入到页面的内容流,会导致页面被重写。
innerHTML将内容写入某个DOM节点,不会导致页面全部重绘;
48. 盒子模型详解
49. Vue实例的生命周期讲一下, mounted阶段真实DOM存在了嘛?
Vue实例从创建到销毁的过程,就是生命周期。
也就是:开始创建->初始化数据->编译模板->挂载dom->数据更新重新渲染虚拟 dom->最后销毁。这一系列的过程就是vue的生命周期。所以在mounted阶段真实的DOM就已经存在了。
beforeCreate:vue实例的挂载元素el和数据对象data都还没有进行初始化,还是一个 undefined状态
created: 此时vue实例的数据对象data已经有了,可以访问里面的数据和方法, el还没有,也没有挂载dom
beforeMount: 在这里vue实例的元素el和数据对象都有了,只不过在挂载之前还是虚拟的dom节点
mounted: vue实例已经挂在到真实的dom上,可以通过对 dom操作来获取dom节点
beforeUpdate: 响应式数据更新时调用,发生在虚拟dom打补丁之前,适合在更新之前访问现有的 dom,比如手动移除已添加的事件监听器
updated: 虚拟dom重新渲染和打补丁之后调用,组成新的 dom已经更新,避免在这个钩子函数中操作数据,防止死循环。
beforeDestroy: vue实例在销毁前调用,在这里还可以使用,通过this也能访问到实例,可以在这里对一些不用的定时器进行清除,解绑事件。
destroyed:vue实例销毁后调用,调用后所有事件监听器会被移除,所有的子实例都会被销毁。
50. vue路由的两种模式
1.hash模式
特点:在url地址上有#号
实现的原理:原生的hasChange事件来实现,来监听hash值的变化
window.onhaschange=function(){}
刷新页面的时候:不会去发送请求,页面不会有任何问题,不需要后端来配合
2.history模式
特点:在url地址上没有#号,比较与hash模式看起来好看一些
实现的原理:利用的是history的api 来实现的 popState() 来实现的
刷新页面的时候:会去发送请求然后会导致页面出现找不到的情况,需要后端来配合解决
51. css3新的特性
1.CSS3选择器
2.CSS3边框与圆角
3.CSS3背景与渐变
4.CSS3过渡
5.CSS3变换
6.CSS3动画
更多参考:https://zhuanlan.zhihu.com/p/434788923
52. vue中组件keep-alive生命周期
activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated
deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated
53. computed和watch的区别
计算属性computed :
支持缓存,只有依赖数据发生改变,才会重新进行计算
不支持异步,当computed内有异步操作时无效,无法监听数据的变化
computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
不支持缓存,数据变,直接会触发相应的操作;
watch支持异步;
监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
当一个属性发生变化时,需要执行对应的操作;一对多;
监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数。immediate:组件加载立即触发回调函数执行;deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。这是watch和computed最大的区别。
54. diff算法的作用?
Diff算法的作用是用来计算出 Virtual DOM 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。
55. vue项目中:首屏加载空白的解决方案?
单页面应用的 html 是靠 js 生成,因为首屏需要加载很大的js文件(app.js vendor.js),所以当网速差的时候会产生一定程度的白屏。
解决办法:
- 优化 webpack 减少模块打包体积,code-split 按需加载
- 服务端渲染,在服务端事先拼装好首页所需的 html
- 首页加 loading 或 骨架屏 (仅仅是优化体验)
- 服务端开启gzip压缩
- 打包文件分包,提取公共文件包
56. 谈谈对keep-alive的理解
在平常开发中,有部分组件没有必要多次初始化,这时,我们需要将组件进行持久化,使组件的状态维持不变,在下一次展示时,也不会进行重新初始化组件。
也就是说,kee-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存。