86-js-2-原始类型和引用类型

概述

通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。至于undefinednull,一般将它们看成两个特殊值。

栈内存和堆内存

栈内存

  • 存储的值大小固定
  • 空间较小
  • 可以直接操作其保存的变量,运行效率高
  • 由系统自动分配存储空间

堆内存

  • 存储的值大小不定,可动态调整
  • 空间较大,运行效率低
  • 无法直接操作其内部存储,使用引用地址读取
  • 通过代码进行分配空间

值类型

解析

// 值类型
let a = 100
let b = a
a = 200
console.log(b) // 100

JavaScript中的原始类型的值被直接存储在栈中,在变量定义时,栈就为其分配好了内存空间。

内存中有一个变量a,值为100。我们从变量a复制出一个变量b,此时在内存中创建了一个块新的空间用于存储b,虽然两者值是相同的,但是两者指向的内存空间完全不同,这两个变量参与任何操作都互不影响。当改变a后,b指向的空间存储的值仍为100

比较

对于原始类型,比较时会直接比较它们的值,如果值相等,即返回true

var a = 'abc';
var b = 'abc';
console.log(a === b); // true

常见值类型

// 常见值类型
let a // undefined
const s = 'abc'
const n = 100
const b = true
const s = Symbol('s')

引用类型

解析

// 引用类型
let a = { age: 20 }
let b = a
b.age = 21
console.log(a.age) // 21

引用类型的值实际存储在堆内存中,它在栈中只存储了一个固定长度的地址,这个地址指向堆内存中的值。

当我们复制引用类型的变量时,实际上复制的是栈中存储的地址,所以复制出来的b实际上和a指向的堆中同一个对象。因此,我们改变其中任何一个变量的值,另一个变量都会受到影响,这就是为什么会有深拷贝和浅拷贝的原因。

比较

var obja = { age: 20 }
var objb = { age: 20 }
console.log(obja === objb); // false

对于引用类型,比较时会比较它们的引用地址,虽然两个变量在堆中存储的对象具有的属性值都是相等的,但是它们被存储在了不同的存储空间,因此比较值为false

常见引用类型

// 常见引用类型
const obj = { x: 100 }
const arr = ['a', 'b', 'c']
// 特殊引用类型,指针指向为空地址
const n = null
// 特殊引用类型,但不用于存储数据,所以没有"拷贝、复制函数"一说
function fn() {}

推荐阅读

栈和堆的区别

你真的掌握变量和类型了吗(一)