1. JS 深拷贝和浅拷贝
深拷贝是要拷贝他里面引用的对象
浅拷贝只拷贝数据,引用的不拷贝
如何区分深拷贝与浅拷贝,简单点来说:
就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短。
如果B没变,那就是深拷贝.
2. JS 原型链的理解
一个对象所拥有的属性不仅仅是它本身拥有的属性,
它还会从其他对象中继承一些属性。当js在一个对象中找不到需要的属性时,
它会到这个对象的父对象上去找,以此类推,这就构成了对象的原型链。
包括
- prototype、
- __proto__、
- constructor
等
1、原型链
1)构造函数、原型和实例的关系
①构造函数都有一个属性prototype,这个属性是一个对象(Object的实例)
②原型对象prototype里面有一个constructor属性,该属性指向原型对象所属的构造函数---继承
③实例对象都有一个_proto_属性,该属性也指向构造函数的原型对象,它是一个非标准属性,不可以用于编程,
它是用于浏览器自己使用的
2)prototype与_proto_的关系
①prototype是构造函数的属性
②_proto_是实例对象的属性
——这两者都指向同一个对象
【总结】i)函数也是对象,对象不一定是函数;
ii)对象的本质:无序的键值对集合;键值对当中的值可以是任意数据类型的值
iii)对象就是一个容器,这个容器当中放的是(属性和方法)
3)属性搜索
①在访问对象的某个成员的时候会先在对象中找是否存在
②如果当前对象中没有就在构造函数的原型对象中找
③如果原型对象中没有找到就到原型对象的原型上找
④知道Object的原型对象的原型是null为止
2、Function
——所有函数都是Function的实例
①本地对象:独立于宿主环境(浏览器)的对象——包括
Object、Array、Date、RegExp、Function、Error、Number、String、Boolean
②内置对象——包括Math、Global(window,在js中就是全局变量),使用的时候不需要new
③宿主对象——包括自定义对象、DOM、BOM
es6常用数组操作
https://blog.youkuaiyun.com/qq_58340302/article/details/126429430
vue事件修饰符
.stop 阻止事件继续传播
.prevent 阻止标签默认行为
.capture 使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理
.self 只当在 event.target 是当前元素自身时触发处理函数
.once 事件将只会触发一次
.passive 告诉浏览器你不想阻止事件的默认行为
JS宏观任务和微观
宏观任务:顺序执行
微观任务:异步执行
先执行宏观任务,在执行微观任务;
宏任务主要包含:script( 整体代码)、setTimeout、setInterval、setImmediate、I/O、UI 交互事件、requestAnimationFrame
微任务主要包含:Promise.then catch finally、MutationObserver、process.nextTick
html5有哪些新特性、移除了那些元素
新特性
绘画 canvas
用于媒介回放的 video 和 audio 元素
本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不丢失
sessionStorage 的数据在浏览器关闭后自动删除
语意化更好的内容元素,比如article、footer、header、nav、section
表单控件,calendar、date、time、email、url、search
新的技术webworker, websocket, Geolocation
移除
纯表现的元素:basefont,big,center,font, s,strike,tt,u`
对可用性产生负面影响的元素:frame,frameset,noframes
diff算法
diff 算法是一种通过同层的树节点进行比较的高效算法,比较方式:diff整体策略为:深度优先,同层比较
diff算法 当data发生改变 会根据新的数据生成一个新的虚拟dom ,
新的虚拟dom和旧的虚拟dom进行对比,这个对比的过程就是diff算法,会找到不同地方,只去渲染不同的地方,总的来说就是减少DOM,重绘和回流。
vite和webpack的区别
vite服务器启动速度比webpack快,由于vite启动的时候不需要打包,也就无需分析模块依赖、编译,
所以启动速度非常快。当浏览器请求需要的模块时,再对模块进行编译,这种按需动态编译的模式,
极大缩短了编译时间,当项目越大,文件越多时,vite的开发时优势越明显。
vite热更新比webpack快,vite在HRM方面,当某个模块内容改变时,让浏览器去重新请求该模块即可,
而不是像webpack重新将该模块的所有依赖重新编译。
Vite的使用简单,只需执行初始化命令,就可以得到一个预设好的开发环境,开箱即获得一堆功能,
包括:CSS预处理、html预处理、异步加载、分包、压缩、HMR等。使用复杂度介于Parcel和Webpack的中间,
只是暴露了极少数的配置项和plugin接口,既不会像Parcel一样配置不灵活,又不会像Webpack一样需要了解庞大的loader、plugin生态,
灵活适中、复杂度适中。
3. cookie和session,localStorage区别
Session 是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
Cookie 是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式,不能超过4K。
localStorage - 用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去除,存储5M
sessionStorage - 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据,存储5M
VUE2~VUE3双向数据绑定的原理和区别
数据劫持: 当访问或者设置对象的属性的时候,触发相应的函数,并且返回设置属性的值。
1.VUE2.0 通过 Object.defineProperty 来劫持对象属性的 getter 和 setter 操作,当数据发⽣变化时
发出通知
2.VUE3.0 通过 Proxy 来劫持数据,当数据发⽣变化时发出通知
数据劫持的优势:
①不需要进⾏显示调⽤, vue 的双向绑定原理就是通过数据劫持 + 发布订阅来实现的,⽐如 angular
的脏检查需要通过显示调⽤ markForCheck , react 则需要通过 setState 来进⾏显示调⽤
②通过属性的劫持可以精准获得变化的内容,这部分不需要额外的 diff 操作,减少性能消耗
proxy相较于object.defineProperty的优势
直接监听对象⽽⾮属性
直接监听数组的变化
拦截⽅式较多(有 13 种⽅式)
Proxy 返回⼀个新对象,可以只操作新对象达到⽬的,⽽ Object.defineProperty 只能遍历对象属性
直接修改(需要⽤深拷⻉进⾏修改)
Proxy 作为新标准将受到浏览器⼚商重点持续的性能优化
不知道⼤家有这样的疑问没?既然 proxy 作为 ES6 的语法并且还有这么多的优点,
为啥不在之前 2.X 版本中就⽤ Proxy?(ES6 可⽐ vue2.0 版本出现的早哈 )
4. VUEX 原理及各个属性
多个组件共享数据或者是跨组件传递数据时
有五种,分别是State , Getter , Mutation , Action , Module (就是mapAction)
1. state:vuex的基本数据,用来存储变量
2. geeter:从基本数据(state)派生的数据,相当于state的计算属性
3. mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)。
每个mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。
回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。
4. action:和mutation的功能大致相同,不同之处在于 ==》 Action 提交的是 mutation,而不是直接变更状态。
action 可以包含任意异步操作。(类似于装饰器-(用来注释或修改类和类方法)->装饰器大大提高了代码的简洁性和可读性。)
5. modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
辅助函数
Vuex提供了mapState、MapGetters、MapActions、mapMutations等辅助函数给开发在vm中处理store
HTTP和TCP的不同
性质不同:
http是一个简单的请求-响应协议。TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议。
TCP:传输控制协议,是传输层的协议,以IP协议为基础
Http协议是建立在TCP协议基础之上的。当浏览器需要从服务器 获取网页数据的时候,会发出一次http请求。
Http通过TCP建立起一个到服务器的通道。
连接不同:
TCP连接到不同但互连的计算机通信网络的主计算机中的成对进程之间依靠TCP提供可靠的通信服务。http通常运行在TCP之上。
指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
功能不同:
当应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,TCP则把数据流分割成适当长度的报文段,
最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制。HTTP协议是基于请求/响应范式的。
JSONP的原理
基本原理:主要就是利用 script 标签的src属性没有跨域的限制,通过指向一个需要访问的地址,
由服务端返回一个预先定义好的 Javascript 函数的调用,并且将服务器数据以该函数参数的形式传递过来,此方法需要前后端配合完成。
执行过程:
前端定义一个解析函数(如: jsonpCallback = function (res) {})
通过params的形式包装script标签的请求参数,并且声明执行函数(如cb=jsonpCallback)
后端获取到前端声明的执行函数(jsonpCallback),并以带上参数且调用执行函数的方式传递给前端
前端在script标签返回资源的时候就会去执行jsonpCallback并通过回调函数的方式拿到数据了。
缺点:
只能进行GET请求
优点:
兼容性好,在一些古老的浏览器中都可以运行
requestAnimationFrame有了解过吗?
requestAnimationFrame是浏览器用于定时循环操作的一个接口,类似于setTimeout,主要用途是按帧对网页进行重绘。
对于JS动画,用requestAnimationFrame 会比 setInterval 效果更好。
TCP和UDP的区别
TCP/IP协议集包括应用层,传输层,网络层,网络访问层。
TCP/IP 中有两个具有代表性的传输层协议,分别是 TCP 和 UDP。
TCP是一个面向连接的、可靠的、基于字节流的传输层协议。
UDP是一个面向无连接的传输层协议。
TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复
对系统资源的要求(TCP较多,UDP少);
UDP程序结构较简单;
什么是虚拟dom
虚拟dom本质上就是一个普通的JS对象,用于描述视图的界面结构
在vue中,每个组件都有一个render函数,每个render函数都会返回一个虚拟dom树,这也就意味着每个组件都对应一棵虚拟DOM树
为什么需要虚拟dom?
在vue中,渲染视图会调用render函数,这种渲染不仅发生在组件创建时,同时发生在视图依赖的数据更新时。
如果在渲染时,直接使用真实DOM,由于真实DOM的创建、更新、插入等操作会带来大量的性能损耗,从而就会极大的降低渲染效率。
CommonJs和ES6 module的区别是什么呢?
ES6 module是编译时加载,输出的是接口,CommonJS运行时加载,加载的是一个对象
CommonJs导入的模块路径可以是一个表达式,因为它使用的是require()方法;而ES6 Modules只能是字符串
CommonJS this指向当前模块,ES6 Modules this指向undefined
且ES6 Modules中没有这些顶层变量:arguments、require、module、exports、__filename、__dirname
盒子模型
盒模型的组成:content(内容区)+padding(填充区)+border(边框区)+margin(外界区)。
JavaScript之AMD,CMD规范
浏览器的执行不能是同步执行的,必须是异步的,这里不得不提出AMD。AMD(Asynchronous Module Definition),意思就是"异步模块定义"。
AMD跟CommonJS一样也是通过require来导入,但是区别在于多了一个回调参数。用于导入后执行函数。
JS 原生你了解多少?
1. 数据类型{Number,String,Boolean,Null,Undefined}.
Null 与 Undefined 之间的区别
Undefined类型只有一个值,即undefined。当声明的变量还未被初始化时,变量的默认值为undefined。
Null类型也只有一个值,即null。null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象。
2. 运算{+,-,*,/,&&,||,++,--}
‘&&’两个表达式 都为真,最后结果才是true;有一个是假的,结果就是false。 一假即假,
‘||’只要有一个表达式为真,最后结果即为真。 一真即真
3. 对象、(普通对象,数组对象,)
4. Function、
5. 继承、{1. 原型链继承,2. 借用构造函数继承(伪造对象、经典继承),3. 实例继承(原型式继承),4. 组合式继承
5. 寄生组合继承,6. es6继承}
(1.子类实例共享父类引用属性的问题,2.创建子类实例时,可以向父类传递参数)
//class 相当于es5中构造函数
//class中定义方法时,前后不能加function,全部定义在class的protopyte属性中
//class中定义的所有方法是不可枚举的
//class中只能定义方法,不能定义对象,变量等
//class和方法内默认都是严格模式
//es5中constructor为隐式属性
es6继承--常用--
class People{
constructor(name='wang',age='27'){
this.name = name;
this.age = age;
}
eat(){
console.log(this.name , this.age})
}
}
//继承父类
class Woman extends People{
constructor(name = 'ren',age = '27'){ //原型链继承
//继承父类属性
super(name, age);
}
eat(){
//继承父类方法
super.eat()
}
}
let wonmanObj=new Woman('xiaoxiami');
wonmanObj.eat();
ES5继承和ES6继承的区别:
1. es5继承首先是在子类中创建自己的this指向,最后将方法添加到this中
2. Child.prototype=new Parent() || Parent.apply(this) || Parent.call(this)
3. es6继承是使用关键字先创建父类的实例对象this,最后在子类class中修改this
6. 闭包、
1. 函数嵌套函数,内部函数可以引用外部函数的参数和变量
2. 参数和变量不会被垃圾回收机制所收回.导致内存占用过多
7. 作用域、
1.作用域是可访问变量的集合。
2.使用var声明的变量,其作用域为该语句所在的函数内,且存在变量提升现象;只有全局作用域和函数作用域概念,
3.使用let声明的变量,其作用域为该语句所在的代码块内,不存在变量提升;-只有块级作用域的概念
4.使用const声明的是常量,在后面出现的代码中不能再修改该常量的值。
const定义的基本类型不能改变,但是定义的对象是可以通过修改对象属性等方法来改变的。
8. 原型链、
9. 事件、RegExp、JSON、Ajax、DOM、BOM、内存泄漏、
跨域、异步装载、模板引擎、前端MVC、路由、模块化、Canvas、ECMAScript
js把两个对象合并成一个对象
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
instanceof作用
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
js函数形参和实参的区别
声明函数add时,a,b就是形参。调用函数add(1,2) 1,2就是实参。
function add(a,b) { //a,b就是形参。
return a + b
};
add(1,2); //1,2就是实参
webpack 配置各个方法代表的是什么?
1.mode方法--
2.entry方法 -- 入口文件
entry: {
app: ['./src/index.js']
},
3.output方法
output: {
path: path.resolve(process.cwd(), './lib'), // 输出文件的目录,是个绝对路径
publicPath: '/dist/', // 所有静态资源都会加上这个前缀 比如 images/a.png -> /dist/images/a.png
filename: '[name].min.js', // 打完包的入口文件, 入口文件名.min.js
chunkFilename: '[id].js', // 非入口文件,按这种方式输出文件 0.js, 1.js ...
libraryTarget: 'umd', // 和 library配合使用,规定你的代码打包成的模块,可以用什么规范导入,这里可以用umd方式导入,即CommonJS, AMD 或者全局变量方式导入
libraryExport: 'default', // 哪些子模块需要被导出。libraryTarget 支持 commonjs才有意义,这里只导出default子模块。
library: 'ELEMENT', // 导出的模块名
umdNamedDefine: true, // 是否将模块名称作为 AMD 输出的命名空间
globalObject: 'typeof self !== \'undefined\' ? self : this' // 如果输出全局对象的话,绑定到这个对象上比如 self.ELEMENT 或者 this.ELEMENT
},
4.resolve 方法
resolve: {
extensions: ['.js', '.vue', '.json'], // 导入文件时,不带扩展名,会依次按这几个扩展名找
alias: config.alias // 创建 import 或 require 的别名,来确保模块引入变得更简单, 比如import 'element-ui' 就相当于 import 'element-ui在项目下的路径'
},
5. externals 方法 --如果我们想引用一个库,但是又不想让webpack一起打包,就用externals
externals: {
"lodash": {
commonjs: "lodash",//如果我们的库运行在Node.js环境中,import _ from 'lodash'等价于const _ = require('lodash') 转成异步加载
commonjs2: "lodash",//同上
amd: "lodash",//如果我们的库使用require.js等加载,等价于 define(["lodash"], factory);
root: "_"//如果我们的库在浏览器中使用,需要提供一个全局的变量‘_’,等价于 var _ = (window._) or (_);
}
}
6. optimization -- 代码优化,减少体积等
optimization: {
minimizer: [ // 定制压缩选项
new TerserPlugin({
terserOptions: {
output: {
comments: false // 去掉注释
}
}
})
]
},
7.performance --打包时性能提示的相关配置
performance: {
hints: false // 不提示 可选值 false | "error" | "warning", 如果开启,一个资源大于 250kb 就会有提示
},
8.stats -- 打包过程中,控制台输出信息的配置。参数比较多,官方文档定义也比较清楚,有需要可查阅
stats: {
children: false // 不显示子信息,这个子信息是什么,还不清楚,可以分别打开,关闭测试下
},
9.module -- 创建模块时,匹配请求的规则数组。这些规则能够修改模块的创建方式。这些规则能够对模块(module)应用 loader,或者修改解析器(parser)。
module: {
rules: [
{
test: /\.(jsx?|babel|es6)$/, // resource 条件1
include: process.cwd(), // resource 条件2
exclude: config.jsexclude, // resource 条件3
loader: 'babel-loader' // 匹配成功的结果
},
{
test: /\.vue$/, resource 条件1
loader: 'vue-loader', // 匹配成功的结果, 应用vue-loader
options: {
compilerOptions: {
preserveWhitespace: false // 忽略模版中HTML标签间的空格
}
}
}
]
},
10.plugins
plugins: [
new webpack.DefinePlugin({
// 允许你创建可在编译时配置的全局常量。这对需要在开发环境构建和生产环境构建之间产生不同行为来说非常有用。
// Definitions...
}),
new ProgressBarPlugin(), // 打包编译时,显示进度条
new VueLoaderPlugin() // 为vue-loader服务
]
什么是vue-loader?
Vue-loader 是 Webpack 的加载器模块,它使我们可以用 .vue 文件格式编写单文件组件。
他就是基于webpack的一个的loader,解析和转换 .vue 文件,
提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,
再分别把它们交给对应的 Loader 去处理,核心的作用,就是提取,划重点。
单文件组件文件有三个部分,即模板、脚本和样式。
vue-loader 模块允许 webpack 使用单独的加载器模块(例如 SASS 或 SCSS 加载器)提取和处理每个部分。该设置使我们可以使用
vue 文件无缝编写程序。
vue-loader 模块还允许把静态资源视为模块依赖性,并允许使用 webpack 加载器进行处理。而且还允许在开发过程中进行热重装。
less 和 sass区别
Sass的缩排语法,对于写惯css前端的web开发者来说很不直观,也不能将css代码加入到Sass里面,
因此Sass语法进行了改良,Sass 3就变成了Scss(Sassy CSS)。SCSS(Sassy CSS)是CSS语法的扩展。
这意味着每一个有效的CSS也是一个有效的SCSS语句,与原来的语法兼容,只是用{}取代了原来的缩进。
Less也是一种动态样式语言. 对CSS赋予了动态语言的特性,如变量,继承,运算, 函数.
Less 既可以在客户端上运行 (支持IE 6+, Webkit, Firefox),也可在服务端运行 (借助 Node.js)。
结构清晰,便于扩展。 可以方便地屏蔽浏览器私有语法差异。封装对浏览器语法差异的重复处理, 减少无意义的机械劳动。
可以轻松实现多重继承。 完全兼容 CSS 代码,可以方便地应用到老项目中。LESS 只是在 CSS 语法上做了扩展,
所以老的 CSS 代码也可以与 LESS 代码一同编译。
《img》的title和alt有什么区别
alt是图片加载失败时,显示在网页上的替代文字;
title是鼠标放上面时显示的文字。
alt是img必要的属性,而title不是。
常见图片格式BMP、JPG/JPEG、PNG、GIF、TIFF、SVG的区别
CSS position定位(5种方式)
静态定位:static,
相对定位:relative,
绝对定位:absolute,
固定定位:fixed,
粘性定位:sticky
css - 伪类
":link": a标签还未被访问的状态;
":visited": a标签已被访问过的状态;
":hover": 鼠标悬停在a标签上的状态;
":active": a标签被鼠标按着时的状态;
伪类和伪元素区别有哪些?
使用方法不同:css3规范中要求使用双冒号(::)表示伪元素,以此来区分伪类和伪元素,
比如::before和::after等伪元素使用双冒号(::),
:hover和:active伪类使用单冒号(:)目前来看有一部分浏览器为了达到一个更好的兼容性的问题,我们的双冒号也可以写成单冒号;
但是在一些低版本浏览器里面有些时候还是需要使用双冒号的
伪元素
:before
:after
rem和em的区别
em和rem的主要区别是:浏览器根据谁来转化成px。
当使用rem的时候,他们转化为像素的大小取决于页根元素的字体大小,即html元素的字体大小。
例如:根元素的字体大小为16px,10rem将等于160px,即10*16=160。
get 和 post的区别
vue 的生命周期
beforeCreat() 创建前 在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。
在此生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法
created()被创建 data 和 methods都已经被初始化好了,可以调用了
beforeMount() 挂载前 在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的
mounted()已挂载 Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。
如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行
beforeupdate()更新前 页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步
updated()更新 页面显示的数据和data中的数据已经保持同步了,都是最新的
beforeDestroy() 销毁前 Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods ,
指令, 过滤器 ……都是处于可用状态。还没有真正被销毁
destroyed()被销毁 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。
vue3改了4个生命周期函数。Vue3组合式api取消了beforeCreated和created钩子函数,
采用steup钩子代替,且里面不能使用this。Vue3里面的组件销毁的钩子函数由destroyed和beforeDestroy换成了beforeUnmount和unmounted。
生命周期是什么?
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,
我们称这是 Vue 的生命周期。
Vue生命周期钩子函数hook解析
hook其实就是一种回调函数,只不过这种回调函数的名称已经被固定,内容不固定,
且函数名称作为了一个接口被暴露出去。这样也更好了进行了抽象化:将经常变化的内容抽象暴露出去,将固定不变的代码进行封装。
JS中BOM和DOM的区别与联系
1. DOM 是 W3C 的标准; [所有浏览器公共遵守的标准]
2. BOM 是 各个浏览器厂商根据 DOM 在各自浏览器上的实现;[表现为不同浏览器定义有差别,实现方式不同]
3. window 是 BOM 对象,而非 js 对象;
4. BOM 主要处理浏览器窗口和框架,不过通常浏览器特定的 JavaScript 扩展都被看做 BOM 的一部分。
<keep-alive 是什么
负载均衡
<keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。
它能够不活动的组件实例保存在内存中,而不是直接将其销毁,它是一个抽象组件,不会被渲染到真实DOM中,也不会出现在父组件链中。
一般结合路由和动态组件一起使用,用于缓存组件;
提供 include 和 exclude 属性,两者都支持字符串或正则表达式,
include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,
其中 exclude 的优先级比 include 高;
对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,
当组件被移除时,触发钩子函数 deactivated。
协商缓存
首先从缓存的类型上来说, 可以分为两种: 强缓存与协商缓存.
强缓存是不需要发送HTTP请求的, 而协商缓存需要.
也就是在发送HTTP请求之前, 浏览器会先检查一下强缓存, 如果命中直接使用,否则就进入下一步。
Last-Modefied配合If-Modified-Since
HTTP中的Keep-Alive有了解过吗?
Keep-Alive是HTTP的一个头部字段Connection中的一个值,它是保证我们的HTTP请求能建立一个持久连接。
也就是说建立一次TCP连接即可进行多次请求和响应的交互。它的特点就是只要有一方没有明确的提出断开连接,
则保持TCP连接状态,减少了TCP连接和断开造成的额外开销。
跨域有了解吗?如何解决跨域?
什么是跨域?
指协议、域名、端口
为什么要跨域?
浏览器设置了同源策略,当页面执行脚本的时候,浏览器会检查访问的资源是否同源,如果不是,就会报错
前端安全方面?XSS?CSRF?
XSS(Cross Site Script)跨站脚本攻击。指的是攻击者向网页注入恶意的客户端代码,通过恶意的脚本对客户端网页进行篡改,
从而在用户浏览网页时,对用户浏览器进行控制或者获取用户隐私数据的一种攻击方式。
主要是分为三种:
存储型:即攻击被存储在服务端,常见的是在评论区插入攻击脚本,如果脚本被储存到服务端,那么所有看见对应评论的用户都会受到攻击。
反射型:攻击者将脚本混在URL里,服务端接收到URL将恶意代码当做参数取出并拼接在HTML里返回,浏览器解析此HTML后即执行恶意代码
DOM型:将攻击脚本写在URL中,诱导用户点击该URL,如果URL被解析,那么攻击脚本就会被运行。和前两者的差别主要在于DOM型攻击不经过服务端
如何防御XSS攻击
输入检查:对输入内容中的script和<iframe>等标签进行转义或者过滤
设置httpOnly:很多XSS攻击目标都是窃取用户cookie伪造身份认证,设置此属性可防止JS获取cookie
开启CSP,即开启白名单,可阻止白名单以外的资源加载和运行
vue 路由跳转的三种方式
1、router-link 【实现跳转最简单的方法】 //将它解析成一个类似于<a> 的标签。
2、this.$router.push({ path:’/user’}) //常用于路由传参
3、this.$router.replace{path:‘/’ }类似,不再赘述 // 可以传参数,又可以跳路由
数组方法pop() push() unshift() shift()
push()尾部添加 pop()尾部删除 unshift()头部添加 shift()头部删除
v-for中为什么要用key
为了更好地区别各个组件 key的作用主要是为了高效的更新虚拟DOM。
this 指向问题
1 普通函数内部的this分两种情况,严格模式和非严格模式。非严格模式下,this 默认指向全局对象
2 如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,
这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。
this 是什么?
JavaScript this 关键词指的是它所属的对象。
它拥有不同的值,具体取决于它的使用位置:
在方法中,this 指的是所有者对象。
单独的情况下,this 指的是全局对象。
在函数中,this 指的是全局对象。
在函数中,严格模式下,this 是 undefined。
在事件中,this 指的是接收事件的元素。
像 call() 和 apply() 这样的方法可以将 this 引用到任何对象。
vue 中data为什么是以函数形式存在
因为我们能抽离出来的组件,肯定是具有复用性的,它在项目中会存在多个实例。
如果data属性值是一个对象时,那么它所有的实例都会共享这些数据,这是很麻烦的事情,
你不能确保你的所有实例中的属性值都不会重复。
我们的期望是,组件的每个实例都能独立的维护自己的数据
为什么说script标签建议放在body下面?
JS代码在加载完之后是立即执行的,且JS代码执行时会阻塞页面的渲染。
javascript中apply、call和bind的区别
call 是传入每一个参数,apply是参数数组 都是改变this的指向
bind 和 call/apply 的区别
是否立刻执行:
call/apply 改变了函数的 this 上下文后 马上 执行该函数。
bind 则是返回改变了上下文后的函数, 不执行该函数 。
返回值的区别:
call/apply 返回 fun 的执行结果。
bind 返回 fun 的拷贝,并指定了 fun 的 this 指向,保存了 fun 的参数。
Promise的三种状态
pending - 进行中
fulfilled - 成功
rejected - 失败
什么是插槽 slot
插槽就是子组件中的提供给父组件使用的一个占位符,用<slot></slot> 表示,
父组件可以在这个占位符中填充任何模板代码
什么是js的回调地狱?为什么会引发回调地狱?如何解决回调地狱问题
js的回调地狱:根据外层ajax请求的结果,将结果作为参数继续发起ajax请求
function doTask1() {
return new Promise((resolve) => {
setTimeout(() => resolve("Task 1 complete"), 1000);
});
}
function doTask2(result1) {
return new Promise((resolve) => {
setTimeout(() => resolve(result1 + " -> Task 2 complete"), 1000);
});
}
function doTask3(result2) {
return new Promise((resolve) => {
setTimeout(() => resolve(result2 + " -> Task 3 complete"), 1000);
});
}
doTask1().then((result1) => doTask2(result1)).then((result2) => doTask3(result2)).then((result3) => console.log(result3));
css 变量
:root {
--blue: #6495ed;
--white: #faf0e6;
}
body { background-color: var(--blue); }
h2 { border-bottom: 2px solid var(--blue); }
块级元素
<div>
<h1> - <h6>
<p>
<form>
<header>
<footer>
<section>
行内元素
<span>
<a>
<img>
position 定位
static // 默认值 // 即没有定位,遵循正常的文档流对象
relative // 相对定位元素
fixed // 元素的位置相对于浏览器窗口是固定位置。
absolute //绝对定位的元素的位置相对于最近的已定位父元素
sticky // 基于用户的滚动位置来定位
Vue 中query和params的区别
query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
1、query 传参:
this.$router.push({
path:'/xxx',
query:{
id:id
}
})
接收参数:
this.$route.query.id
2、params 传参:
this.$router.push({
name:'xxx',
params:{
id:id
}
})
接收参数:
this.$route.params.id
params传参,push里面只能是 name:'xxxx',不能是path:'/xxx',
因为params只能用name来引入路由,如果这里写成了path,接收参数页面会是undefined。
2. query传参
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
// html 取参 $route.query.id
// script 取参 this.$route.query.id
3. params传参
this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
Vue中组件通信 兄弟传参(eventBus)
Vue.js中 watch(深度监听)
watch: {
firstName: {
handler(newName, oldName) {
this.fullName = newName + ' ' + this.lastName;
},
// 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法
immediate: true
}
}
注意到handler了吗,我们给 firstName 绑定了一个handler方法,
之前我们写的 watch 方法其实默认写的就是这个handler,Vue.js会去处理这个逻辑,最终编译出来其实就是这个handler
deep属性
watch 里面还有一个属性 deep,默认值是 false,代表是否深度监听,比如我们 data 里有一个obj属性:
<div>
<p>obj.a: {{obj.a}}</p>
<p>obj.a: <input type="text" v-model="obj.a"></p>
</div>
new Vue({
el: '#root',
data: {
obj: {
a: 123
}
},
watch: {
obj: {
handler(newName, oldName) {
console.log('obj.a changed');
},
immediate: true
}
}
})
set 集合
Set 是唯一值的集合。
每个值在 Set 中只能出现一次。
一个 Set 可以容纳任何数据类型的任何值。
vue-router 是什么?它有哪些组件
https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dbc632da4d344c21bcf4a51eed789f2f~tplv-k3u1fbpfcp-zoom-in-crop-mark:3024:0:0:0.awebp
1, route,它是一条路由,由这个英文单词也可以看出来,它是单数, Home按钮 => home内容, 这是一条route, about按钮 => about 内容, 这是另一条路由。
2, routes 是一组路由,把上面的每一条路由组合起来,形成一个数组。[{home 按钮 =>home内容 }, { about按钮 => about 内容}]
3, router 是一个机制,相当于一个管理者,它来管理路由。因为routes 只是定义了一组路由,它放在哪里是静止的,当真正来了请求,怎么办? 就是当用户点击home 按钮的时候,怎么办?这时router 就起作用了,它到routes 中去查找,去找到对应的 home 内容,所以页面中就显示了 home 内容。
4,客户端中的路由,实际上就是dom 元素的显示和隐藏。当页面中显示home 内容的时候,about 中的内容全部隐藏,反之也是一样。客户端路由有两种实现方式:基于hash 和基于html5 history api.
路由跳转等都需要vue-router
active-class 属于哪个组件中的属性?该如何使用?
active-class 属于vue-router的样式方法,当router-link标签被点击时将会应用这个样式
一、首先,active-class是什么,
active-class是vue-router模块的router-link组件中的属性,用来做选中样式的切换;
相关可查阅文档:https://router.vuejs.org/zh-cn/api/router-link.html
二、在vue-router中要使用active-class有两种方法:
1、直接在路由js文件中配置linkActiveClass
export default new Router({
linkActiveClass: ‘active’,
})
2、在router-link中写入active-class
首页
三、最近在项目中出现一个问题,使用第二种方法添加active-class,跳转到my页面后,两个router-link始终都会有选中样式,代码如下
首页
我的
四、后来发现是因为 to="/" 引起的,active-class选择样式时根据路由中的路径去匹配,然后显示,
例如在my页面中,路由为 ,那么to="/”和to="/my"都可以匹配到,所有都会激活选中样式
五、要解决问题也有两种方式,都是通过加入一个exact属性
1、直接在路由js文件中配置linkActiveClass
export default new Router({
linkExactActiveClass: ‘active’,
})
2、在router-link中写入exact
首页
六、不过我不是用exact这种方法去解决的,我的方法是
首页
路由中加入重定向
{
path: ‘/’,
redirect: ‘/home’
怎么定义vue-router的动态路由?怎么获取传过来的动态参数?
可以通过query ,param两种方式
区别: query通过url传参,刷新页面还在 params刷新页面不在了
Vue中hash模式和history模式的区别
最明显的是在显示上,hash模式的URL中会夹杂着#号,而history没有。
Vue底层对它们的实现方式不同。hash模式是依靠onhashchange事件(监听location.hash的改变),
而history模式是主要是依靠的HTML5 history中新增的两个方法,pushState()可以改变url地址且不会发送请求,
replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。
当真正需要通过URL向后端发送HTTP请求的时候,比如常见的用户手动输入URL后回车,
或者是刷新(重启)浏览器,
这时候history模式需要后端的支持。
因为history模式下,前端的URL必须和实际向后端发送请求的URL一致,
例如有一个URL是带有路径path的(例如www.lindaidai.wang/blogs/id),如果后端没有对这个路径做处理的话,就会返回404错误。
所以需要后端增加一个覆盖所有情况的候选资源,一般会配合前端给出的一个404页面。
vue-router 有哪几种导航钩子?
三种导航钩子:
1.全局导航钩子:router.beforeEach(to,from,next) 作用:跳转前进行判断拦截
2.组件内的钩子
3.单独路由独享组件
答案2:
共有三种守卫:
1:全局守卫:beforeEach,afterEach
2:路由独享守卫:beforeEnter
3:组件级别的守卫beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
他们执行顺序:全局》路由》组件
除了afterEach全局后置外,其他的守卫中务必要调用next(),否则无法完成导航
还有注意全局前置守卫可以用来进行拦截,(登录拦截)
route和router的区别详解
$ router是用来操作路由的,$ route是用来获取路由信息的。
1.$router是VueRouter的一个实例,他包含了所有的路由,包括路由的跳转方法,钩子函数等,也包含一些子对象(例如history)
vue-router响应路由参数的变化
当使用路由参数时,例如从 /user/aside导航到 /user/foo,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
注意:
(1)从同一个组件跳转到同一个组件。
(2)生命周期钩子created和mounted都不会调用。
可以使用router的组件内钩子函数
beforeRouteUpdate(to,from,next){
//在这个钩子函数中:to表示将要跳转的路由对象,from表示从哪个路由跳转过来,next多数就是需要调用
//created和mounted不调用,无法拿到需要的动态值,就通过to.path,to.params等
//可以在这个函数中打印to,具体看to对象有什么可以使用的属性
}
添加watch监听
Vue 路由router的两种模式
vue中router可以设两种模式:hash和history。设置方式就是代码中注释的部分
vue-router实现路由懒加载( 动态加载路由 )
浏览器输入url加载过程
1.首先输入url
2.查找缓存
3.DNS域名解析,解析其中对应ip,如果有继续,
4.建立TCP连接
5.发起HTTP请求
6.服务器返回结果
7.渲染DOM树,构建CSS布局,
8.js引擎加载文件
浏览器重绘和重排的区别
重排:浏览器重新计算元素属性,将其安放在界面的正确位置,这个过程叫重排
重绘:当元素外观发生变化,但没有改变布局,把元素重新绘制出来的过程叫重绘
vue是如何实现响应式数据的呢?(响应式数据原理)
Vue2: Object.defineProperty 重新定义 data 中所有的属性,
Object.defineProperty 可以使数据的获取与设置增加一个拦截的功能,拦截属性的获取,进行依赖收集。
拦截属性的更新操作,进行通知。
具体的过程:首先Vue使用 initData 初始化用户传入的参数,然后使用 new Observer 对数据进行观测,
如果数据是一个对象类型就会调用 this.walk(value) 对对象进行处理,内部使用 defineeReactive
循环对象属性定义响应式变化,核心就是使用 Object.defineProperty 重新定义数据。
那vue中是如何检测数组变化的呢?
数组就是使用 object.defineProperty 重新定义数组的每一项,那能引起数组变化的方法我们都是知道的,
pop 、 push 、 shift 、 unshift 、 splice 、 sort 、 reverse 这七种,只要这些方法执行改了数组内容,
我就更新内容就好了,是不是很好理解
数组就是使用 object.defineProperty 重新定义数组的每一项,那能引起数组变化的方法我们都是知道的,
是用来函数劫持的方式,重写了数组方法,具体呢就是更改了数组的原型,更改成自己的,
用户调数组的一些方法的时候,走的就是自己的方法,然后通知视图去更新。
数组里每一项可能是对象,那么我就是会对数组的每一项进行观测,(且只有数组里的对象才能进行观测,观测过的也不会进行观测)
vue3:改用 proxy ,可直接监听对象数组的变化。
vue3:改用 proxy 好处
1、Proxy 可以直接监听对象而非属性;
2、Proxy 可以直接监听数组的变化;
3、Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是Object.defineProperty 不具备的;
4、Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
5、Proxy 作为新标准将受到浏览器厂商重点持续的性能优化,也就是传说中的新标准的性能红利;
为什么Vue采用异步渲染呢?
Vue 是组件级更新,如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染,所以为了性能,
Vue 会在本轮数据更新后,在异步更新视图。核心思想 nextTick 。
dep.notify() 通知 watcher进行更新, subs[i].update 依次调用 watcher 的 update , queueWatcher 将watcher 去重放入队列, nextTick( flushSchedulerQueue )在下一tick中刷新watcher队列(异步)。
了解nextTick吗?
异步方法,异步渲染最后一步,与JS事件循环联系紧密。主要使用了宏任务微任务(setTimeout、promise那些),
定义了一个异步方法,多次调用nextTick会将方法存入队列,通过异步方法清空当前队列。
父子组件生命周期调用顺序(简单)
渲染顺序:先父后子,完成顺序:先子后父
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
更新顺序:父更新导致子更新,子更新完成后父
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
销毁顺序:先父后子,完成顺序:先子后父
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
v-html 会导致哪些问题
XSS 攻击
(1)持久型跨站:最直接的危害类型,跨站代码存储在服务器(数据库)。
(2)非持久型跨站:反射型跨站脚本漏洞,最普遍的类型。用户访问服务器-跨站链接-返回跨站代码。
(3)DOM跨站(DOM XSS):DOM(document object model文档对象模型),客户端脚本处理逻辑导致的安全问题。
v-html 会替换标签内部的元素
浏览器垃圾回收机制
通常情况下有两种实现方式:标记清除和引用计数。引用计数不太常用,标记清除较为常用。
js中最常用的垃圾回收方式就是标记清除。
V8的垃圾回收是发生在什么时候?
V8引擎帮助我们实现了自动的垃圾回收管理,利用浏览器渲染页面的空闲时间进行垃圾回收。
link和@import的区别
两者都是外部引用CSS的方式,它们的区别如下:
link是XHTML标签,除了加载CSS外,还可以定义RSS等其他事务;@import属于CSS范畴,只能加载CSS。
link引用CSS时,在页面载入时同时加载;@import需要页面网页完全载入以后加载。
link是XHTML标签,无兼容问题;@import是在CSS2.1提出的,低版本的浏览器不支持。
link支持使用Javascript控制DOM去改变样式;而@import不支持。
vw,vh与 % 的区别是什么?
% 是基于【父元素】的宽度/高度的百分比,vw,vh是根据视窗的宽度/高度的百分比。
视口单位优势在于【vh】能够直接获取高度,而用 % 在没有设置 body 高度情况下,是无法正确获得可视区域的高度。
css3新特性
新增各种CSS选择器 (: not(.input):所有 class 不是“input”的节点)
圆角 (border-radius:8px)
多列布局 (multi-column layout)
阴影和反射 (Shadoweflect)
文字特效 (text-shadow)
文字渲染 (Text-decoration)
线性渐变 (gradient)
旋转 (transform)
增加了旋转,缩放,定位,倾斜,动画,多背景
::before 和 :after 的双冒号和单冒号有什么区别?
冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。
Vue3 中如何使用 provide 和 inject 实现依赖注入?它们的作用是什么?
provide 用于在上级组件中提供数据,
inject 用于在下级组件中注入数据,适用于跨组件传递数据而无需通过 props 和 emits。
// 父组件
import { provide } from 'vue';
export default {
setup() {
provide('message', 'Hello from parent');
}
}
// 子组件
import { inject } from 'vue';
export default {
setup() {
const message = inject('message');
console.log(message); // Hello from parent
}
}
ts部分
简单介绍一下 TypeScript 模块的加载机制?
假设有一个导入语句 import { a } from "moduleA";
1. 首先,编译器会尝试定位需要导入的模块文件,通过绝对或者相对的路径查找方式;
2. 如果上面的解析失败了,没有查找到对应的模块,编译器会尝试定位一个外部模块声明(.d.ts);
3. 最后,如果编译器还是不能解析这个模块,则会抛出一个错误 error TS2307: Cannot find module 'moduleA'.
tsc 执行TS文件
let a:any //不检查数据类型
let b:unknown //不知道类型
a as string //as断言 强制更改类型
never // 不能定义变量,限制函数返值 类型异常才会用
void 函数返回值声明 函数不返回任何值 为空