前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【一文秒懂】带你彻底搞懂范式与反范式数据库设计

【一文秒懂】带你彻底搞懂范式与反范式数据库设计

作者头像
玖柒的小窝
修改2021-11-02 10:58:37
4770
修改2021-11-02 10:58:37
举报
文章被收录于专栏:各类技术文章~

想要讲明白 JS 中对象的浅拷贝和深拷贝,需要从它的数据类型说起。

JavaScript中的数据类型

一般我们说到JS的数据类型指的是它的原始(Primitive types)数据类型(共有6种):

  • String
  • Number
  • Boolean
  • Symbol(ES6新增)
  • Null
  • Undefined

这些类型可以直接操作保存在变量中的实际值。

此外,JS中还有引用数据类型:对象(Object)、数组(Array)、函数(Function)。在JS中除了基本数据类型以外的都是对象,数组是对象,函数是对象,正则表达式是对象,日期也是对象...

栈(stack)和堆(heap)

stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不确定。

基本数据类型是指存放在栈中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问:

代码语言:javascript
复制
var a = 10;
var b = a;
b = 20;
console.log(a); // 10
console.log(b); // 20

被重新赋值的b并没有影响a的值。

引用类型是存放在堆内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存。

代码语言:javascript
复制
var obj1 = new Object();
var obj2 = obj1;
obj2.description = "Hello World";
console.log(obj1.name); // Hello World

说明这两个引用数据类型指向了同一个堆内存对象。

引用传递和值传递

在变量复制的过程中,对象的复制是引用传递, 基础类型是值传递。

  • 在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的value而已。
  • 引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。

浅拷贝

当我们想要拷贝一个对象时,如果它的属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。

代码语言:javascript
复制
const obj = { name: "bird", abilities: ["fly","sing"]}

function copy(target){
   var objNew ={};
   for (var i in target){
      objNew[i] = target[i]
   }    
   return objNew;
}

const objCopy = copy(obj)
console.log(objCopy) // { name: "bird", abilities: ["fly","sing"]}

objCopy.name = "bird01" // 修改原始类型的属性
console.log(objCopy) // {name: 'bird01', abilities: ["fly","sing"]}

objCopy.abilities.push("lay eggs") // 修改引用类型的属性
console.log(objCopy) // {name: 'bird01', abilities: ["fly","sing", 'lay eggs']}

console.log(obj) //  {name: 'bird', abilities: ["fly","sing", 'lay eggs']} 

可以看到obj的abilities属性随着objCopy的改变而改变,两个对象之间发生了关联。需要注意的是Object.assign()或者是Spread Operator都是浅拷贝:

代码语言:javascript
复制
const obj = { name: "bird", abilities: ["fly","sing"]}
const objCopy = Object.assign({}, obj) // { name: "bird", abilities: ["fly","sing"]}
objCopy.abilities.push("lay egg")
console.log(obj) // { name: "bird", abilities: ["fly","sing","lay egg"]}

const objCopy2 = {...obj} // { name: "bird", abilities: ["fly","sing","lay egg"]}
objCopy2.abilities.pop()
console.log(obj)  //  { name: "bird", abilities: ["fly","sing"]}

这样的关联往往不是我们希望看到的,那么就有了深拷贝。

深拷贝

使用JSON.parse/stringify可以复制属性中含有数组的情况:

代码语言:javascript
复制
const a = { arr: ["Google","Baidu"]}
const clone = JSON.parse(JSON.stringify(a))
clone.arr.pop()
console.log(a) // { arr: ["Google","Baidu"]}

可见clone的属性改变已经不再和a发生关联。不过对于其他类型的属性,在这个过程中可能会放生丢失:

代码语言:javascript
复制
const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost
}

所以借助一些第三方的库是个不错的选择,比如:

  • lodash - cloneDeep; can be imported separately via the lodash.clonedeep module and is probably your best choice if you're not already using a library that provides a deep cloning function

在不久以后也许你可以使用structuredClone 2021 update: The structuredClone global function is coming to browsers, Node.js, and Deno soon. 链接

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JavaScript中的数据类型
  • 栈(stack)和堆(heap)
  • 引用传递和值传递
  • 浅拷贝
  • 深拷贝
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档