vue相关了解及深拷贝与浅拷贝

概述:

vue 是一个前端的js库,它简化对应的js原生的操作,提高了对应的浏览器性能(虚拟dom,diff算法)。vue作者(尤雨溪),被阿里巴巴维护(vue2诞生于2015年 vue3诞生于2020年)vue是一个mvvm的框架。

在这里插入图片描述

单向绑定

概述:

vm将对应的m的数据 渲染到v上

主要的操作

vm要将m的数据进行劫持 ,vm再控制v的渲染

vue2的劫持 (es5语法)

Object.defineProperty (对于数组不能进行劫持 ) + 重写数组的方法(数组内容改变的方法 (7个方法))

vue3的劫持 (es6语法)

proxy (都能劫持 (万物皆对象))

双向绑定

概述:

vm将对于的m的数据渲染到v,v的页面的数据发生变化m也会发生变化

主要的操作
单向相关的操作

vue2的Object.defineProperty

vue3的proxy

监听页面数据发生变化 (ObServer 观察者模式)

vm控制v的渲染

避免大量操作dom (导致多次和重绘和回流 影响性能)

解决方案
虚拟dom (虚拟是一个对象存在于内存中(抽取对应的实体dom形成的对象))
<a href=''>哈哈哈<span>嘻嘻<span><a>
//属性文本及子元素 虚拟dom对象
let objA = {
	href:'',
	text:'哈哈哈',
	tagName:'A'
	children:{
		tagName:'SPAN',
		text:'嘻嘻'
	}
}
  • 相关操作在对应的虚拟dom上进行 (避免重绘回流)
  • 完成对应的操作后再进行渲染 (将虚拟dom变成实体dom)(只有一次的重绘和回流操作)
diff算法 (用于比对虚拟dom的差异 (减少渲染量))
模板引擎 (帮助渲染)

双向数据绑定的实现

vue的双向数据绑定
 <!-- 准备容器 -->
  <div id="app">
    <!-- v-model是vue中实现双向数据绑定的指令 -->
    <input type="text" v-model="message">
    <!-- 查看对应的对应的message的值  模板语法-->
    {{message}}
  </div>
  <!-- 链入vue.js -->
  <script src="./js/vue.js"></script>
  <script>
    new Vue({
      el:'#app' ,//挂载点
      data:{ //数据
        message:'hello world'
      }
    })
  </script>
vue2的实现(Object.defineProperty + obServer)
  • Object.defineProperty 来进行数据劫持

    递归data中的数据来进行劫持

  • 当前ObServer监听对应的输入框的内容发生变化

  • 重新设置对应的data中的数据(this._data)

  • 数据重新设置再进行对应的模板比对渲染对应的页面

class Vue {
  constructor(options) {
    let {
      el,
      data
    } = options
    this.el = el //挂载点
    this.data = data //数据
    //用于劫持的容器
    this._data = JSON.parse(JSON.stringify(data))
    //获取对应的内容 el里面内容
    this.content = document.querySelector(this.el)
    //读取里面的 {{}}的内容 进行替换
    this.textContent = this.content.innerHTML
    this.kidnap(this.data, this._data)
    this.comparis()
  }
  //递归遍历data中的数据进行劫持 (递归遍历data中的数据进行劫持操作)
  kidnap(obj, _obj) {
    let that = this
    for (let key in obj) {
      //如果它是一个对象继续往下劫持
      if (typeof obj[key] == 'object') {
        this.kidnap(obj[key], _obj[key])
      }
      //Object.defineProperty来进行劫持
      Object.defineProperty(obj, key, {
        enumerable: true,
        configurable: true,
        get() {
          return _obj[key]
        },
        set(newValue) {
          _obj[key] = newValue
          that.comparis()
        }
      })
    }
  }
  //模板比对解析
  comparis() {
    //{{message}} {message.age.age}
    this.content.innerHTML = this.textContent.replace(/\{\{([\w.]*)\}\}/ig, (v) => {
      //{{message}}
      //读取对应的里面key 利用data里面的数据来进行替换
      // console.log(RegExp.$1) //读取分组1里面的内容
      var arr = v.substring(2,v.length-2).split('.')
      let value = this.data
      //遍历获取数据
      for (var i of arr) {
        value = value[i]
      }
      //遍历arr获取数据 
      return value
    })
    //读取对应的input框的v-model属性进行替换
    //先找input框
    let inputs = this.content.querySelectorAll('input')
    let that = this
    //获取所有具备v-model属性的input框架
    Array.from(inputs).filter((v) => {
      return v.getAttribute('v-model')
    }).forEach(v => {
      let key = v.getAttribute('v-model')
      //利用观察者模式进行监听
      //调用obServer
      v.oninput = () => {
        that.data[key] = v.value
      }
      //读取对应的v-model 设置对应的内容
      v.value = that.data[key]
    })
  }

}

diff算法比对总结

diff算法用于比对新旧虚拟dom,利用打补丁包的形式来比对的。

比对流程
//虚拟dom
let vDOM = {
    //虚拟dom中的节点
    vnode:{
        attributes:{},
        text:"hello",
        tagName:'',
        key:'aaaaaxxxsda',
        children:{
            vnode:{
                attributes:{},
                text:"",
                tagName:'',
                key:'dbbbbadba'
            },
            vnode:{
                attributes:{},
                text:"",
                tagName:'',
                key:'ccccddef'
            }
        }
    }
}

先比对自身 通过key来找到自身 (key是唯一的 下标不能作为key)

先比对key 再比对自身的属性 比对文本 再比对子元素 递归比到低

在这里插入图片描述

深拷贝和浅拷贝

浅拷贝

复制快捷方式 (快捷方式的文件是俩个 但是里面指向的内容都是一个内容)

概述

拷贝的对象和原本的对象不是一个对象,但是内容完全一样,其次里面的内容的地址完全一致

在这里插入图片描述

  • 浅拷贝不等于赋值它会开辟一个新的内存空间,和原本的地址不一致
  • 浅拷贝里面的内容都是拷贝对应的地址 所以和原本的内容地址一致
实现浅拷贝
Object.assign
let obj = {
    user: {
        age: 18
    }
}
let newObj = obj
console.log(newObj == obj) //true 赋值的地址是共享的
//浅拷贝
let copyObj = Object.assign({}, obj)
//浅拷贝会产生一个新的对象 和原本的对象地址不一样
console.log(obj == copyObj) //false
//里面的内容的地址是共享的
console.log(obj.user == copyObj.user) //true
obj.user.age = 20
console.log(copyObj.user.age) //20
使用扩展运算符实现数组及对象的浅拷贝
//使用扩展运算符
let copyObj1 = {...obj}
console.log(copyObj1 == obj) //false
console.log(copyObj1.user == obj.user) //true
let arr = [{age:19},{name:'jack'}]
let copyArr = [...arr]
console.log(copyArr == arr) //false
console.log(copyArr[0] == arr[0]) //true
使用数组的concat方法
//使用数组的concat方法实现数组的浅拷贝
let concatArr = [].concat(arr)
console.log(concatArr == arr) //false
console.log(concatArr[0] == arr[0]) //true
使用数组的slice方法
//使用数组的slice方法
let sliceArr = arr.slice()
console.log(sliceArr == arr) //false
console.log(sliceArr[0] == arr[0]) //true
使用自定义函数遍历
function clone(obj){
	let newObj = {}
	for(let key in obj){
		newObj[key] = obj[key]
	}
	return newObj
}
let obj = {user:{}}
let copyObj = clone(obj)
console.log(copyObj == obj) //false
console.log(copyObj.user == obj.user) //true
第三方插件 lodash.js (提供的clone方法)

https://www.lodashjs.com/

let obj1 = {
    user: {}
}
let cloneObj = _.clone(obj1)
console.log(cloneObj == obj1)//false
console.log(cloneObj.user == obj1.user)//true

深拷贝

文件复制粘贴

概述

拷贝的是对应的值,不拷贝地址。

实现方式
JSON.Stringify JSON.parse
let obj = {list:['1','2'],user:{name:'tom'}}
let copyObj = JSON.parse(JSON.stringify(obj))
console.log(obj == copyObj) //false
console.log(obj.list == copyObj.list) //false
console.log(obj.user == copyObj.user) //false
console.log(obj.user.name == copyObj.user.name) //true
使用lodash.js cloneDeep方法
//使用lodash.js _.cloneDeep
let cloneObj =  _.cloneDeep(obj);
console.log(obj == cloneObj) //false
console.log(obj.list == cloneObj.list) //false
console.log(obj.user == cloneObj.user) //false
console.log(obj.user.name == cloneObj.user.name) //true
自定义递归书写对应的深拷贝 (重点)
//自定义函数实现 (递归)
//自定义方法传入对应的需要拷贝的对象
function deepClone(obj) {
    //判断是否为对象 如果为对象那么进行拷贝 如果不是对象直接返回
    //如果不是对象 或者 它为null
    if(typeof obj == 'function'){
       //返回新的函数
       return obj.bind(this)
    }
    if (typeof obj != 'object' || !obj) {
        //直接返回
        return obj
    }
    //如果是对象 Regexp Object Array Date
    if (obj instanceof RegExp) { //如果是正则
        return new RegExp(obj)
    }
    //如果它是Date 日期
    if (obj instanceof Date) {
        return new Date(obj.getTime())
    }
    let copyObj = {}
    //判断是数组还是对象
    if (obj instanceof Array) {
        copyObj = []
    }
    //遍历对应的对象里面内容
    for (let key in obj) {
        //递归
        copyObj[key] = deepClone(obj[key])
    }
    return copyObj
}

总结

  • vue是一个mvvm的框架,vm是内置的,不需要你去管理。
  • vue的数据劫持是通过 Object.defineProperty (vue2) 重写了数组的7个方法(不能对于数组进行劫持) Proxy (vue3)
  • vue主要劫持是data中的数据 (_data的属性)递归去进行劫持
  • vue的双向数据绑定主要是通过数据劫持+obServer(观察者模式)
  • vue是利用虚拟dom来进行对应的比对(里面采用diff算法)使用模板引擎进行解析渲染
  • diff算法比对先比对自身(key),再比对对应的vnode,再比对对应的子节点(递归比对) 采用patch补丁包的形式来进行重新渲染
  • 深拷贝和浅拷贝 深拷贝拷贝的是值 浅拷贝拷贝的是地址 不管深浅拷贝都会产生一个新的对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值