一、js
1.什么是js原型?原型链是什么?
所有的函数默认都有一个“prototype”这样公有且不可枚举的属性,它会指向另一个对象,这个对象就是原型。
构造函数的prototype属性就等于实例对象的__proto__属性,构造函数的prototype属性被称为显式原型,实例对象的__proto__属性被称为隐式原型
原型链,当访问对象的属性或方法时,首先对象会从自身去找,找不到就会往原型中去找,也就是它构造函数的“prototype”中,如果原型中找不到,即构造函数中也没有该属性,就会往原型后面的原型上去找,这样就形成了链式的结构,称为原型链。
1.原型链可以解决什么问题?
对象共享属性和共享方法
2. 谁有原型
函数拥有:prototype
对象拥有: __proto__
3.对象查找属性或者方法的顺序
先在对象本身找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型 -->当前原型的原型中
function Fun(){
this.name = '1';
}
Fun.prototype.name='2';
let newObj = new Fun();
newObj.name='3';
newObj.__proto__.name='4';
Object.prototype.name='5';
console.log(newObj.name) // 3 -> 1 -> 4 -> 2 -> 5
2.闭包是什么?应用场景是什么?
闭包:函数嵌套函数,内部函数就是闭包,即有权访问另一个函数作用域的变量的函数
场景:立即执行函数,缓存,实现封装,实现模板
示例:
function outerFun(){
let a = 10;
function innerFun(){
console.log(a);
}
return innerFun;
}
let fun = outerFun();
fun(); // 10 或者写成outerFun()();
3.promise是什么?和async await的区别是什么?
promise是处理异步操作的一种解决方案。解决了回调地狱问题(层层嵌套的回调函数)
场景:封装ajax
async await是异步处理同步化。是ES7引入的一种基于Promise的语法糖,用于更简洁的处理异步操作。它可以让异步的代码看起来更像是同步的代码,提供了更好的可读性和编写体验。
promise 与async await的区别是:
- 语法差异:Promise 使用 then() 和 catch() 方法来处理异步操作的结果和错误,而 async/await 使用 async 和 await 关键字以更直观的方式编写异步代码。
- 错误处理:Promise 使用 catch() 方法来捕获错误,而 async/await 可以使用 try-catch 语句来捕获错误。
- 代码可读性:async/await 可以让异步代码看起来更像同步代码,逻辑更清晰,可读性更好。通过使用 await 关键字,可以将异步操作写成一系列顺序执行的语句,而不是嵌套的回调函数。
- 错误堆栈追踪:使用 Promise,错误发生时,堆栈追踪会包含 Promise 内部的异步操作,使得定位错误变得更困难。而使用 async/await,错误堆栈追踪会显示在出错的地方,更方便调试和定位错误。
- 错误处理方式:Promise 是使用回调函数来处理异步操作的错误,而 async/await 使用 try-catch 机制来处理错误。
- 虽然 async/await 是基于 Promise 的,但它们有不同的用法和语法,让异步代码的编写更简洁和可维护,并提供了更好的错误处理机制。
4.防抖,节流是什么?应用场景是什么?
都是用于控制函数执行频率的方法,以避免不必要的重复操作,减轻系统负担,提高用户体验。
区别:
1. **防抖**:多次触发,只执行最后一次
是指当事件被触发后,延迟n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时
**场景**:适用于需要等待用户停止操作后在执行的场景,如搜索框输入文本后请求接口、实时保存,表单输入验证,实时聊天,
2. **节流**:规定时间内,只触发一次
是指当事件持续触发时,每n秒只执行一次
**场景**:按钮点击事件,鼠标移动事件(懒加载),浏览器resize
实现:用于setTimeout实现
5.事件循环机制是什么?
js是单线程,指在同一时刻只能执行一个任务,任务只有在前一个任务执行完毕后才能开始下一个任务,但是js通过事件循环机制实现了异步。
Js事件循环机制,指的是js运行时环境按照一定的规则处理代码中的异步操作和事件的机制。包含任务队列,微任务队列,宏任务队列。
事件循环机制是指:
1、代码执行时,先执行同步任务,然后把异步任务放入任务队列中,等待执行。
2、当所有同步任务执行完毕后,js引擎会读取任务队列中的任务。
3、将队列中的第一个任务压入执行栈中执行,执行完毕后将其出栈。
4、如此循环执行,直到任务队列中的所有任务都执行完毕。
总的来说,JavaScript通过事件循环机制来实现异步操作,将异步任务放到任务队列中,然后在任务队列中等待执行,直到JavaScript引擎空闲,再将任务队列中的任务拿出来执行。
事件执行顺序:
1.同步
2.processs.nextTick
3.微任务(promise.then、process. nextTick)
4.宏任务(定时器,ajax,读取文件)
5.setImmediate
注意:setImmediate类似于setTimeout,但是会在当前事件的末尾立即执行回调函数,而不是等待一定的延迟时间。优先级比setTimeout高
console.log(1);
async function async1(){
await async2();
console.log(2);
}
async function async2(){
console.log(3);
}
async1();
setTimeout(()=>{
console.log(4);
})
new Promise(resolve =>{
console.log(5);
resolve();
}).then(()=>{
console.log(6);
}).then(()=>{
console.log(7);
})
console.log(8); // 1 3 5 8 2 6 7 4
6.事件委托是什么?
事件委托也称之为事件代理,是利用冒泡机制,将事件的处理交给父元素或更高层级的元素来管理,而不是直接将事件处理程序绑定到每个子元素。
- 事件冒泡:目标元素事件先触发,然后父元素事件触发
- 事件捕获:父元素事件先触发,然后目标元素事件触发
事件执行顺序是:
- 先事件捕获(从 Windows -> document 依次往下)
- 再是目标事件处理
- 最后是事件冒泡
addEventListener() 第三个参数为 false 事件触发顺序是冒泡顺序,true 为捕获顺序,默认为 false(这个冒泡和捕获是说当子元素被点击时,我是先执行还是后执行)。
好处:
- 减少事件处理程序的数量:使用事件委托可以减少需要绑定事件处理程序的元素数量。相对于为每个子元素绑定事件处理程序,只需在父元素上绑定一个事件处理程序即可。
- 动态绑定和增加灵活性:当新的子元素被添加到父元素中时,它们会自动继承来自父元素的事件处理程序,无需再次手动绑定事件。
- 节省内存消耗:由于事件委托采用冒泡机制,它只需绑定一个事件处理程序,因此减少了多个元素各自绑定事件处理程序所占用的内存。
7.什么是js作用域?作用域链
js作用域指变量可访问的范围,主要有全局作用域和局部作用域
局部作用域又分为函数作用域和块级作用域。
注意:
- 除了函数外,js是没有块级作用域
- 作用域链:内部可以访问外部的变量,但是外部不可以访问内部的变量。 如果内部有,优先查找到内部,如果内部没有就查找外部的
- 声明变量是用var,还是没有写(window.)
- js有变量提升的机制【变量悬挂声明】
- 优先级:变量声明 > 声明普通函数 > 参数 > 变量提升
function Foo(){
getName = function(){ console.log(1) }
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,相当于这里执行了window.getName = function(){ console.log(1) }
getName(); //1
new Foo().getName();//3
8.箭头函数和普通函数的区别?
- this的指向不同。普通函数,谁调用这个函数,this指向谁;箭头函数,在哪里定义函数,this指向谁,即箭头函数没有自己的this,它继承父级作用域的this。
- 原型和构造函数。箭头函数没有自己的原型(prototype),因此不能用作构造函数,使用new关键字调用箭头函数会报错,因为箭头函数没有构造函数(constructor)
- arguments对象。普通函数有一个arguments对象,可以以数组的方式呈现函数的所有参数,箭头函数则使用(...args)接受不定参数的参数
const fun = (...args)=>{
//console.log(arguments) //arguments is not defined
console.log(...args)
}
fun(1,2,3); // 1,2,3
二、vue
1.token是什么?说一下登录流程
Token是服务端生成的一串字符串,作为客户端进行请求的一个令牌。
大概的流程:
- 客户端使用用户名和密码请求登录(服务器--后端)
- 服务端收到请求,验证用户名和密码
- 验证成功后,服务端(后台)会生成一个token,然后把这个token发送给客户端(前端)
- 客户端收到token后把它存储起来,可以放在cookie或者Local Storage(本地存储)里
- 客户端每次向服务端发送请求的时候都需要带上服务端发给的token(客户端--前端)
- 服务端收到请求,然后去验证客户端请求里面带着token,如果验证成功,就向客户端返回请求的数据
注意:这个token必须在每次请求时传递给服务器,应该保存在请求头里,另外服务器要支持CORS(跨域资源共享)的策略
2.computed和watch的区别
1.缓存:computed依赖data中的属性,会自动计算并缓存结果,watch不支持
2.异步:computed不支持异步, 当有异步操作时无效,无法监听数据的变化,watch 支持异步操作
3.return:computed中的函数必须用return返回,watch没有return
4.在computed中的,属性都有一个get和一个 set 方法,当数据变化时,调用 set 方法;
3.路由懒加载的原理?
Vue 路由懒加载的实现依赖于动态导入语法
import()
来实现异步组件。当路由被访问时,
import()
函数会返回一个Promise对象,这个Promise对象会在组件被加载完成后resolve,并将组件作为参数传递给回调函数。这样,只有在组件被实际需要时才会加载对应的模块,从而实现了路由的懒加载。
Webpack编译打包后,会把每个路由组件的代码分割成多个js文件,初始化时不会加载这些js文件,只当激活路由组件才会去加载对应的js文件
使用动态导入时,只有在用户访问对应路由时才会加载相应的组件,这样可以减少初始加载时间和资源消耗
注意:路由懒加载通常只在非首页路由中使用,因为首页路由通常需要在页面加载时就立即呈现给用户,不适合使用懒加载
// 使用动态导入进行懒加载
component: () => import('@/components/Home.vue')
4.webpack的编译原理是什么?
webpack是一个串行流程,启动到结束依次执行:
1)初始化参数:解析webpack配置参数,合并shell传入和webpack.config.js文件配置的参数,形成最后的配置结果
2)开始编译:初始化Compiler对象,加载插件,执行对象的run方法
3)确定入口:从配置的entry入口,开始解析文件构建AST语法树,找出依赖,递归下去
4)编译模块:从entry出发,调用所有配置的loader对模块进行编译,再找到该模块所依赖的模块,递归本步骤直至所有入口依赖的文件经过处理
5)完成模块编译:得到每个模块被编译后的最终内容,以及依赖关系
6)输出资源:根据入口和模块之间的依赖关系,组装成一个个chunk,再把每个chunk转换为单独的文件输出
7)输出完成:输出所有的chunk到文件系统
plugin与loader的区别:
plugin:插件用于扩展webpack的功能。可以在打包的不同阶段执行不同特定的任务。如压缩代码。
loader:是在模块加载时,对其进行转换和处理。
版权归原作者 yecengxiangshi0426 所有, 如有侵权,请联系我们删除。