本文参考了focusxxxxy 的博客,感谢他的知识分享。
一 基本类型和引用类型的值
ECMAScript 变量包含两种不同数据类型的值:基本类型和引用类型。
也有其他的叫法,比如原始类型和对象类型,拥有方法的类型和不能拥有方法的类型,还可以分为可变类型和不可变类型,其实这些叫法都是依据这两种的类型特点来命名的,大家爱叫啥就叫啥吧 。 ------------focusxxxxy 的博客
基本类型:简单的数据段,undefined、boolean、number 和 string ,他们都是按值访问的,因为可以操作保存在变量中的实际值。
基本类型的特点:
1. 基本类型的比较是值的比较
但是在比较的时候注意运算符 == 和 === 的区别。== 默认会把两边不同的数据类型转换城相同的数据类型,再进行值的比较。而 === 会先比较数据类型,若数据类型不一样,就会返回 false。举一些例子:
var a = 1; var b = '1'; console.log(a == b); // true 想转成相同的格式,再比较 console.log(a === b); // false 不转格式直接比较 var c = true console.log(a == c); // true console.log(a ===c); // false
2. 基本类型的变量存放在栈内存(栈区)里面
var name = 'Jhon'; var city = 'Beijing'; var age = 27;
那么他的存储结构如下图:栈内存包含了变量名和变量值。
引用类型:除了上面的基本类型(number,string,boolean,null,undefined)之外就是引用类型了,也可以说是就是对象(对象,数组,函数和 null)了。对象是属性和方法的集合。也就是说引用类型可以拥有属性和方法,属性又可以包含基本类型和引用类型。来看看引用类型的一些特性:
1. 引用类型的属性和方法是可以变化的,也就是可以增删改查。这个很好理解,无需多说。但是要注意有很多方法,注意总结归纳
2. 引用类型的内容是同是保存在栈内存和堆内存中的对象。(什么是栈内存和堆内存呢?后续需要查询资料)
javascript和其他语言不同,其不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间,我们是操作对象的引用,所以引用类型的值是按引用访问的。准确地说,引用类型的存储需要内存的栈内存和堆内存共同完成,栈区内存保存变量标识符和指向堆内存中该对象的指针,也可以说是该对象在堆内存的地址。假如有以下几个对象:
person1 = {name : 'Jhon'}; person2 = {name : 'Marry'}; person2 = {name : 'Lily'};
那么,他们的存储结构如下图:
3. 引用类型的比较:
var person1 = "{}" var person2 = "{}" console.log(person1 == person2) // true 这里比较的是字符串
var person1 = {} var person2 = {} console.log(person1 == person2) // false 这里比较的是 person1 和 person2 里面的内存地址。内存地址不一样,返回值就是 false
引用类型时按引用访问的,换句话说就是比较两个对象的堆内存中的地址是否相同,那很明显,person1 和 person2 在堆内存中地址是不同的:
二 基本类型和引用类型在复制变量值的区别
基本类型复制:从一个变量到了另一个变量复制基本类型的值,会在这个变量对象创建一个新的值,载把这个值复制到为新变量分配的位置上。如下面的例子:
var num1 = 5; var num2 = num1; num2 = num2 + 1; console.log(num1); // 5 console.log(num2); // 6 将 num1 的值赋值给 num2 以后,两个变量之间相互不影响。改变一个变量的值不会改变另外一个。但是引用变量的复制就不同了,会相互改变。
引用类型复制:从一个变量到了另一个变量复制引用类型的值,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个复制的值实际上是一个指针,而这个指针指向的是堆内存中的一个对象。复制结束后,两个变量引用的是同一个对象。这样的后果是,如果对变量1进行修改,那么变量2的内容也会跟着改变。如下面的例子:
var person1 = new Object(); // 为 person1 创建一个新的空对象 var person2 = person1; // 将 person1 的堆内存地址复制一份,给 person2 person1.name = 'Jhon'; // 为 person1 指向的对象添加 name 属性 console.log(person2.name); // person2 的 name 属性返回 Jhon (person2 和 person1 指向同一个对象。通过 person1 对对象进行改变,调用 person2 时也会看到改变)
ECMAScript 中所有函数的参数都是按值传递的。
三 检测基本类型和引用类型的方法
基本类型检测方法:用 typeof 操作符。他可以确定一个变量是 字符串、数字、布尔值还是 undefined。但是却区分不出来一个变量是 null 还是 object。例如:
注意,function 是引用类型,但是 typeof 却能区分出是不是 function。
var a = 'Jhon'; var b = true; var c ; var d = null; var e = new Object(); console.log(typeof a); // string console.log(typeof b); // boolean console.log(typeof c); // undefined console.log(typeof d); // object console.log(typeof e); // object
引用类型检测方法:用 instanceof 操作符。例如:
var o = new Object(); console.log(o instanceof Object); // true