闭包
闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment,词法环境)的引用的组合。换而言之,闭包让开发者可以从内部函数访问外部函数的作用域。在 JavaScript 中,闭包会随着函数的创建而被同时创建
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
深拷贝浅拷贝
- 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存(分支)
- 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。
- 如果属性是基本类型,拷贝的就是基本类型的值;如果属性是内存地址(引用类型),拷贝的就是内存地址 ,因此如果其中一个对象改变了这个地址,就会影响到另一个对象。
- 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象,是“值”而不是“引用”(不是分支)
- 拷贝第一层级的对象属性或数组元素
- 递归拷贝所有层级的对象属性和数组元素
- 深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大
如何理解js的异步
JS是一门单线程的语言,这是因为它运行在浏览器的渲染主线程中,而渲染主线程只有一个。而渲染主线程承担着诸多的工作,渲染页面、执行JS都在其中运行。
如果使用同步的方式,就极有可能导致主线程产生阻塞,从而导致消息队列中的很多其他任务无法得到执行。这样一来,一方面会导致繁忙的主线程白白的消耗时间,另一方面导致页面无法及时更新,给用户造成卡死现象。
所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时,比如计时器、网络、事件监听,主线程将任务交给其他线程去处理,自身立即结束任务的执行,转而执行后续代码。当其他线程完成时,将事先传递的回调函数包装成任务,加入到消息队列的末尾排队,等待主线程调度执行。
在这种异步模式下,浏览器永不阻塞,从而最大限度的保证了单线程的流畅运行。
数组的方法
1.shift 删除数组中的第一个元素
2.pop 删除数组中的最后一个元素
3.unshift 增加元素在数组的前面
4.push 增加元素在数组的后面
5.map 循环,并且返回新的数组
6.forEach 循环,遍历
7.filter 过滤,筛选出数组中的满足条件的,并且返回新的数组
8.concat 合并数组
9.find 查找出第一个符合条件中的数组元素
10.findIndex 查找出第一个符合条件中的数组元素,所在的索引位置
11.flat 将多维数组转为一维数组
12.join将数组转为字符串
13.reverse 颠倒数组中的顺序
14.every检测数组中元素是否都是符合条件 === Boolean
15.some检测数组中元素是否有满足条件的元素 === Boolean
16.splice(start,n,添加元素) 开始位置 删除个数,添加元素
17.sort 排序
18.slice(start,end) 选中[start.end)之间的元素
19.indexOf 查找值所在的位置
20.includes 查看数组中是否存在此元素
21.copyWithin( ) 指定位置的成员复制到其他位置
22.fill( )填充数组
23.Array.from( )方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map
24.Array.of( ) 用于将一组值,转换为数组
25.flatMap( )只能展开一层数组-----flat 降维 与 map 有返回值的遍历 的结合
Cookie、Session、localStorage区别
- cookie数据存放在客户的浏览器上,session数据放在服务器上
- cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,如果主要考虑到安全应当使用session
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用COOKIE
- 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的COOKIE不能3K。
- localStorage (当前)仅支持将字符串作为值,并且为了做到这一点,需要先将对象进行字符串化(存储为JSON-string),然后才可以定义值的长度限制
查看以下console.log输出什么
var a=[];
var b=a;
a[2]=2;
b[3]=3;
console.log(a.length);
console.log(b.length);
console.log(a);
console.log(b);
//输出 4、4、[空 ã2, 2, 3]、[空 ã2, 2, 3]
function Obj() {this.a = 100;}
Obj.prototype.a = 300;
Obj.a = 200;
var obj = new Obj();
console.log(obj.a); //100
setTimeout(function () {
console.log(1)
})
new Promise(function (resolve) {
console.log(2)
resolve();
}).then(function () {
console.log(3)
})
console.log(4)
//结果 2 4 3 1
vue相关面试题
组件通信
组件通信常用方法有以下8种
- props
- $emit/ $
on - $children/ $parent
- $attrs/ $listeners
- ref
- $root
- eventbus 事件总线
- vuex
根据组件之间关系讨论组件通信可分为 - 父子组件
props
/$emit
/$parent
/ref
/$attrs
- 兄弟组件
$parent
/$root
/eventbus
/vuex
/pinia
- 跨层级关系
eventbus
/vuex
/provide
+inject
/pinia
v-model的原理
v-model
本质上不过是语法糖,可以用v-model
指令在表单<input>
、<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过JavaScript
在组件的data
选项中声明初始值。v-model
在内部为不同的输入元素使用不同的属性并抛出不同的事件:text
和textarea
元素使用value
属性和input
事件;checkbox
和radio
使用checked
属性和change
事件;select
字段将value
作为prop
并将change
作为事件。
v-if和v-for哪个优先级更高
回答范例:
- 实践中不应该把v-for和v-if放一起
- 在vue2中,v-for的优先级是高于v-if,把它们放在一起,输出的渲染函数中可以看出会先执行循环再判断条件,哪怕我们只渲染列表中一小部分元素,也得在每次重渲染的时候遍历整个列表,这会比较浪费;另外需要注意的是在vue3中则完全相反,v-if的优先级高于v-for,所以v-if执行时,它调用的变量还不存在,就会导致异常
- 通常有两种情况下导致我们这么做:
- 为了过滤列表中的项目(比如
v-for="user in users" v-if="user.isActive" )。此时定义一个计算属性(比如
activeUsers),让其返回过滤后的列表即可(比如
users.filter(u=>u.isActive) ')。 - 为了避免渲染本应该被隐藏的列表(比如
v-for="user in users" v-if="shouldShowUsers"
)。此时把v-if
移动至容器元素上(比如ul
、ol
)或者外面包一层template
即可
- 为了过滤列表中的项目(比如
ref和toRef区别
- ref本质是拷贝,修改响应式数据不会影响原始数据;toRef的本质是引用关系,修改响应式数据会影响原始数据
- ref数据发生改变,界面会自动更新;toRef当数据发生改变是,界面不会自动更新
- toRef传参与ref不同;toRef接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
ref和reactive区别
- 从定义数据角度对比:
- ref用来定义:基本类型数据。
- reactive用来定义:对象(或数组)类型数据。
- 备注:ref也可以用来定义对象(或数组)类型数据, 它内部会自动通过
reactive
转为代理对象。
- 从原理角度对比:
- ref通过
Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。 - reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
- ref通过
- 从使用角度对比:
- ref定义的数据:操作数据需要
.value
,读取数据时模板中直接读取不需要.value
。 - reactive定义的数据:操作数据与读取数据:均不需要
.value
。
- ref定义的数据:操作数据需要
计算属性和watch区别
- 计算属性在调用时需要在模板中渲染,修改计算所依赖元数据;watch在调用时只需修改元数据。
- 计算属性默认深度依赖,watch默认浅度观测。
- 计算属性适合做筛选,不可异步;watch适合做执行异步或开销较大的操作。
vue-router
有几种模式
hash
模式- 在第一个#后面出现的任何字符,都会被浏览器解读为位置标识符。这意味着,这些字符都不会被发送到服务器端
- 单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页。
- 每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用"后退"按钮,就可以回到上一个位置。
- 可通过window.location.hash属性读取 hash 值,并且
window.location.hash
这个属性可读可写。 - 使用
window.addEventListener("hashchange", fun)
可以监听 hash 的变化
history
模式abstract
模式- 总结
- hash 和 history 的使用方式差不多,hash 中路由带 # ,但是使用简单,不需要服务端配合,站在技术角度讲,这个是配置最简单的模式,本人感觉这也是 hash 被设为默认模式的原因
- history 模式需要服务端配合处理404的情况,但是路由中不带 # ,比 hash 美观一点。
- abstract 模式没有使用浏览器api,可以放到node环境或者桌面应用中, 本人感觉是对 spa应用 的兜底和能力扩展。