vue双向绑定的原理?
首先要了解MVVM(model数据层,view视图层,viewmodel数据逻辑层),viewmodel和view、model交互是双向的。数据层发生变化的时候,可同布更新视图层,当视图层发生变化的时候,同步更新数据层。
核心是采用数据劫持结合发布者-订阅者模式的方式,
Vue2:Object.defineProperty()劫持各个属性的setter,getter,通过拦截对象的读取和修改操作来实现对数据的追踪。在数据变动时发布消息给订阅者,触发相应的监听回调,达到监听数据变动的目的。
Vue3: 采用了ES6中的 Proxy 方法,可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除,而且还可以监听数组。
区别:
Vue2是监听对象中的一个属性,必须定义在data中,无法检测对象的添加或移除,不能利用索引直接设置一个数组项,也不能修改数组的长度,可以使用$set强制绑定。
Vue3是监听整个对象。可以监听对象某个属性值的变化,还可以监听对象属性的新增和删除,而且还可以监听数组
深浅拷贝
浅拷贝,深拷贝是相对于引用数据类型来说的(Array, Object, Function, 存放在堆内存中的对象,变量其实保存的是堆内存中的引用地址)
浅拷贝:简单来说就是把a的值赋给b, a改变的时候b也改变了。除了直接赋值, Array.form()方法也可以实现浅拷贝
深拷贝:创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”(就是a的值改变与不会对b产生影响)
array.slice()、array.concat(),这两种方式都会返回数组的副本,是第一层拷贝,只对数组元素是基本类型变量(如number,String,boolean)的简单数组有效。对第一级数组元素是对象或者数组等引用类型变量的数组无效。
Object.assign(), 这个方法是对对象的复制,object.assign()对引用数据类型第一层是深拷贝,第二层就失效了
JSON.parse(JSON.stringify( )), 可以拷贝每次层的对象和属性,利用JSON.stringify将对象序列化(JSON字符串),再使用JSON.parse来反序列化还原js对象。序列化的作用是存储和传输。
(不拷贝引用对象,拷贝一个字符串会新辟一个新的存储地址,这样就切断了引用对象的指针联系。)
原型链
当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__(隐式原型)属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的__proto__属性所指向的那个对象(可以理解为爷爷对象)里找,这种通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链。
闭包
闭包就是能够读取其他函数内部变量的函数。可以理解成“定义在一个函数内部的函数“。防抖、节流的函数也会形成一个闭包。闭包会使函数中的变量都保存在内存中,不会被垃圾回收机制回收,占用内存导致内存泄露;解决方法是,在退出函数之前,将不使用的局部变量全部删除。
闭包的主要作用有以下几点:
实现模块化:通过闭包可以创建私有变量和函数,实现对外部的隔离,避免命名冲突。
实现函数柯里化:将多个参数的函数转换成单个参数的函数,使函数更具通用性和复用性。
实现缓存:可以将计算结果缓存下来,避免重复计算,提高性能。
实现异步编程:通过闭包保存上下文信息,实现异步任务的回调函数。
防抖节流的实现也是一个闭包。
防抖、节流
防抖:防止抖动,避免事件的重复触发。不管事件触发多少次,都只执行最后一次。使用场景:按钮点击。
节流:减少流量,每隔一段时间执行。即,控制事件触发的频率,使用场景:滚动条。第一次立即执行
//防抖函数
function debounce(fn,delay){
let timer = null //借助闭包
return function() {
if(timer) clearTimeout(timer)
timer = setTimeout(fn,delay)
}
}
其原理就是每次调用 debounce 之后,之前的 timeout 会被清理掉,并且返回一个新的 timeout。在 timeout 中设定的时间间隔过去后,原本的函数被调用
v-model原理
其实它是一个语法糖
v-bind绑定一个value属性
v-on指令给当前元素绑定input事件
<input v-model="message">
<input v-bind:value="message" v-on:input="message = $event.target.value">
input 元素本身有个 oninput 事件,这是 HTML5 新增加的,类似 onchange ,每当输入框内容发生变化,就会触发 oninput ,通过 $event 把最新的 value 传递给 something。我们仔细观察语法糖和原始语法那两行代码,可以得出一个结论:在给 input 元素添加 v-model 属性时,默认会把 value 作为元素的属性,然后把 input 事件作为实时传递 value 的触发事件
v-for为什么要用key
什么是symbol
vue中的data为什么是一个函数
在Vue中,data选项是一个函数,用于定义组件的初始数据。将data作为函数的主要原因是为了使每个实例都能够维护其自己的数据副本,而不是共享相同的数据对象。
当Vue实例化一个组件时,它会调用该组件的构造函数并创建一个新的Vue实例。在创建实例时,Vue会执行data函数并将其返回值作为实例的初始数据对象。由于data函数会在每个实例化时都会被调用,所以每个实例都会有自己独立的数据对象。如果将data选项定义为一个普通对象,则该对象将被所有实例共享,这可能会导致意外的副作用和难以调试的问题。但是,将data选项定义为函数可以确保每个实例都有自己独立的数据对象,从而避免这些问题。
因此,将data选项定义为函数是Vue中的一个重要设计决策,它保证了每个实例都有自己的数据副本,并允许Vue追踪数据对象的变化并更新视图。
v-if和v-show
1、v-if在条件切换时,会对标签进行适当的创建和销毁,而v-show则仅在初始化时加载一次,因此v-if的开销相对来说会比v-show大。
2、v-if是惰性的,只有当条件为真时才会真正渲染标签;如果初始条件不为真,则v-if不会去渲染标签。v-show不管初始条件是什么,元素总是会被渲染,它仅仅做的只是简单的CSS(display)切换。
3、display: none在 DOM 树中存在,Render(dom + cssom) 树中不存在,v-if在DOM树中不存在
使用场景:v-if适用于不需要频繁切换元素显示和隐藏的情况,v-show适用于需要频繁切换元素的显示和隐藏的场景。
css隐藏元素
display: none
原理:
在 DOM 解析时,元素是存在的,因此在 DOM 树中该元素是存在的。
解析完样式形成 CSS 树,然后将 DOM 树与 CSS 树合并形成 Render 树。在合并时,CSS 树中的样式与 DOM 树中的元素形成一对一或多对一的映射关系,并将具有 display: none 样式的元素未添加到 Render 树中。因此具有 display: none 样式的元素,在 DOM 树中是存在的,但在 Render 树中是不存在的。
浏览器渲染引擎,只渲染 Render 树中已存在的 DOM 元素到页面。
特点:
1、不占据页面标准文档流的位置(空间)。
2、在 DOM 树中存在,Render 树中不存在。
3、会引发重构(reflow),导致页面重新渲染,损耗一定的资源。
4、不能被搜索引擎爬虫检索到。
5、不能做 SEO。(其本具有的权重消失)
6、在页面能查找到此元素。(凡是在 DOM 树存在的元素,都能被查找到)
visibility: hidden
原理/特点:
1、在 DOM 树中存在,在 Render 树中也存在。
2、占据页面标准流的位置(空间)。
3、不会引发 reflow,但会引发 repaint(重构)。(重绘损耗的资源远小于重构)
4、能被搜索引擎爬虫检索到。
5、能做 SEO 优化。
6、在页面也能查找到此元素。
特点:它所注册的事件,在隐藏后不会再触发。
opacity: 0
原理/特点:
1、在 DOM 树中存在,在 Render 树中也存在。
2、占据页面标准流的位置(空间)。
3、不会引发 reflow,但会引发 repaint。
4、能被搜索引擎爬虫检索到。
5、能做 SEO 优化。
6、在页面也能查找到此元素。
特点:元素以及元素内内容是通过完全透明来到达视觉上的隐藏效果。元素所注册的事件是能被触发的。
普通函数和箭头函数区别
(1)箭头函数没有自己的this对象。它的this是继承而来; 默认指向父级作用域。所以不能使用call、apply、bind改变this指向
(2)不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误。
(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
上面四点中,最重要的是第一点。对于普通函数来说,内部的this指向函数运行时所在的对象,但是这一点对箭头函数不成立。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。