写在前面
ECMAScirpt 变量有两种不同的数据类型:基本类型
,引用类型
。或者也可以叫原始类型
,对象类型
。初次之外还有很多其他的叫法,不过都是根据这两种类型的特点进行命名的。
基本类型
ES5拥有5种基本数据类型,非别是:undefined
,boolean
,number
,string
,null
,ES6中多了一种基本数据尅性,叫symbol
,Symbol的目的就是为了实现一个唯一不重复不可变的值,任何一个Symbol都是唯一的,不会和其他任何Symbol相等。
基本类型的访问是按值访问的,就是说你可以操作保存在变量中的实际的值。基本类型有以下几个特点:
1.值不可变
任何的方法都不可以改变一个基本类型的值,看例子:
<script>
var name = "LAN";
name.toLowerCase();
console.log(name);
</script>
Output:LAN
对name调用了toLowerCase()方法,再输出name变量,依然是大写LAN。因为toLowerCase()会返回一个新的字符串回来。
2.不能添加属性和方法
<script>
var name = "LAN";
name.do = function(){
console.log("name.do");
}
name.do();
</script>
Output:name.do is not a function
控制台爆出错误,说name.do不是一个function,说明不能给基本类型添加属性或者方法。
3.基本类型比较为值比较
值比较是什么意思呢?意思就是只要两个变量的值相等,那么就认为就俩个变量就是相等的。举个例子:
<script>
var a = 1;
var b = 1;
console.log(a === b);
</script>
Output:true
这里的a、b两个变量的值都为1,通过输出可知a变量等于b变量。
4.基本类型的变量是存放在栈区的
如果我们定义了以下几个变量:
<script>
var name = "LAN";
var age = 22;
var sex = "男";
</script>
那么这些变量在栈区里面的存在形式是这样的:
栈区里面包括了变量的标识符和变量的值,也就是上图的key和value。
引用类型
引用类型其实也就是对象。对象里面可以有属性和方法,也就是引用类型可以拥有属性和方法。下面是一些引用类型的特点:
1.值可变
我们可以为对象添加或者删除属性和方法,看代码:
<script>
var person = {};
person.name = "LAN";
person.age = 22;
person.sayName = function() {
console.log(this.name);
};
person.sayName();
delete person.name;
person.sayName();
</script>
Output:
LAN
undefined
上面代码说明引用类型可以拥有属性和方法,并且是可以动态改变的。
2.引用类型的值同时保存在栈内存和堆内存中
对于javascript,我们不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。实际上,我们是操作对象的引用
,所以引用类型的值是按引用访问的。
简单来说,要存储引用类型的变量,需要栈空间、堆空间同时使用,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。假如我们定义了如下几个对象:
<script>
var student1 = {name: "张三"};
var student2 = {name: "李四"};
var student3 = {name: "王五"};
</script>
那么这几个对象在内存中的存储形式如下:
引用类型比较是引用比较
这个特点意思是说,两个对象比较,比较的是栈区里面存储的引用地址,也就是映射到堆区的那个地址。举个例子:
<script>
var student1 = {name: "张三"};
var student2 = {name: "张三"};
console.log(student1 === student2);
</script>
Output:false
虽然说student1和student2的值是一样的,但是存储到堆区里面的地址是不相同的,所以相比较为false。
简单赋值
基本类型变量进行相互赋值,两个变量依然是相互独立的,举个例子:
<script>
var a = 1;
var b = a;
a++;
console.log(a);
console.log(b);
</script>
Output:
2
1
赋值之后,两个变量依然是独立的,可以进行独立操作不受互相影响。
对象引用
引用类型变量进行相互赋值,是将栈区存放的地址进行相互赋值,结果就是两个对象指向同一块堆地址,也就是说两个赋值之后的两个对象其实是一个对象,是完全相等的。
<script>
var a = {};
var b = a;
a.name = "lan";
console.log(a.name);
console.log(b.name);
console.log(a === b);
</script>
Outout:
lan
lan
true
就如同之前所说,引用类型比较比较的是地址,现在两个对象指向同一个地址,所以是相等的,固然输出true。下面是内存示意图:
因此,引用类型的赋值其实是对象保存在栈区地址指针的赋值,因此两个变量指向同一个对象,任何的操作都会相互影响。