JS对象类型赋值和原生类型赋值原理解析

 更新时间:2023年09月20日 09:50:33   作者:Jaxu  
在本文中,我试图以最简洁的方式来阐明JavaScript编程原理中对象类型赋值和原生类型赋值之间的区别,以及它们各自是如何工作的,感兴趣的朋友跟随小编一起看看吧

介绍

  在本文中,我试图以最简洁的方式来阐明JavaScript编程原理中对象类型赋值和原生类型赋值之间的区别,以及它们各自是如何工作的。这也是我希望在我的JavaScript编程生涯早期就已经理解的东西。

JS中的原生类型和对象类型

  首先,让我们回顾一下JavaScript中不同的原生类型和对象类型。
  原生类型:Boolean,Null,Undefined,Number,BigInt(可能不常见),String,Symbol(可能不常见)。
  对象类型:Object,Array,Date,以及许多其它类型。

原生类型赋值和对象类型赋值有什么不同?

原生类型赋值

  将一个原生类型的值赋值给一个变量非常简单,看下面的例子:

const a = 'hello';
const b = a;

  在这个示例中,a的值被设置为hellob的值也被设置为hello。如果我们将b的值修改,a的值不会发生变化。ab之间不存在任何关联。

const b = 'foobar';
console.log(a); // "hello"
console.log(b); // "foobar"

对象类型赋值

  对象类型赋值的工作方式则不同。将一个对象类型的值赋值给一个变量会执行下面这两步操作:

  • 在内存中创建一个对象
  • 将该对象的引用赋值给变量

  这会发生什么呢?让我们看一下:

const a = { name: 'Joe' };
const b = a;

  第一行在内存中创建了一个对象{ name: 'Joe' },然后将该对象的引用赋值给变量a。第二行将同一对象的引用又赋值给了变量b

  接下来,让我们修改分配给b的对象的一个属性:

b.name = 'Jane';
console.log(b); // { name: "Jane" }
console.log(a); // { name: "Jane" }

  由于ab的值指向内存中同一对象的引用,所以对变量b的属性的修改会实际影响到ab

  我们在数组中也可以很清楚地看到这一变化:

const a = ['foo'];
const b = a;
b[0] = 'bar';
console.log(b); // ["bar"]
console.log(a); // ["bar"]

这种变化也适用于函数参数

  这些赋值规则同样也适用于将对象传递给函数的时候。让我们看看下面的例子:

const a = { name: 'Joe' };
function doSomething(val) {
val.name = 'Bip';
}
doSomething(a);
console.log(a); // { name: "Bip" }

  对传递给函数的对象的值进行修改时要小心,除非这是有意而为之的(但我相信在多数情况下你并不希望这样)。

防止意外的修改

  在多数情况下,这种方式是符合预期的。这可以让我们非常方便地将同一对象的引用赋值给不同的变量,不过有时候也会引起一些意想不到的结果,当我们改变对象时,这种行为可能会导致一些非常令人困惑的bug。  

有几种方法可以防止这种行为的发生,这里我会介绍其中的几个,但肯定不止这几种方法。

JavaScript展开操作符(...)

  展开操作符是对对象或数组进行浅拷贝的一个好方法。

const a = { name: 'Joe' };
const b = { ...a };
b.name = 'Jane';
console.log(b); // { name: "Jane" }
console.log(a); // { name: "Joe" }

有关“浅拷贝”

  理解浅拷贝和深拷贝非常重要。对于只有一层深度的对象而言,浅拷贝没有问题,但是对于嵌套的对象则会有问题,让我们看下面的例子:

const a = {
name: 'Joe',
dog: {
name: 'Daffodil',
},
};
const b = { ...a };
b.name = 'Pete';
b.dog.name = 'Frenchie';
console.log(a);
// {
//   name: 'Joe',
//   dog: {
//     name: 'Frenchie',
//   },
// }

  展开操作符只实现了对象的一层深度的拷贝,但是第二层的属性在内存中仍然指向了同一对象。为了解决这个问题,人们想到了一些方法来进行“深拷贝”,例如第三方库deep-copy,或者序列化和反序列化对象。

使用Object.assign

  Object.assign可以用来基于一个对象创建另一个新对象。使用方式如下:

const a = { name: 'Joe' };
const b = Object.create({}, a);

  注意,这仍然是一个浅拷贝!

序列化和反序列化

  序列化和反序列化一个对象可以实现对象的深拷贝,最常见的方法是使用JSON.stringifyJSON.parse

const a = {
name: 'Joe',
dog: {
name: 'Daffodil',
},
};
const b = JSON.parse(JSON.stringify(a));
b.name = 'Eva';
b.dog.name = 'Jojo';
console.log(a);
// {
//   name: 'Joe',
//   dog: {
//     name: 'Daffodil',
//   },
// }
console.log(b);
// {
//   name: 'Eva',
//   dog: {
//     name: 'Jojo',
//   },
// }

  不过这种方法也存在缺点,序列化和反序列化不会保留复杂类型的对象例如函数。

实现深拷贝的第三方库

  使用第三方库来实现深拷贝在实际工作中很常见,特别是当你对要操作的对象的结构和层级不是很清楚时。这些库提供的函数通常都是通过递归操作的方式来实现上述对象浅拷贝的功能。

结论

  也许本文讨论的这些细节看起来有点复杂,但如果你对JS中原生类型赋值和对象类型赋值有所了解的话,这对你而言就是小菜一碟了。你可以尝试一下上文提到的这些例子,如果愿意的话,你也完全可以尝试着自己实现一个对象深拷贝的函数。

到此这篇关于JS基本原理:对象类型赋值和原生类型赋值的文章就介绍到这了,更多相关js对象类型赋值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 微信JSSDK上传图片

    微信JSSDK上传图片

    做过微信开发的都知道,在部分android机型里微信不支持网页上传图片的,这是由于这些机型的文件上传存在内存泄漏,会导致微信闪退,所以微信内置浏览器将文件上传屏蔽,本篇文章给大家介绍使用微信jssdk如何上传图片,需要的朋友可以关注下
    2015-08-08
  • js的alert弹出框出现乱码解决方案

    js的alert弹出框出现乱码解决方案

    alert弹出框出现乱码的情况,想必大家都有遇到过吧,其实解决方法很简单设置charset=utf-8在试试,看看是不是好了
    2013-09-09
  • JavaScript限定复选框的选择个数示例代码

    JavaScript限定复选框的选择个数示例代码

    有10个复选框,用户最多只能勾选3个,否则就灰掉所有复选框,具体实现思路及代码如下,感兴趣的朋友可以参考下,希望对大家有所帮助
    2013-08-08
  • 一个无限级XML绑定跨框架菜单(For IE)

    一个无限级XML绑定跨框架菜单(For IE)

    一个无限级XML绑定跨框架菜单(For IE)...
    2007-01-01
  • ant design中实现table的表格行的拖拽

    ant design中实现table的表格行的拖拽

    这篇文章主要介绍了ant design中实现table的表格行的拖拽,文章围绕table表格行拖拽实现的相关资料展开详细的代码内容,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-03-03
  • 谈一谈bootstrap响应式布局

    谈一谈bootstrap响应式布局

    这篇文章主要和大家谈一谈bootstrap响应式布局,本教程讲解如何在网页布局中应用响应式设计,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • MVVM模式中ViewModel和View、Model有什么区别?

    MVVM模式中ViewModel和View、Model有什么区别?

    这篇文章主要介绍了MVVM模式中ViewModel和View、Model有什么区别?本文分别解释了它们的功能和作用,然后总结了它之间的区别,需要的朋友可以参考下
    2015-06-06
  • 认识less和webstrom的less配置方法

    认识less和webstrom的less配置方法

    下面小编就为大家带来一篇认识less和webstrom的less配置方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • javascript的23种设计模式示例总结大全

    javascript的23种设计模式示例总结大全

    这篇文章主要为大家介绍了javascript的23种设计模式的总结大全,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-06-06
  • 微信小程序简单的canvas裁剪图片功能详解

    微信小程序简单的canvas裁剪图片功能详解

    这篇文章主要介绍了微信小程序简单的canvas裁剪图片功能详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-07-07

最新评论