vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()对数据进行劫持 结合 观察者模式(发布和订阅)的方式来实现的。
vue3 中使用了 es6 的 ProxyAPI 对数据代理。
区别一:defineProperty 是对属性劫持,proxy 是对代理对象
区别二:defineProperty 无法监听对象新增/删除属性,proxy 可以
区别三:defineProperty 无法监听对象属性元素增删除proxy 可以
区别四:defineProperty 不能监听数组下标改变值的变化,proxy 可以且不需要对数组的方法进行重载
Vue2.0 对于数据响应式的实现上是有一些局限性的,比如:
无法检测数组和对象的新增
无法检测通过索引改变数组的操作
Vue 对数组的7个操作方法(push、pop、shift、unshift、splice、sort、reverse)也实现了响应式,这里我们就不做测试了,感兴趣的小伙伴可以自己试一下。
总结:
Object.defineProperty 在数组中的表现和在对象中的表现是一致的,数组的索引就可以看做是对象中的 key 。
通过使用上面操作数组的方法发现:
通过索引访问或设置对应元素的值时,可以触发 getter 和 setter 方法
通过 push 或 unshift 会增加索引,对于新增加的属性,需要再手动初始化才能被 observe
通过 pop 或 shift 删除元素,会删除并更新索引,也会触发 setter 和 getter 方法
所以,Object.defineProperty 是有监控数组下标变化的能力的,只是在 vue2.x 放弃了这个特性(性能原因)
vue3
单文件组件<script setup>
性能
区别五:defineProperty 是循环遍历对象属性的方式来进行监听,自然会比 proxy 对整个对象进行监听的方式要耗性能。
最大的区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
Vue3支持碎片 就是说在组件可以拥有多个根节点。《template》下面可以多个div 但是vue2只能一个
Vue 瞬移组件 <teleport> 可以挂载到任何地方 常用的地方app全局
vue的特点是:底层是Virtual DOM,上层有包含大量的静态信息的模版,vue3进行性能优化的就是基于 兼容手写 render function,最大化利用模版静态信息 采用“动静结合”进行的的方式
Vue 和 react 区别
Vue 使用的是 web 开发者更熟悉的模板与特性,Vue的API跟传统web开发者熟悉的模板契合度更高
React 的特色在于函数式编程的理念和丰富的技术选型。
共同点:
数据驱动视图
组件化
都使用 Virtual DOM
不同点:
vue是渐进式框架,react是声明式框架
Vue数据双向绑定,react单项数据流
vue能更快计算出Virtual DOM 分割成许多小组件,react 会递归子组件
vuex都是注入的,redux是每次都改state,
react趋向于大型应用, vue适用于简单迅速解决问题
它们最大的区别在于 Vue. js通常使用HTML模板文件,而 React完全使用 JavaScript创建虚拟DOM。 Vue. js还具有对于“可变状态”的“ reactivity”的重新渲染的自动化检测系统
node-Egg
Master -多个worker(看cpu) aggent一个处理日志,worker之间通信
前端工程化是大厂前端开发人员的必备技能,从开发,规范,测试,lint,构建,部署,监控,集成,微服务等多个维度,以组合拳的形式
vue原理:
注意:Vue并没有完全遵循MVVM的思想,这一点官网自己也有声明。
1、什么是vue生命周期?作用是什么? 总共有几个阶段?new Vue做了什么
答: Vue 实例从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
2.vue生命周期的作用是什么?
答:它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
3.vue生命周期总共有几个阶段?
答:它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
4.第一次页面加载会触发哪几个钩子?
答:会触发 下面这几个beforeCreate, created, beforeMount, mounted 。
Vue 的生命周期钩子核心实现是利用发布-订阅模式
new Vue()创建了根实例并准备好数据和方法,未来执行挂载时,此过程还会递归的应用于它的子组件上,最终形成一个有紧密关系的组件实例树,defineReactive 时为每⼀个 key 创建⼀个 Dep 实例。
2、vue实现双向数据绑定 v-model数据实现(input、change) 事件绑定($on)
vue 采用“数据劫持”+“观察者模式(发布者-订阅者模式)”相结合的方式实现了双向绑定——vue 的响应式原理
Observer,Compile和Watcher
Vue事件绑定原理
on、emit 是基于发布订阅模式的,维护一个事件中心,on的时候将事件按名称存在事件中心里,称之为订阅者,然后emit将对应的事件进行发布,去执行事件中心里的对应的监听器。
3、Vue组件间的参数传递
props 和 e m i t 。 父 组 件 向 子 组 件 传 递 数 据 是 通 过 p r o p s 传 递 的 , 子 组 件 传 递 给 父 组 件 是 通 过 emit。父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过emit。父组件向子组件传递数据是通过props传递的,子组件传递给父组件是通过emit触发事件来做到的。
$parent 和 $children 获取单签组件的父组件和当前组件的子组件。
父组件中通过 provide 来提供变量,然后在子组件中通过 inject 来注入变量。(官方不推荐在实际业务中适用,但是写组件库时很常用)优点:不需要传参给子组件,直接穿透所有子组件,不管嵌多少层都能使用缺点:子组件需要调用父组件上提供的方法的话,父组件必须provide提供方法,如果子组件inject了某方法,但是父组件没有提供,就会报错。
5、watch和computed (对象有几个属性、被缓存)
watchEffect 和watch区别
6、reactive与ref区别
ref通常用来定义基本类型数据
reactive用来定义:对象(或者数组)类型数据
ref也可以用来定义对象或者数组类型的数据,内部会通过reactive转为代理对象
ref通过Object.defineProperty()的get和set实现数据代理。
reactive使用Proxy实现数据代理,并且通过Reflect操作源对象内部的数据。
ref操作数据需要.value,template模板中不需要。
reactive都不需要,value
shallowReactive 只相应本身,不响应内嵌对象 shallowReadonly
toRefs toRef
ref、toRef、toRefs 都可以将某个对象中的属性变成响应式数据
ref的本质是拷贝,修改响应式数据,不会影响到原始数据,视图会更新 toRef、toRefs的本质是引用
toRef 一次仅能设置一个数据,接收两个参数,第一个参数是哪个对象,第二个参数是对象的哪个属性
toRefs接收一个对象作为参数,它会遍历对象身上的所有属性,然后挨个调用toRef执行
JavaScript
const fooRef = toRef(state, 'foo')
ref 被用来给元素或子组件注册引用信息会被挂载到父组件$refs上面
7、render
render函数的优先级高于根据 template
8、路由
VueRouter 和 createRouter
hash模式 和 history模式
hash模式 #号 window.location.hash读取 不会请求服务器,hash不会重加载页面
history模式:history采用HTML5的新特性;且提供了两个新方法:window.history.pushState/replaceState
hash兼容IE8以上,history兼容IE10以上
html和html5区别:h5第五个版本,增加了一些对视频、svg、meta的一些支持
$route和 $router的区别是什么?
Router 传参 Params 和 Query
9、keep-alive
include(逗号分隔字符串、reg、Array) exclude max(LRU 算法模式)
<keep-alive> 不会在函数式组件中正常工作,因为它们没有缓存实例。
actived: 在激活的时候的使用,第一次激活实在mounted之后执行
dectived:在失活的时候使用。
v-model修饰符 (layz、number、trim)事件修饰符 native once(渲染一次) prevent(鼠标的左右点击)
事件动态写法 @[event](v-on) :[key] (v-bind) v-loack
10、component slot teleport transition
<component :is="currentView"></component>
1、Vue 没有哪只的防抖 截流
Lodash 可以帮忙实现 _.debounce(()=>{})
更多的是在请求里面 相同参数请求,500ms内只能请求一次
12、key data: {} 和 data()
防止数据污染
组件是用来复用的,JS 里对象是引用关系,这样作用域没有隔离,
而 new Vue 的实例,是不会被复用的
13、Vuex (state、Getter、Mutation、action、module)
Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地
getters 可以对State进行计算操作,它就是Store的计算属性
通过mapState把全局的 state 和 getters 映射到当前组件的 computed
14、vue 中使用了哪些设计模式
1、工厂模式 - 传入参数即可创建实例
虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode。
2、单例模式 - 整个程序有且仅有一个实例
vuex 和 vue-router 的插件注册方法 install 判断如果系统存在实例就直接返回掉。
3、发布-订阅模式。(vue 事件机制)
4、观察者模式。(响应式数据原理)
5、装饰器模式(@装饰器的用法)
6、策略模式,策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案 - 比如选项的合并策略
15、你都做过哪些 Vue 的性能优化?
这里只列举针对 Vue 的性能优化,整个项目的性能优化是一个大工程。
对象层级不要过深,否则性能就会差。
不需要响应式的数据不要放在 data 中(可以使用 Object.freeze() 冻结数据)
v-if 和 v-show 区分使用场景
computed 和 watch 区分场景使用
v-for 遍历必须加 key,key最好是id值,且避免同时使用 v-if
大数据列表和表格性能优化 - 虚拟列表 / 虚拟表格
防止内部泄露,组件销毁后把全局变量和时间销毁
图片懒加载
路由懒加载
异步路由
第三方插件的按需加载
适当采用 keep-alive 缓存组件
防抖、节流的运用
服务端渲染 SSR or 预渲染
16、Vue中的scoped的实现原理以及scoped穿透的用法
PostCSS给一个组件中的所有dom添加了一个独一无二的动态属性
17、vue 中怎么重置 data?
拿到原始data 对当前data复值 Object.assign(this.$data, this.$options.data());
18、Observer (数据的观察者)、Watcher 「订阅者」、dep(依赖管理)
Observer顾名思义是观察者,观察的就是 data,它通过数据劫持使 data 的读写都处于它的监管之下
// src/core/observer/index.js
// ...
const dep = new Dep()
// ...
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// ...
dep.depend()
//...
},
set: function reactiveSetter (newVal) {
// ...
dep.notify()
},
Watcher 「订阅者」
vm.$mount挂载,在这之后会执行mountComponent方法,Watcher就是在这里实例化的
// src/core/instance/lifecycle.js
export function mountComponent () {
// ...
new Watcher(vm, updateComponent, noop, {
// ...
}, true /* isRenderWatcher */)
}
Watcher 的定义如下,实例化时会执行 get 方法对传入的 updateComponent 进行求值,updateComponent 也就是 _render 函数,执行 _render 函数会读取 data 数据从而触发 getter 进行依赖收集。
// src/core/observer/watcher.js
export default class Watcher {
// 对 getter 求值,进行依赖收集
get () {}
// 触发更新
update() {}
}
Observer 将数据定义为响应式,每个 Observer 实例都有自己的 Dep 来管理依赖。实例化 Wacther 的时候进行求值会触发 getter ,进而执行 dep.depend() 将当前 Wacther 加入 Dep 维护的依赖列表,这就是依赖收集过程。
19、vue 父子组件生命周期执行/渲染顺序
父beforeCreate => 父created => 父beforeMount => 子beforeCreate => 子created => 子beforeMount => 子mounted => 父mounted
在数据更新阶段执行顺序为:
父beforeUpdate => 子beforeUpdate => 子updated => 父updated
在组件销毁阶段执行顺序为:
父beforeDestroy -> 子beforeDestroy -> 子destroyed -> 父destroyed
由此可见,其实所有周期规律就是:只要子组件被引入触发,所处不管任何周期都是父组件先开始执行,然后等到子组件执行完,父组件收尾。
20、vue2、vue3中自定义v-model的使用区别
Vue2 v-model 语法糖原理::value="数据" @input="数据=$event"
Vue3 v-model 语法糖原理::modelValue="数据" @update:modelValue="数据=$event
vue2中只允许在组件上使用一个 model,vue3中双向数据绑定的API标准化,组件上允许使用多个model
vue3 proxy 有什么缺点 浏览器兼容不好
23、vue.nextTick实现
在DOM事件中使用Vue.nextTick 默认使用宏任务, 其他地方使用Vue.nextTick默认使用微任务。
vue 大多数情况下优先使用微任务, 很少的地方使用宏任务
if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {
macroTimerFunc = () => {
setImmediate(flushCallbacks)
}
}
优先检测 setImmediate
其次检测MessageChannel 支持情况
上面都不支持就使用最原始的setTimeout
vue nextTick 微任务实现
优先检测 Promise
如果不支持Promise, 还是使用宏任务
TS基础 (稳定版本4.2.3)
TypeScript 的主要特点是什么?使用 TypeScript 有什么好处?
跨平台、es6大部分包含、面向对象、静态类型、DOM 操作、
ts更具有表现力、更以阅读、面向对象编程、规范、ts面向编程的优势、代码可读性极强
TypeScript 的原始数据类型有哪些? 什么是泛型?TS中的类; never 和 void 的区别
number、string、boolea、viod 、枚举、Null\\undfined元祖[string, number]
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,我们希望传入的值是什么类型,返回的值就是什么类型
TypeScript 是面向对象的 JavaScript。而其中的类描述了所创建的对象共同的属性和方法
void 表示没有任何类型;never 表示一个不包含值的类型,即表示永远不存在的值。
拥有 void 返回值类型的函数能正常运行。拥有 never 返回值类型的函数无法正常返回,无法终止,或会抛出异常。
TypeScript 和 JavaScript 的区别是什么?
Ts是js超群、Ts面相对象、ts有 接口、类型、静态类、枚举、modules (模块)
什么是构造函数,构造函数作用是什么?实例化是什么?方法重写是什么?
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。
什么是可索引类型接口?什么是函数类型接口?类类型接口?混合类型接口?
可索引类型一般用来约束数组和对象
函数类型接口对方法传入的参数和返回值进行约束
类类型接口: 接口(抽象类的)多实现implements
混合类型接口:一个对象可以同时做为函数和对象使用
如何编译Typescript
Tsc 手动
Tsc watch 监听
TypeScript 合并js区别
interfaces 接口
classes 类
enumerated types 枚举类型
generics 泛型
modules 模块
instanceof (num instanceof Array),反回布尔值
typeof 得出当前类型 返回类型字符串
interface只能定义对象类型, 而type声明可以声明任何类型,包括基础类型、联合类型或交叉类型。
void,void(0),void 0
源码涉及到 undefined 表达都会被编译成 void 0
在ts中用void表达没有任何返回的值的函数。
undefined 是 js 原始类型值之一,也是全局对象window的属性,在一部分低级浏览器(IE7-IE8)中or局部作用域可以被修改,
undefined在js中,全局属性是允许被覆盖的,ES5中尝试解决上述问题但是在局部作用域内,undefined依然是可变的
void 66+99没有加括号,代码从左到右执行,void 66 是 undefined—undefined + 99是NaN
void 返回值永远是undefined
1. 什么是 any 类型,何时使用 ?什么是declare?类型断言(as)?
当你没有明确提供类型时,TypeScript假定变量是any类型,并且编译器无法从周围的上下文中推断出类型
.d.ts的顶级声明必须以declare开头
以declare声明的变量和模块后,其他地方不需要引入,就可以直接使用了
As 告诉编辑器我知道我在做什么
et someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
2. 什么是void,什么时候使用void类型 ?
void 表示变量没有类型,它充当与任何相反的类型,它在不返回值的函数中特别有用
3. 如何在 TypeScript 中指定可选属性
age?: number;
如何声明枚举值
enum CardinalDirection {
North = 1,
East,
South,
West,
}; // 会递增
4. Type interface class 区别
Interface 只能声明对象, type 可以声明任何基本类型、联合类型 、元祖类型
interface 可以继承interface/ type ;type只能合并 进行合并 &
Class 实现interface
Interface Dog {
name: strng
}
Interface Cat {
name: strng
age: number
}
Interface Cat extends Cat {
Color: string
}
inte
Type name = string; type animal = { name: string; age: number }
Type animal = Cat | DOg // 联合类型
Type animal = [ Cat ,DOg] //元祖类型
// interface extends type
Interface Cat extends animal {
Color: string
}
interface Person { name: string}
interface Person { age: number}
// 合并为:interface Person { name: string age: number}