JavaScript中的 变量和数据类型(⼀)

变量量和数据类型是学习 JavaScript 最先接触到的东⻄西,但是往往看起来最简单的东⻄西往往还隐藏着很多 你不了解、或者容易易犯错的知识,⽐比如下⾯面两个问题:
JavaScript 中变量在内存中的具体存储形式是什什么?
[] == [] 为什什么等于 false 、 [undefined] == false 为什么等于 true ?
如果你还不能很好的解答上⾯面的问题,那说明你还没有完全掌握这部分的知识,那么请好好阅读下面的⽂章吧。
本⽂从底层原理理到实际应⽤详细介绍了 JavaScript 中的变量和数据类型相关知识。

JavaScript 数据类型

ECMAScript 标准规定了了 7 种数据类型,其中这 7 种数据类型⼜又分为两种:原始类型和引⽤用类型。
原始类型
Null :只包含一个值: null
Undefined :只包含一个值: undefined
Boolean :包含两个值: true 和 false
Number :整数或浮点数,还有一些特殊值( -Infinity 、 +Infinity 、 NaN ) String :⼀串串表示⽂文本值的字符序列列
Symbol :⼀种实例例是唯⼀且不不可改变的数据类型
(在 ES10 中加⼊了第七种原始类型 BigInt ,现已被最新 Chrome 支持)
引⽤用类型
Object :⾃己分一类丝毫不过分,除了常⽤的 Object , Array 、 Function 等都属于特殊的 对象
原始类型 原始类型的不可变性
上⾯所提到的原始类型,在 ECMAScript 标准中,它们被定义为 primitive values ,即原始值,代表值本身是不可被改变的。
以字符串为例,我们在调⽤操作字符串的方法时,没有任何方法是可以直接改变字符串的:

let str = 'Lovo';
str.slice(1);
str.substr(1);
str.trim(1);
str.toLowerCase(1);
str[0] = 1;
console.log(str);  // Lovo

在上⾯面的代码中我们对 str 调⽤用了了⼏个⽅法,⽆一例外,这些方法都没有直接去改变 str ,⽽是在原 字符串的基础上产⽣了了⼀个新字符串串,这也就印证了了字符串的不可变性。
那么,当我们继续调⽤用下⾯面的代码:
你会发现,str 的值被改变了了,那这不就打脸了字符串串的不可变性么?其实并没有,我们从内存上来理 解。
原始类型与栈内存
在 JavaScript 中,每一个变量量在内存中都需要一个空间来存储,而内存空间又被分为两种,栈内存与堆 内存。
栈内存:
存储的值⼤小固定
空间较小
可以直接操作其保存的变量,运⾏效率高
由系统自动分配存储空间
JavaScript 中的原始类型的值被直接存储在栈中,在变量量定义时,栈就为其分配好了了内存空间。

   str += '6'
console.log(str);  // Lovo6
  由于栈中的内存空间的⼤小是固定的,那么注定了了存储在栈中的变量就是不可变的。

在上⾯面的代码中,我们执⾏了了 str += ‘6’ 的操作,实际上是在栈中⼜又开辟了了⼀块内存空间用于存储 ‘Lovo6’ ,然后将变量量 str 指向这块空间,所以这并不违背原始类型「不可变性」的特点。
引⽤用类型
引⽤用类型与堆内存 堆内存:
存储的值⼤小不定,可动态调整
空间较大,运⾏效率低
⽆法直接操作其内部存储,使⽤引⽤地址读取
通过代码进⾏分配空间
引⽤类型的值实际存储在堆内存中,它在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的
值。

 var obj1 = { name: "Lovo" }
var obj2 = { age: 18 }
var obj3 = function(){...}
var obj4 = [1, 2, 3, 4, 5, 6, 7, 8, 9]


当然,引⽤用类型就不再具有「不可变性」了,我们可以轻易的改变它们:
对比原始类型和引用类型
下⾯面我们通过几个操作来对比一下原始类型和引⽤用类型的区别。
复制
当我们把一个变量的值复制到另⼀一个变量上时,原始类型和引用类型的表现是不一样的。
先来看看原始类型:

obj1.name = "Lovo6";
obj2.age = 19;
obj4.length = 0;
console.log(obj1); // { name: "Lovo6" }
console.log(obj2); // { age: 19 }
console.log(obj4); // []
   var name = 'Lovo';
var name2 = name;
name2 = 'Hello';
console.log(name); // Lovo;

内存中有一个变量量 name ,值为 Lovo 。我们从变量 name 复制出一个变量name2 ,此时在内存中创 建了了一块新的空间用于存储 Lovo ,虽然两者值是相同的,但是两者指向的内存空间完全不不同,这两 个变量参与任何操作都互不不影响。
再来看看引⽤用类型:
当我们复制引⽤类型的变量量时,实际上复制的是栈中存储的地址,所以复制出来的 obj2 实际上和obj 指向的堆中同一个对象。因此,我们改变其中任何一个变量的值,另一个变量都会受到影响,这就是为什么会有深拷贝和浅拷贝的原因。
比较
当我们在对两个变量进行比较时,不同类型的变量的表现是不同的。

 var obj = { name:'Lovo' };
var obj2 = obj;
obj2.name = 'Hello';
console.log(obj.name); // Hello
   
   var name = 'Lovo';
var name2 = 'Lovo';
console.log(name === name2); // true
var obj = { name:'Lovo' };
var obj2 = { name:'Lovo' };
console.log(obj === obj2); // false

对于原始类型,比较时会直接⽐较它们的值,如果值相等,即返回 true。
对于引⽤类型,比较时会⽐较它们的引⽤地址,虽然两个变量在堆中存储的对象具有的属性值都是相等 的,但是它们被存储在了不同的存储空间,因此比较值为 false 。
学习更多IT技术请关注公众号“朗沃IT学习”

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值