前言: 数值 / 字符串 / 布尔值 是基本类型, 对象 / 数组 / 函数是引用类型
ES5中有6种数据类型, 分别为: number / string / boolean / null / undefined / object. 这里的对象是广义的对象, 还可以细分为: array / function / object等.
typeof(1); // "number" typeof("1"); // "string" typeof(true); // "boolean" typeof({}); // "object" typeof(null); // "object" typeof(undefined); // "undefined" // 数组也是对象 typeof([1,2,3]); // "object" // 函数也是对象 var aFunc = function() {}; typeof(aFunc); // "function"; aFunc instanceOf Object; // true
其中, number / string / boolean 为基本类型, 也叫作: 原始类型; 而 object 则是引用类型, 这里的null 和 undefined有点特殊, 暂时不管它;
注意:
1. 尽管typeof(null)为"object", 但: null instanceOf Object 为 false.
2. typoof(undefined) 为 "undefined";
第一步: 基本类型的数据存储在栈内存中
什么是栈内存呢? 我们目前可以简单理解为是下面这样, 在取得栈内存中的数据时的过程是根据变量名, 找到对应的内存地址, 再把内存地址中的数据取出来.
也就是说, 栈内存中的数据不能还是内存地址, 只能是特定的值, 这个值其实就是我们说的基本类型. 比如下面这段代码, 我们声明一个叫做: name的变量, 此时内存中就将一个内存地址同这个name作绑定, 然后我们给它赋值一个字符串: "hanmeimei", 这时内存中就会创建一个字符串数据: "hanmeimei", 并且将这个数据所在的内存地址"绑定"到变量名name上. 这样就实现了赋值.
当我们修改这个这个值为 "lilei"时, 实际上是修改了name指向的内存地址, 此时name将不再指向"hanmeimei"所在的内存地址.
// 声明一个变量, 因为变量没有赋值, 因此指向 undefined; var name; // 赋值, 内存中新创建的 "hanmeimei" 数据的地址绑定到了 name上, name不再指向 undefined; name = "hanmeimei"; // name 指向内存中新创建的 "lilei" 数据所在的内存地址, 不再指向 "hanmeimei"所在的内存地址 name = "lilei";
上面这一过程经历了下面的过程:
注意:
1. JavaScript中一切皆对象, 基本类型也是如此, 只是他们的对象特征体现在他们各自的包装对象上.
2. 真实的作用过程远比上图描述的复杂, 这里仅作演示;
3. 如果一个数据没有被任何变量所指向, 那这个数据将会被垃圾回收机制所销毁, 内存将会释放;
第二步: 引用类型的数据存储在堆内存中
堆内存是内存中另一种数据组织方式, 不同于栈内存中的 变量 => 内存地址 => 数据这种引用方式, 堆内存中的存储的数据还是内存地址, 也就是说: 从堆内存中取数据要不断地去找数据中内存地址指向的数据, 如果仍旧是内存地址, 则继续往下找. 比如下面这个数组中的数据就是最简单的堆内存:
var family, son; son = "liqiang"; family = ["lilei", "hanmeimei", son];
对应的演示图如下:
注意:
1. 基本类型无法被修改, 只能被覆盖, 原因是基本类型指向的内存地址里面的数据无法被修改, 只能新建一个数据, 把变量名指向这个内存地址;
2. 原始类型可以被修改, 指的是它指向的内存地址里面的内存地址可以被修改, 比如上面的000009地址里面的数据, 完全可以再加其他的. 不过加的也只能是内存地址;
3. 类似String.prototype.replce()一类的类型原始的方法, 产生的数据都是在一个新的内存地址上, 因为它无法做到改变自身.