前端知识梳理(Vue与JS篇)

1、深拷贝与浅拷贝

1.1 什么是深拷贝与浅拷贝

在了解深浅拷贝之前我们需要了解一下都有哪些数据类型

js中数据类型主要分为两大类:基本数据类型与引用数据类型

基本数据类型(值类型):字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol

引用数据类型:对象(Object)、数组(Array)、函数(Function)

基本数据类型:数据直接存储在栈(stack)中的数据。
引用数据类型:地址直接存储在栈(stack)中,真实的数据存储在堆内存中。当需要取引用类型数据时,会先检索栈中地址,取得地址后再去堆中获取真实的数据。

浅拷贝:会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用地址,当引用地址指向的值改变时也会跟着变化。

对于复杂数据类型来说:浅拷贝后的变量改变影响旧变量,未实现完全的隔离

但对于基本数据类型数据没有啥影响

浅拷贝方法:for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 、=(赋值操作)等

深拷贝:深拷贝和浅拷贝是针对复杂数据类型(对象及数组)来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。

        深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

.2 浅拷贝实现方式

浅拷贝是我们在使用基础数据类型时最常用到的一个方式,浅拷贝方法:for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 、=(赋值操作)等

1、Object.assign

这里我们可以看到当只有一层的时候,修改一个变量另一个不受影响

但是二层之后,修改一个变量的值另一个也受到影响,因此是浅拷贝(以下几个方法也是同理)

let arr = ['张三',{name: '小明'}, {name: '小红'}]

let arr1 = Object.assign({},arr)

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

 2、扩展运算符 ...

let arr = ['张三', { name: '小明' }, { name: '小红' }]

let arr1 = [...arr]

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

 3、Array.prototype.slice()

 let arr = ['张三', { name: '小明' }, { name: '小红' }]

let arr1 = arr.slice()

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

 4、Array.prototype.concat()

let arr = ['张三', { name: '小明' }, { name: '小红' }]

let arr1 = arr.concat()

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

5、for in 与 =(赋值操作)

let arr = ['张三', { name: '小明' }, { name: '小红' }]

let arr1 = []

for (let key in arr) {

      arr1[key] = arr[key];

}

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

3 深拷贝实现方式

深拷贝主要针对的是复杂数据类型(对象、数据、数组对象)

深拷贝常用的实现:JSON.parse(JSON.stringify(obj)) 、递归实现、函数库lodash

3.1、JSON.parse(JSON.stringify(obj))

JSON.parse(JSON.stringify(obj))是最简单的实现深拷贝的方法,直接拿来就能用

但是也有一个固有的缺陷

1、对象的属性值是函数时,无法拷贝
2、原型链上的属性无法拷贝
3、会忽略undefined、symbol
4、不能处理RegExp、Date类型数据 

let arr = [{
        name:'小明'
      },{
        name:'小红'
      }]
    let arr1 = JSON.parse(JSON.stringify(arr))
    arr1[0].name = '我换名字了'
    console.log(arr,arr1);

实现效果:拷贝之后,变量之间不相互影响

3.2、递归实现(尽量能手写

如果是基本数据类型就直接赋值操作,如果不是基本数据类型就继续递归调用

 // 递归方法
    function deepClone(source) {
      // [] => Array(基类) {} => Object(基类)
      // constructor 构造器
      const targetObj = source.constructor === Array ? [] : {}
      for (let keys in source) {
        // key是否存在
        if (Object.hasOwnProperty.call(source, keys)) {
          // 引用数据类型
          if (source[keys] && typeof source[keys] === 'object') {
            // 递归
            targetObj[keys] = deepClone(source[keys])
          } else {
            // 基础类 直接赋值
            targetObj[keys] = source[keys]
          }
        }
      }
      return targetObj
    }
    let arr = [{
      name: '小明'
    }, {
      name: '小红'
    }]
    let arr1 = deepClone(arr)
    arr1[0].name = '我换名字了'
    console.log(arr, arr1);

运行效果:

3.3、使用函数库lodash中的cloneDeep

Lodash 通过降低 array、number、objects、string 等等的使用难度从而让 JavaScript 变得更简单。 Lodash 的模块化方法 非常适用于:

  • 遍历 array、object 和 string
  • 对值进行操作和检测
  • 创建符合功能的函数

使用lodash

1、安装lodash

npm i --save lodash

2、按需引入

import _ from "lodash"

3、使用

let arr = ['张三', { name: '小明' }, { name: '小红' }]

let arr1 = _.cloneDeep(arr)

arr1[0] = '我换名字了'

arr1[1].name = '我又换名字了'

console.log(arr, arr1);

运行结果:两个变量互不影响是深拷贝

参考链接:

Lodash 简介 | Lodash中文文档 | Lodash中文网

2、如何让谷歌浏览器支持小字体

谷歌浏览器默认的字体最小12px,如果不去调浏览器配置,小于12px的字体默认展示是12px。如何用代码实现

scale(参数)缩放实现小字体

参数:大于1放大;小于1缩小;等于1不变

<div class="parent">
    大字体
    <div class="small-font">小字体</div>
</div>

<style>
  .parent{
     font-size:12px;
  }
  .small-font{
     transform:scale(0.8);
     -webkit-transform:scale(0.8);
  }
</style>

3、字面量与Object.create()的区别

Object.create()静态方法以一个现有对象作为原型,创建一个新对象。

Object.create(proto, propertiesObject)

proto 必填,可以是null也可以是对象

propertiesObject 不必填,默认属性有value、writable(不可写)、configurable(可配置)、enumerable(可枚举)

 Object.create(null) 创建的对象无原型,等价于

o = Object.create(null);
// 等价于:
o = { __proto__: null };

Object.create(obj) 创建的对象以obj对象为原型,这样就可以保证新创建的对象和原有对象解耦,当我们操作对象b或者c时并不会影响原有数据

propertiesObject  

o2 = Object.create(
  {},
  {
    p: {
      value: 42,
      writable: true,
      enumerable: true,
      configurable: true,
    },
  },
);
// 这与以下语句不等价:
// o2 = Object.create({ p: 42 })
// 后者将创建一个原型为 { p: 42 } 的对象。

propertiesObject设置只读的时候,对象中键值不可改

 

个人总结:

1、Object.create(null)创建的对象,无原型比较纯洁

2、Object.create()可以实现一个继承目标且可高度配置的对象

3、字面量方式创建比较简洁

4、实现树形结构数据筛选

this.treeList = this.filterTree(this.listQuery.keyword, res.data)

filterTree(searchValue, searchTopicCatalogs) {

      let tempSearchArr = [];

      searchTopicCatalogs.forEach((treeNode) => {

        if (treeNode.baseMenuEntityList && treeNode.baseMenuEntityList.length > 0) {

          // 后序遍历
          let tempArr = this.filterTree(searchValue, treeNode.baseMenuEntityList)||[];

          // 当前树节点的子节点存在匹配字符,直接纳入数组
          if (tempArr.length > 0) {
            treeNode.baseMenuEntityList = tempArr
            tempSearchArr.push(treeNode);

          //当前树节点存在匹配字符
          }else {
            if (treeNode.menuName.indexOf(searchValue) >= 0) {
              tempSearchArr.push(treeNode);
            }
          }

        // 叶子节点
        }else {
          // 当前树节点存在匹配字符
          if (treeNode.menuName.indexOf(searchValue) >= 0) {
            tempSearchArr.push(treeNode);
          }
        }
      });
      return tempSearchArr;
    },

实现结果:

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱编程的小学究

愿你有所收获

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值