面试

31 阅读35分钟
cookielocalStoragesessionStorage
由谁初始化客户端或服务器,服务器可以使用 Set-Cookie 请求头。客户端客户端
过期时间手动设置永不过期当前页面关闭时
在当前浏览器会话(browser sessions)中是否保持不变取决于是否设置了过期时间
是否随着每个 HTTP 请求发送给服务器是,Cookies 会通过 Cookie 请求头,自动发送给服务器
容量(每个域名)4kb5MB5MB
访问权限任意窗口任意窗口当前页面窗口

项目难点:

CSS

1.css选择器优先级
伪类选择器,伪元素选择器,基本选择器,属性选择器,组合选择器

优先级:
!important > 内联 > ID选择器 > 类选择器 > 标签选择器 > 通用选择器(*)
1.什么是浮动?怎么清除浮动?
<style>
    #box1{
        width: 50px;
        height: 50px;
        background-color: #00B7FF;
    }
    #box2{
        width: 50px;
        height: 50px;
        background-color: red;
        float: left; // 浮动
    }
    #box3{
        width: 50px;
        height: 50px;
        background-color: yellow;
    }
</style>
<body>
    <div id="box1">box1</div>
    <div id="box2">box2</div>
    <div id="box3">box3</div>
</div>

效果:box2浮动,box3在box2下面(重叠),但是box3的文字仍然在box2之外的下面,浮动只是针对样式,文本无法重叠

清除浮动的方法:
1. 在最后一个浮动标签后,新加一个标签,给其设置clear: both(不推荐)
优点: 通俗易懂,方便
缺点:添加无意义标签,语义化差
<style>
    #box1{
        width: 50px;
        height: 50px;
        background-color: #00B7FF;
    }
    #box2{
        width: 50px;
        height: 50px;
        background-color: red;
        float: left; // 浮动
    }
    #clear{
    	clear:both
	}
    #box3{
        width: 50px;
        height: 50px;
        background-color: yellow;
    }
</style>
	<div>
    	<div id="box1">box1</div>
    	<div id="box2">box2</div>
		<div id="clear"></div>
    </div>
    <div id="box3">box3</div>
2.触发bfc——父元素添加overflow:hidden(不推荐)
优点:代码简洁
缺点:内容增多时无法显示被溢出的元素
3.使用after伪元素清除浮动(推荐使用)
优点:符合闭合浮动思想,结构语义化正确
缺点:ie6-7不支持伪元素:after,使用zoom:1触发hasLayout.
<style>
    #box1{
        width: 50px;
        height: 50px;
        background-color: #00B7FF;
    }
    #box2{
        width: 50px;
        height: 50px;
        background-color: red;
        float: left; // 浮动
    }
    #box:after{
    	content:"",
         display:block,
         clear:both
	}
    #box3{
        width: 50px;
        height: 50px;
        background-color: yellow;
    }
</style>
	<div id="box">
    	<div id="box1">box1</div>
    	<div id="box2">box2</div>
    </div>
    <div id="box3">box3</div>
1.有什么不同的方式可以隐藏内容
width: 0; height: 0:使元素不占用屏幕上的任何空间,导致不显示它。
position: absolute; left: -99999px:将它置于屏幕之外。
text-indent: -9999px:这只适用于block元素中的文本。
Metadata:例如通过使用 Schema.orgRDFJSON-LDWAI-ARIA:如何增加网页可访问性的 W3C 技术规范。
1.使用 CSS 预处理的优缺点分别是什么?
优点:
提高 CSS 可维护性。
易于编写嵌套选择器。
引入变量,增添主题功能。可以在不同的项目中共享主题文件。
通过混合(Mixins)生成重复的 CSS。
将代码分割成多个文件。不进行预处理的 CSS,虽然也可以分割成多个文件,但需要建立多个 HTTP 请求加载这些文件。

缺点:
需要预处理工具。
重新编译的时间可能会很慢。

JS

目标:

1.整理面试题

2.整理简历

3.熟悉简历项目

如何修改this指向?方法区别?
答:
1.call方法
let obj = {name:"123"};
function func(a, b){
    console.log(this);
    console.log(a + b);
}
func.call(obj, 1, 2)
//控制台打印结果
//this:obj {name: "123"};
// 3

func(1, 2);
//控制台打印结果
//windows 3

2.apply方法
let obj = {name:"123"};
function func(array){
    console.log(this);
    console.log(array);
}
let fn = func.apply(obj, ['123']);
fn();
//控制台打印结果
//this:obj {name: "123"};
// 123

var arr = [1, 66, 3, 99, 4];
var max = Math.max.apply(Math, arr); // 99
var min = Math.min.apply(Math, arr); // 1

3.bind方法
let obj = {name:"123"};
function func(a, b){
    console.log(this);
    console.log(a + b);
}
func.apply(obj, 1, 2);

//控制台打印结果
//this:obj {name: "123"};
// 3

区别:
call,apply需要去调用才会修改,使用bind方法编写后,不调用this指向已经修改;
call适用继承,apply适用数组计算(求最大值,最小值),bind适用只想修改this指向不需要调用
1.什么是闭包(closure),为什么使用闭包?
闭包是函数和声明该函数的词法环境的组合。词法作用域中使用的域,是变量在代码中声明的位置所决定的。闭包是即使被外部函数返回,依然可以访问到外部(封闭)函数作用域的函数。

为什么使用闭包?

利用闭包实现数据私有化或模拟私有方法。这个方式也称为模块模式(module pattern)。
部分参数函数(partial applications)柯里化(currying).
1.请尽可能详细地解释 AjaxAjax(asynchronous JavaScript and XML)是使用客户端上的许多 Web 技术,创建异步 Web 应用的一种 Web 开发技术。借助 AjaxWeb 应用可以异步(在后台)向服务器发送数据和从服务器检索数据,而不会干扰现有页面的显示和行为。通过将数据交换层与表示层分离,Ajax 允许网页和扩展 Web 应用程序动态更改内容,而无需重新加载整个页面。实际上,现在通常将 XML 替换为 JSON,因为 JavaScriptJSON 有原生支持优势。

XMLHttpRequest API 经常用于异步通信。此外还有最近流行的 fetch API。

优点
交互性更好。来自服务器的新内容可以动态更改,无需重新加载整个页面。
减少与服务器的连接,因为脚本和样式只需要被请求一次。
状态可以维护在一个页面上。JavaScript 变量和 DOM 状态将得到保持,因为主容器页面未被重新加载。
基本上包括大部分 SPA 的优点。

缺点
动态网页很难收藏。
如果 JavaScript 已在浏览器中被禁用,则不起作用。
有些网络爬虫不执行 JavaScript,也不会看到 JavaScript 加载的内容。
基本上包括大部分 SPA 的缺点
1.请解释变量提升(hoisting)
变量提升(hoisting)是用于解释代码中变量声明行为的术语。使用 var 关键字声明或初始化的变量,会将声明语句“提升”到当前作用域的顶部。 但是,只有声明才会触发提升,赋值语句(如果有的话)将保持原样。
1.请解释关于 JavaScript 的同源策略。
同源策略可防止 JavaScript 发起跨域请求。源被定义为 URI、主机名和端口号的组合。此策略可防止页面上的恶意脚本通过该页面的文档对象模型,访问另一个网页上的敏感数据。(协议,域名,端口号)
1.什么是原型?
答:
每个构造函数都有一个(原型对象)显示原型prototype,通过该构造函数new出来的实例对象上有一个隐式原型__proto__,指向的是该构造函数的显示原型prototype,显示原型上有一个constructor属性指向的是该构造函数本身。
原型链:
查找某个对象上的属性的路径就是原型链
1.作用域?作用域链?
作用域:通过声明定义的变量或者函数,在执行上下文中能够被访问到的范围,称为作用域。

全局作用域:任何不是在函数或者大括号能声明定义的变量或者函数,那么它的作用域就是全局作用域,能够在任意位置被访问

局部作用域:局部作用域又叫函数作用域,任何在函数内声明定义的变量或者函数,那么它的作用域就是局部作用域,只能在函数内被访问,函数外无法访问

块级作用域:任何在大括号内声明定义的变量或者函数,那么它的作用域就是块级作用域,只能在大括号内被访问,大括号外无法访问

作用域链:js查找某个标识符所形成的查找路径就是作用域链
1.js引擎如何实现异步的?
​ js引擎是通过事件循环(Event Loop)实现异步的

​ 什么是事件循环??

​ js引擎里面有两个非常重要的部分:执行栈和任务队列

所有的代码都要加载到执行栈里面进行执行,在执行过程中如果发现有异步任务,则js引擎会把这个异步任务交给浏览器的其他线程去处理,比如在执行的时候,遇到接口发送,则js引擎会把它交给http请求线程去处理,然后js引擎继续执行后边的同步任务,但是同http请求线程也在同时运作,当请求发送成功之后,即数据拿到之后,http请求线程会将我们之前在js里面设置的回调函数推送到js引擎的任务队列里面,当js引擎在执行栈里面把任务清空之后,则回到任务队列里面去寻找有没有待执行的回调函数,有则拿到执行栈里面去执行,执行完了之后,又会到任务队列里面去寻找有没有待执行的回调,如此循环往复的过程就是事件循环

  * 浏览器是多线程的,js引擎只是其中一个线程,除此之外还有http请求线程,定时触发线程,事件处理线程,GUI渲染线程

1.能说说你对宏任务 和 微任务 的理解吗?

js是一种单线程语言,只有一条通道,那么在任务多的情况下,就会出现堵塞,这种情况下就产生了 多线程,那么就产生了同步任务和异步任务。

同步任务: 在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。是由 js 执行栈/回调栈执行的

异步任务: 不进入主线程、而进入任务队列的任务,当主线程中的任务运行完成了,才会从任务队列中取出异步任务,放入主线程中执行

微任务和宏任务都是异步任务,它们都属于一个队列

宏任务:script、setTimeoutsetInterval、postMessage、MessageChannel、及Node.js 环境中的setImmediate.
微任务:Promise.thenObject.observeMutationObserver、及Node.js 环境中的process.nextTick.

执行顺序就为: 同步任务 ---> 微任务 ---> 宏任务

区别:
首先,宏任务和微任务的执行时机是不同的。
宏任务会在主线程执行完毕后被执行,而微任务会在主线程执行完毕之前立即执行。
其次,宏任务和微任务的优先级也是不同的。在 JavaScript 中,微任务的优先级比宏任务高,也就是说,如果微任务队列和宏任务队列中都有任务需要执行,微任务会先于宏任务执行。
另外,宏任务和微任务对于 JavaScript 事件循环的影响也是不同的。宏任务会触发事件循环,而微任务不会触发事件循环,而是在主线程上的同步任务执行完毕后立即执行。
此外,宏任务和微任务在实际应用中有着不同的用途。宏任务通常用于与浏览器渲染相关的任务,如 setTimeout 和 requestAnimationFrame,而微任务通常用于异步操作,如 Promise.thenasync/await
1.防抖和节流有什么区别,如何实现
​ 在高频触发的事件中,可能会导致一些性能问题,比如在PC端浏览器缩放时(resize事件),我们在事件处理函数里面如果操作DOM,则用户缩放的时候,可能会导致浏览器卡顿,这是我们就可以通过防抖节流来控制操作DOM的频率,避免过快的操作DOM,但是这两者的区别在于:

​ 防抖的思路是:设置一个延时器,延时n秒在执行相应的逻辑(即频繁执行可能会影响性能的逻辑),如果在n秒内,再次执行了,则清空延时器,并从当下开始从新设置延时器,n秒后再执行。

​ 节流的思路是:在特定的时间段内,相应的逻辑必须有且只能执行一次。
//防抖
function debunce(func,time){
	let timer = null;
	return function(){
		if(timer)clearInterval(timer);
		timer = setTimeout(()=&gt;{
			func.apply(this,arguments)
		},time);
	}
}
//节流
function throttle(func,time){
	let preTime = +new Date()
	return function(){
		const curTime = +new Date()
		if(curTime - preTime &gt;= time){
			func.apply(this,arguments);
			preTime = curTime;
		}
	}
}

WebPack

1.什么是webpack?
webpack 是一个模块打包器。webpack 的主要目标是将 JavaScript 文件打包在一起,打包后的文件用于在浏览器中使用,但它也能够胜任转换(transform)、打包(bundle)。

2.原理?
entry:一个可执行模块或者库的入口。
chunk:多个文件组成一个代码块。可以将可执行的模块和他所依赖的模块组合成一个chunk,这是打包。
loader:文件转换器。例如把es6转为es5,scss转为css等
plugin:扩展webpack功能的插件。在webpack构建的生命周期节点上加入扩展hook,添加功能。
output:编译结果文件输出

Webpack 的运⾏流程是⼀个串⾏的过程,从启动到结束会依次执⾏以下流程:

初始化参数:解析webpack配置参数,合并shell传入和webpack.config.js文件配置的参数,形成最后的配置结果。
开始编译:上一步得到的参数初始化compiler对象,注册所有配置的插件,插件监听webpack构建生命周期的事件节点,做出相应的反应,执行对象的 run 方法开始执行编译。
确定入口:从配置的entry入口,开始解析文件构建AST语法树,找出依赖,递归下去。
编译模块:递归中根据文件类型和loader配置,调用所有配置的loader对文件进行转换,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
完成模块编译:在经过第4步使⽤ Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
输出资源:根据⼊⼝和模块之间的依赖关系,组装成⼀个个包含多个模块的 Chunk,再把每个 Chunk 转换成⼀个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会;
输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统。


3.vite和webpack的区别?(vite是未来趋势,最火)

Webpack 是一个打包模块化 JavaScript 的工具,在 Webpack 里一切文件皆模块,通过 Loader 转换文件,通过 Plugin 注入钩子,最后输出由多个模块组合成的文件。Webpack 专注于构建模块化项目。
一切文件:JavaScriptCSSSCSS、图片、模板,在 Webpack 眼中都是一个个模块,这样的好处是能清晰的描述出各个模块之间的依赖关系,以方便 Webpack 对模块进行组合和打包。 经过 Webpack 的处理,最终会输出浏览器能使用的静态资源。因此每次编译都需要重新构建。

vite主要遵循的是使用ESM(Es modules模块)的规范来执行代码,由于现代浏览器基本上都支持了ESM规范,所以在开发阶段并不需要将代码打包编译成es5模块,即可直接在浏览器上运行。我们只需要从入口文件出发, 在遇到对应的 import 语句时,将对应的模块加载到浏览器中就可以了。当项目越大,文件越多时,vite的开发时优势越明显。vite热更新比webpack,vite在HRM方面,当某个模块内容改变时,让浏览器直接重新请求该模块即可,而不是像webpack重新将该模块的所有依赖重新编译。
Vite的使用简单,只需执行初始化命令,就可以得到一个预设好的开发环境,开箱即获得一堆功能,包括:CSS预处理、html预处理、异步加载、分包、压缩、HMR等。使用复杂度介于ParcelWebpack的中间,只是暴露了极少数的配置项和plugin接口,既不会像Parcel一样配置不灵活,又不会像Webpack一样需要了解庞大的loader、plugin生态,灵活适中、复杂度适中。
总体来说,Vite在前端构建工具领域上开辟了一条和webpack完全不同的道路,很好地解决了前端开发阶段构建速度慢的问题。

VUE

1.v-if和v-show的区别?
答:
v-if和v-show都是用来控制元素显隐的;
区别:
v-if是通过判断来控制整个DOM的创建和删除
v-show是通过判断来给DOM元素添加display:none的样式

总结:
如果DOM的显隐状态频繁切换,使用v-show,否则v-if

1.常用的vue内部指令?
答:
v-model:
双向绑定数据,常用表单

v-text:
<p v-text="gender">性别</p> //只能渲染纯文本内容,会覆盖标签内部原本的内容
<p>性别:{{ gender }}</p> //只能渲染纯文本内容,不会覆盖标签内部原本的内容

v-html:
<p v-html="info">该内容会被覆盖</p> //能将带标签的字符串渲染成html内容,会覆盖标签内部原本的内容

v-bind:<!--两种写法都可以-->
<input v-bind:placeholder="tips">
<input :placeholder="tips"> 为元素的属性 动态 绑定属性值


1.vue2和vue3的响应式原理?区别?
答:
vue2响应式原理:
通过object.defineProperty对每个属性进行监听,当对属性进行读取时,会触发getter;对属性进行设置时,会触发setter,在getter中收集依赖,当setter被触发时,把在getter中收集的依赖进行相关的操作,一般是执行相关的回调函数,我们收集的依赖需要进行存储,vue2中设置了一个dep类,类似管家,负责添加或删除依赖和通知相关依赖的操作,所谓的依赖就是watcher,只有通过watcher触发的getter才会去收集依赖,由于object.defineProperty无法监听对象的变化,vue2设置了observer类来管理对象的响应依赖。

vue3响应式原理:
Vue 3 中的响应式原理是通过使用 ES6Proxy 对象来实现的。在 Vue 3 中,每个组件都有一个响应式代理对象,当组件中的数据发生变化时,代理对象会立即响应并更新视图。
具体来说,当一个组件被创建时,Vue 会为组件的 data 对象创建一个响应式代理对象。这个代理对象可以监听到数据的变化,并在数据变化时更新视图。
当组件的 data 对象发生变化时,代理对象会收到变化通知,然后将变化传递给相关的组件和子组件,从而触发组件的重新渲染。这种机制可以有效地保证视图和数据的同步


Vue2Vue3 的区别?
性能优化:
Vue 3 在底层进行了许多性能优化,包括虚拟 DOM 的升级,使其更快速和高效。
Vue 3 引入了懒加载(Lazy Loading)和静态提升(Static Hoisting)等优化策略,进一步提高了性能。

Composition APIVue 3 引入了 Composition API,这是一个基于函数的 API,可以更灵活地组织和重用组件逻辑。
Composition API 允许开发者按功能划分代码,提高了代码的可读性和维护性。

更小的包体积:
Vue 3 的核心库体积更小,因此加载更快。
Vue 3 支持按需加载,使得只引入需要的功能,进一步减小包体积。

TeleportVue 3 引入了 Teleport,允许将组件的内容渲染到 DOM 中的任何位置,这在处理模态框、弹出菜单等场景中非常有用。

FragmentsVue 3 支持 Fragments,允许组件返回多个根元素,而不需要额外的容器元素。

全局 API 的修改:
Vue 3 对全局 API 进行了一些修改,使其更符合现代 JavaScript 的标准。
例如,Vue.component 现在改为 app.componentVue.directive 改为 app.directiveVue.mixin 改为 app.mixin。

新的生命周期钩子:
Vue 3 引入了新的生命周期钩子,如 onBeforeMount 和 onBeforeUpdate,以提供更精确的控制和更好的性能优化机会。

TypeScript 支持改进:
Vue 3TypeScript 的支持更加完善,提供了更好的类型推断和类型检查。

响应式系统的改进:
Vue 3 对响应式系统进行了改进,提供了更好的 TypeScript 支持,并且更加高效。


代码演示:
我们都知道在vue3中主要是采取的ES6中的Proxy来进行数据的代理,通过reflect反射来实现动态的数据响应式,Vue3数据的更新是proxy配合Reflect来实现的
通过Proxy(代理): 拦截对象中任意属性的变化,属性值的读写,属性的增加,属性的删除等。

通过Reflect(反射): 对源对象的属性进行操作

其中的Proxy就相当于一个拦截器,用来拦截对对象中的修改、添加、删除任意属性时,都能被监测到,如下代码:
const person = {
    name:'张三',
    age:18,
    sex:'男'
}
const person1 = new Proxy(person,{
    set(target,key,value){ //其中的target是被操作的对象,key是操作对象的key值,value是更新值
        console.log('我正在被修改');
        return target[key]
        // return Reflect.set(target,key,value)
    },
    get(target,key){
        console.log(target,1);
        console.log(key,2);
        console.log('我正在被读取');
        return target[key]
        // return Reflect.get(target,key)
    }
})

person1.age = 19
person1.sex = '女'
person1.name = '李四'
console.log(person1); // {name:'张三',age:18,sex:'男'}
console.log(person); // {name:'张三',age:18,sex:'男'}

//我们可以看出虽然我们对person1中的相关属性进行了对应的修改,且Proxy所代理的虚拟化对象也监测到了我们对这三个属性的修改,但是也只是单纯的监测到,没有进行实质上的属性的响应式的处理。因此我们就需要使用reffect映射来完成最后的处理。

什么是reflect?
答:
在vue3中通常会将Proxy和reffect两者配合起来使用,Reflect对象的方法与Proxy对象的方法一一对应,只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法。这就让Proxy对象可以方便地调用对应的Reflect方法,完成默认行为,作为修改行为的基础。Proxy可以捕获13种不同的基本操作,这些操作有各自不同的Reflect API方法。如get、set、has、defineProperty等相关操作。如下代码就简单的完成了一个响应式的基本操作。
const person = {
name:'张三',
    age:18,
        sex:'男'
}
 
 
const person1 = new Proxy(person,{
    set(target,key,value){
        console.log('我正在被修改');
        return Reflect.set(target,key,value)
    },
    get(target,key){
        console.log(target,1);
        console.log(key,2);
        console.log('我正在被读取');
        return Reflect.get(target,key)
    }
})
person1.age = 19
person1.sex = '女'
person1.name = '李四'
console.log(person1);  // {name:'李四',age:19,sex:'女'}
console.log(person);  // {name:'李四',age:19,sex:'女'}

3.vue3定义响应式数据有两种
第一种:ref
import {ref} from "vue";
const name = ref('jack');
console.log(name) // 返回一个proxy对象,需要通过.value的方式获取值jack
console.log(name.value) //jack

第二种:reactive
import {reactive} from "vue";
const stu = reactive({name:"mick", age: 1});
console.log(stu); // {name:"mick", age: 1};

总结:ref建议定义基本数据类型,reactive建议定义复杂数据类型。
1.你能列举一些 Vue3 中的新特性吗?
Composition APIComposition APIVue 3 最引人注目的新特性之一。它允许你按功能划分代码,将相关的代码逻辑组织在一起,提高了可维护性和代码复用性。

TeleportTeleport是一个新的特性,允许你将组件的内容渲染到 DOM 中的其他位置。这对于创建模态框、弹出菜单等组件非常有用。

FragmentsVue 3 支持 Fragments,允许一个组件返回多个根元素,而不需要额外的包装容器元素。

全局 API 的修改:
Vue 3 对全局 API 进行了一些修改,使其更符合现代 JavaScript 的标准。例如,Vue.component 现在改为 app.component。

性能优化:
Vue 3 在底层进行了许多性能优化,包括虚拟 DOM 的升级,懒加载和静态提升等策略,使应用程序更快速和高效。

响应式系统改进:
Vue 3 对响应式系统进行了改进,提供了更好的 TypeScript 支持和更高效的响应式数据追踪。

TypeScript 支持:
Vue 3TypeScript 的支持更加完善,提供了更好的类型推断和类型检查。

更小的包体积:
Vue 3 的核心库体积更小,加载更快,并且支持按需加载,减小了包体积。

生命周期钩子的改进:
Vue 3 引入了新的生命周期钩子,如 onBeforeMount 和 onBeforeUpdate,提供了更精确的控制和性能优化的机会。

SuspenseVue 3 支持 Suspense 特性,允许你优雅地处理异步组件的加载状态,提供更好的用户体验。

自定义渲染器:
Vue 3 允许你创建自定义渲染器,这使得你可以在不同的目标环境中使用 Vue,例如服务器端渲染(SSR)或原生应用。

V-model 的改进:
Vue 3 改进了 v-model 的语法,使其更加灵活,可以用于自定义组件的双向绑定。
1.请解释 Vue 3 中的响应式系统是如何工作的?
初始化:
当你创建一个Vue 3组件或应用程序时,Vue会初始化一个响应式系统的实例。

数据定义:
你通过在组件的 setup 函数中创建响应式数据。这可以通过 ref、reactive、或 computed 来实现。

数据依赖追踪:
当组件渲染时,Vue 会自动追踪数据属性的依赖关系。这意味着Vue知道哪些数据属性被用于渲染视图。

响应式依赖收集:
Vue 会在组件渲染期间收集数据属性的依赖,构建一个依赖关系图。

数据变更时触发:
当响应式数据属性发生变化时,Vue 会通知依赖于该数据属性的视图更新。

批量更新:
Vue 3 会将多个数据变更的通知进行批处理,以最小化 DOM 更新操作,提高性能。

异步更新队列:
Vue 3 使用微任务队列(如 Promise 或 nextTick)来处理数据更新,确保在同一事件循环中的多次数据变更只触发一次视图更新。

视图更新:
一旦数据变更通知到视图,Vue 3 会重新渲染相关的组件部分,使其与最新的数据保持同步。

计算属性和侦听器」:
Vue 3 允许你使用计算属性(computed)和侦听器(watch)来处理数据的派生和监听变化,这些特性也依赖于响应式系统来工作。
1.vue.set()和this.$set?
答:
vue.setthis.$Set作用一样,当想要对对象添加属性时,vue无法监听到对象属性的添加或删除,
如:
data () {
  return {
    student: {
      name: '',
      sex: ''
    }
  }
}
mounted () { // ——钩子函数,实例挂载之后
  this.student.age = 24 //无法监听到
}

正确写法:// this.$set(this.data,”key”,value')  // Vue.set(this.data,”key”,value')
mounted () {
  this.$set(this.student,"age", 24);
}

2.vue.nextTick()和this.$nextTick?
答:
下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
如:
<template>
  <div>
    <div ref="msg">{{msg}}</div>
    <div v-if="msg1">out $nextTick: {{msg1}}</div> // Hello Vue
    <div v-if="msg2">in $nextTick: {{msg2}}</div>  // Hello world
    <div v-if="msg3">out $nextTick: {{msg3}}</div> // Hello Vue
    <button @click="changeMsg"> changeMsg </button>
  </div>
</template>

<script>
export default {
  data(){
    return{
      msg: 'Hello Vue',
      msg1: '',
      msg2: '',
      msg3: ''
    }
  },
  methods: {
    changeMsg() {
      this.msg = "Hello world"
      this.msg1 = this.$refs.msg.innerHTML
      this.$nextTick(() => {
        this.msg2 = this.$refs.msg.innerHTML
      })
      this.msg3 = this.$refs.msg.innerHTML
    }
  }
}
</script>
1.vue通信方式?
答:
props,自定义事件(子传父,父传子,兄弟),vuex(状态机)等

1.vue的生命周期钩子函数?
答:
beforeCreate(创建前):
在组件实例被创建之前立即调用。
此时组件的数据和事件还未初始化。
created(创建后):
在组件实例被创建后立即调用。
组件的数据已经初始化,但此时还未挂载到 DOM。
beforeMount(挂载前):
在组件挂载到 DOM 之前立即调用。
此时模板编译完成,但尚未将组件渲染到页面上。
mounted(挂载后):
在组件挂载到 DOM 后立即调用。
此时组件已经渲染到页面上,可以进行 DOM 操作。
beforeUpdate(更新前):
在组件数据更新之前立即调用。
在此钩子函数内,你可以访问之前的状态,但此时尚未应用最新的数据。
updated(更新后):
在组件数据更新后立即调用。
此时组件已经重新渲染,可以进行 DOM 操作。
beforeDestroy(销毁前):
在组件销毁之前立即调用。
此时组件仍然可用,你可以执行一些清理工作。
destroyed(销毁后):
在组件销毁后立即调用。
此时组件已经被完全销毁,不再可用。

1.Vue的双向数据绑定是如何实现的?请举例说明。
Vue.js 的双向数据绑定是通过其特有的响应式系统来实现的。这个系统使用了ES6Proxy对象或者Object.defineProperty()方法,以便在数据变化时通知视图进行更新。这意味着当你修改数据模型时,与之相关联的视图会自动更新,反之亦然。

1.Vue中的计算属性和观察者的作用是什么?它们有什么区别?
计算属性(Computed Properties):
计算属性是Vue.js中的一种属性类型,它的值是基于其他数据属性计算而来的,类似于一个函数。计算属性的主要作用是将计算逻辑封装起来,以便在模板中直接引用,而且它们具有缓存机制,只有在依赖的数据发生变化时才会重新计算。

主要特点和作用:
用于派生或计算基于现有数据属性的值。
具有缓存机制,只有在相关数据发生变化时才会重新计算,提高性能。
在模板中可以像普通属性一样直接引用。
计算属性一般用于简单的数据转换、筛选、格式化等操作。

实例:
<template>
  <div>
    <p>{{ fullName }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    }
  },
  computed: {
    fullName() {
      return this.firstName + ' ' + this.lastName;
    }
  }
}
</script>

观察者(Watchers):
观察者是Vue.js中的一种方式,用于在数据变化时执行自定义的异步或开销较大的操作。你可以监听一个或多个数据属性的变化,并在数据变化时执行特定的函数。

主要特点和作用:
用于在数据变化时执行自定义的操作,例如异步请求或复杂的数据处理。
不具有缓存机制,每次数据变化都会触发执行。
需要手动编写观察者函数来处理数据变化。
可以监听多个数据属性的变化。

实例:
<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data() {
    return {
      value: 'Initial Value',
      message: ''
    }
  },
  watch: {
    value(newValue, oldValue) {
      // 在value属性变化时执行的操作
      this.message = 'Value changed: ' + newValue;
    }
  }
}
</script>

区别:
1.「计算属性」主要用于对数据的转换和派生,具有缓存机制,只有在相关数据变化时才会重新计算,适合用于简单的数据处理。它们在模板中可以像普通属性一样直接引用。

2.「观察者」用于在数据变化时执行自定义的操作,没有缓存机制,每次数据变化都会触发执行。适合处理复杂的异步操作或需要监听多个数据变化的情况。

根据具体的需求,你可以选择使用计算属性或观察者来处理数据变化。通常,计算属性是首选,因为它们更简单且性能更高,而只有在需要特殊处理数据变化时才使用观察者

1.谈谈你对Vue组件的理解。如何创建一个Vue组件?
答:
Vue 组件是 Vue.js 应用中的可复用模块,它将一个页面拆分成多个独立的部分,每个部分有自己的状态、模板和行为。组件化是 Vue.js 的核心概念之一,它使前端开发更加模块化、可维护和可重用。

1.vuex核心概念
答:五大核心概念:state,getters,mutaions,actions,modules

state是存放公共数据的数据仓库,

getters是获取state更新后的最新数据

mutaions是存放同步的修改state数据的方法

actions是存放异步的方法

modules是起到模块化拆分后合并的作用

1.keep-alive:
主要用于缓存内部组件数据状态。可以将组件缓存起来并在需要时重新使用,而不是每次重新创建。这可以提高应用的性能和用户体验,特别是在需要频繁切换组件时。

keep-alive 组件的实现原理是将被缓存的组件实例存储到一个缓存对象中,当需要重新渲染这个组件时,会从缓存中获取到之前的实例,并将其重新挂载到 DOM 上。

React

1.解释一下redux核心概念
​ store action reducer

答:store:存放公共数据的数据仓库

action:通知对象。一旦我们想要修改store中的数据,我们就只能通过store.dispatch方法发送action通知对象

reducer:计算者:它是一个函数,有两个参数,一个是state(store中的数据),一个action(接收到的通知对象),通过辨别的action的type来完成对store中数据的修改
1.react常用的生命周期钩子函数有哪些?分别有什么作用
constructor:组件数据的初始化

render:渲染页面

componentdidmount:dom渲染完毕时执行,可以发送接口,获取dom

compoentdiduodate:数据修改后并渲染完毕执行

componentwillunmont:组件即将卸载执行,可以在这里清楚定时器,延时器等
react中refs有什么作用?
1. 获取DOM
2. 获取组件实例
1.redux中间件是什么,有什么作用,你常用的中间件有哪些?
答:redux中间件是指dispatch的封装和升级,

在不使用中间件时,我们通过dispatch方法传递action参数,就会被reducer接收并立即执行,达到修改store的数据的目的

在使用中间件时,我们通过dispatch方法传递action参数,并不会立即被reducer接收,而是先通过中间件的一系列处理,然后才到reducer进行接收执行修改store的数据

使用中间件能够更灵活的处理数据,打印数据修改日志

常用的有

logger:数据更新后,会在控制要打印数据变化前后的值

saga:用于管理异步操作的中间件
1.redux三大原则是什么?
单一数据源
store中的数据(state)是只读的
必须通过纯函数reducer来执行修改

1.函数组件和类组件有什么区别(16.8以前)?
答:类组件有自己的生命周期钩子函数,函数组件是没有的,只能被动的接收外部数据,并且类组件有存在this,函数组件并没有

1.你对react新特性hooks有什么了解吗?
答:指的是函数组件,当一个函数返回一个jsx对象,那么这个函数就是一个函数组件

函数组件有hook特性,hook特性只能在函数组件使用,常用到的hook有useState,useEffect,useRef,useMemo,自定义hook

2.react如何提取组件之间的公共逻辑
redux状态机,自定义hook,高阶组件hoc,renderprops
1.前端如何实现身份验证

session 早些年在token出现之前都是通过session来实现浏览器客户端的身份验证的,每次用户登录时把用户名和密码传到后端服务器,后端服务器验证用户名和密码,如果验证通过就会生成一个sessionId,并存储到服务器中,同时该请求在响应给客户端时,会通过Set-Cookie字段把sessionId投放并存储到客户端(浏览器)的HTTP-cookies,当客户端下一次发送请求到服务端的时候会自动携带上存有sessionId的cookie。这样后端服务器拿到sessionId和之前存储的sessionId一对比,如果一样就确定该用户是之前的用户,然后就把数据响应到客户端了。
token 每次用户登录时把用户名和密码传到后端服务器,后端服务器验证用户名和密码,如果验证通过一般会用过JWT结合用户信息通过一个秘钥(该秘钥会存储到服务器)加密生成一个token,然后把该token返回给客户端,客户端一般把token存储到本地存储,比如localStorage或者sessionStorage中。后续在在发送接口的时候会把token从本地存储中取出来,放到请求头Header中发送给后端服务器。后端拿到token,然后通过之前的秘钥尝试去解该token,如果能解密出来就说明该token是合法的,否则就是不合法的。
session和token的区别
session需要借助于cookie,而cookie只有浏览器支持,如果要做app则没办法用session来实现身份验证。只能用token
seesion需要在服务器中存储每位用户对应的sessionId,而token只需要存一份秘钥即可。

2.什么是跨域?如何解决
跨域是浏览器的同源策略导致的问题,当我们的协议、域名和端口号,任意一个不同的时候,就会导致跨域的出现

常见的一个场景,前端请求后端api的时候出现跨域,如何解决?

前端处理:代理服务器 webpack-dev-server (vue.config.js)


devServer:{
	proxy:{
		&quot;/api&quot;:{
			target:&quot;http://localhost:8000&quot;
		}
	}
}

后端处理:
设置响应头

3.浏览器渲染页面的流程
​ GUI渲染线程负责界面的渲染过程

​ 同时解析html/css

解析html ---->DOMTree

解析css--->CSSTree

然后合并DOMTreeCSSTree形成RenderTree(渲染树)

接下来开始layout (布局,回流)

绘制(重绘)

GIT

步骤:
git clone  //将远程仓库代码拉取下来
git checkout //切换到对应分支,在本地进行代码编辑修改
git add . //将修改后的代码添加到暂存区
git commit message //打印日志,将暂存区的代码推送到本地仓库
git push origin  //发送合并请求,将本地仓库代码推送到远程仓库进行合并

1.常见的命令
git config --global user.name "你的名字" 让你全部的Git仓库绑定你的名字
git config --global user.email "你的邮箱" 让你全部的Git仓库绑定你的邮箱
git init 初始化你的仓库
git add . 把工作区的文件全部提交到暂存区
git add ./<file>/ 把工作区的<file>文件提交到暂存区
git commit -m "xxx" 把暂存区的所有文件提交到仓库区,暂存区空空荡荡
git remote add origin https://github.com/name/name_cangku.git 把本地仓库与远程仓库连接起来
git push -u origin master 把仓库区的主分支master提交到远程仓库里
git push -u origin <其他分支> 把其他分支提交到远程仓库
git status查看当前仓库的状态
git diff 查看文件修改的具体内容
git log 显示从最近到最远的提交历史
git clone + 仓库地址下载克隆文件
git reset --hard + 版本号 回溯版本,版本号在commit的时候与master跟随在一起
git reflog 显示命令历史
git checkout -- <file> 撤销命令,用版本库里的文件替换掉工作区的文件。我觉得就像是Git世界的ctrl + z
git rm 删除版本库的文件
git branch 查看当前所有分支
git branch <分支名字> 创建分支
git checkout <分支名字> 切换到分支
git merge <分支名字> 合并分支
git branch -d <分支名字> 删除分支,有可能会删除失败,因为Git会保护没有被合并的分支
git branch -D + <分支名字> 强行删除,丢弃没被合并的分支
git log --graph 查看分支合并图
git merge --no-ff <分支名字> 合并分支的时候禁用Fast forward模式,因为这个模式会丢失分支历史信息
git stash 当有其他任务插进来时,把当前工作现场“存储”起来,以后恢复后继续工作
git stash list 查看你刚刚“存放”起来的工作去哪里了
git stash apply 恢复却不删除stash内容
git stash drop 删除stash内容
git stash pop 恢复的同时把stash内容也删了
git remote 查看远程库的信息,会显示origin,远程仓库默认名称为origin
git remote -v 显示更详细的信息
git pull 把最新的提交从远程仓库中抓取下来,在本地合并,和git push相反
git rebase 把分叉的提交历史“整理”成一条直线,看上去更直观
git tag 查看所有标签,可以知道历史版本的tag
git tag <name> 打标签,默认为HEAD。比如git tag v1.0
git tag <tagName> <版本号> 把版本号打上标签,版本号就是commit时,跟在旁边的一串字母数字
git show <tagName> 查看标签信息
git tag -a <tagName> -m "<说明>" 创建带说明的标签。 -a指定标签名,-m指定说明文字
git tag -d <tagName> 删除标签
git push origin <tagname> 推送某个标签到远程
git push origin --tags 一次性推送全部尚未推送到远程的本地标签
git push origin :refs/tags/<tagname> 删除远程标签<tagname>
git config --global color.ui trueGit显示颜色,会让命令输出看起来更醒目
git add -f <file> 强制提交已忽略的的文件
git check-ignore -v <file> 检查为什么Git会忽略该文件