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对象类型赋值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • zepto.js 实时监听输入框的方法

    zepto.js 实时监听输入框的方法

    今天小编就为大家分享一篇zepto.js 实时监听输入框的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • uniapp中全局页面挂载组件实战过程(小程序)

    uniapp中全局页面挂载组件实战过程(小程序)

    这篇文章主要给大家介绍了关于uniapp中全局页面挂载组件(小程序)的相关资料,文中通过实例代码介绍的非常详细,对大家学习或者使用uniapp具有一定的参考学习价值,需要的朋友可以参考下
    2022-12-12
  • 详解js访问对象的属性和方法

    详解js访问对象的属性和方法

    在本篇文章里我们给大家分享了关于js访问对象的属性和方法的相关知识点,有需要的朋友们可以学习下。
    2018-10-10
  • 微信小程序上传图片到服务器实例代码

    微信小程序上传图片到服务器实例代码

    这篇文章主要介绍了微信小程序上传图片到服务器的实例代码,在文章给大家补充介绍了微信小程序上传一或多张图片 的方法,本文给大家介绍的非常详细,具有参考借鉴加载,需要的朋友可以参考下
    2017-11-11
  • JavaScript设计模式经典之命令模式

    JavaScript设计模式经典之命令模式

    命令模式(Command)的定义是:用来对方法调用进行参数化处理和传送,经过这样处理过的方法调用可以在任何需要的时候执行。接下来通过本文给大家介绍JavaScript设计模式经典之命令模式,需要的朋友参考下
    2016-02-02
  • 判断横屏竖屏(三种)

    判断横屏竖屏(三种)

    本文主要介绍了通过HTML,CSS,JS三种判断横屏竖屏的方法。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 详解webpack之图片引入-增强的file-loader:url-loader

    详解webpack之图片引入-增强的file-loader:url-loader

    这篇文章主要介绍了详解webpack之图片引入-增强的file-loader:url-loader,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-10-10
  • 关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法

    关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法

    下面小编就为大家带来一篇关于JSON.parse(),JSON.stringify(),jQuery.parseJSON()的用法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-06-06
  • javascript按顺序加载运行js方法

    javascript按顺序加载运行js方法

    本篇文章主要教给大家如何在javascript中动态加载按顺序加载运行js的方法以及实现代码,需要的朋友参考学习下吧。
    2017-12-12
  • firefox下javascript实现高亮关键词的方法

    firefox下javascript实现高亮关键词的方法

    “点睛”的广告代码,很牛B,本想从中找出在FireFox下如何实现findText及pasteHTML类似效果的,我看了大半天,楞是没有看出个所以然来!还是自己慢慢研究吧。
    2007-07-07

最新评论