ECMAScirpt 变量有两种不同的数据类型:基本类型、引用类型。也有其他的叫法,比如原始类型和对象类型。
一、基本类型
- 基本的数据类型有:
undefined
、boolean
、number
、string
、null
和Symbol
.- 基本类型是存放在栈(stack)内存中的简单数据段,它是直接按值存放的,就是说你可以操作保存在变量中的实际的值。
1. 基本类型的值是不可变得
任何方法都无法改变一个基本类型的值,比如一个字符串:
var name = 'jack';
name.toUpperCase(); // 'JACK'
console.log(name); // 'jack'
2. 基本类型的比较是值的比较
只有在它们的值相等的时候它们才相等。
var a = 1;
var b = true;
console.log(a == b); // true
console.log(a === b); // false
注意:比较的时候,最好使用全等于(===
),因为 ==
会进行类型转换。
3. 基本类型的变量是存放在栈内存的
var name = 'jack';
var age = 22;
它在栈内存中的存储结构如下图:
栈内存包括了 变量的标识符和变量的值。
二、引用类型
对象Object(数组、函数)。
- 对象是属性和方法的集合,引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。
- 引用类型的值保存在内存中的对象,JavaScript不能直接操作对象的内存空间,操作对象时,实际上是操作对象的引用而不是实际的对象。引用类型的值是按引用访问的。
1. 引用类型的值是可变的
var person = {};
person.name = 'jack';
person.age = 22;
person.sayName = function(){console.log(person.name);}
person.sayName(); // 'jack'
delete person.name; // 删除person对象的name属性
person.sayName(); // undefined
2. 引用类型的值是同时保存在栈内存和堆内存中的对象
- javascript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,那我们操作啥呢? 实际上,是操作对象的引用,所以引用类型的值是按引用访问的。
- 准确地说,引用类型的存储需要内存的栈区和堆区共同完成
- 栈内存:保存变量标识符和指向堆内存中该对象的指针(堆内存地址)。
- 堆内存:对象。
var person1 = {name:'jozo'};
var person2 = {name:'xiaom'};
var person3 = {name:'xiaoq'};
3. 引用类型的比较是引用的比较
var person1 = {};
var person2 = {};
console.log(person1 == person2); // false
引用类型时按引用访问的,换句话说就是比较两个对象的堆内存中的地址是否相同,那很明显,person1和person2在堆内存中地址是不同的:
三、基本类型赋值
在从一个变量向另一个变量 赋值基本类型 时,会在该变量上创建一个新值,然后再把该值复制到为新变量分配的位置上:
var a = 10;
var b = a;
a ++ ;
console.log(a); // 11
console.log(b); // 10
此时,a
中保存的值为 10
,当使用 a
来初始化 b
时,b
中保存的值也为 10
,但 b
中的 10
与 a
中的是完全独立的,该值只是a
中的值的一个副本。此后,这两个变量可以参加任何操作而相互不受影响。
也就是说基本类型在赋值操作后,两个变量是相互不受影响的。
四、对象引用赋值
当从一个变量向另一个变量 赋值引用类型 的值时,同样也会将存储在变量中的对象的值复制一份放到为新变量分配的空间中。
前面讲引用类型的时候提到,保存在变量中的是对象在堆内存中的地址,所以,与简单赋值不同,这个值的副本实际上是一个指针,而这个指针指向存储在堆内存的一个对象。
那么,赋值操作后,两个变量都保存了同一个对象地址,则这两个变量指向了同一个对象。因此,改变其中任何一个变量,都会相互影响:
var a = {}; // a保存了一个空对象的实例
var b = a; // a和b都指向了这个空对象
a.name = 'jack';
console.log(a.name); // 'jack'
console.log(b.name); // 'jack'
b.age = 22;
console.log(b.age); // 22
console.log(a.age); // 22
console.log(a == b);// true
总结
-
原始类型的值存在栈内存中,对象类型的引用存在栈内存中,对象类型的值存在堆内存
原始类型的赋值传值,对象类型的赋值传引用