变量的值

534 阅读4分钟

ECMAScript 的变量是松散类型的,也就是说可以保存任何类型的数据。数据的类型分为简单数据类型和复杂数据类型。简单数据类型有: Undefined、Null、Boolean、Number和 String;复杂数据类型只有一种,就是Object。在将一个值赋值给变量时,解析器会确定值的类型。如果是简单类型,直接保存在变量中,如果是复杂类型,则把值保存在内存中,而把值的引用保存在变量中。也就是说变量的值有两种:简单的数据类型的值或者复杂数据类型的引用。因此,在操作变量时,就会有所不同。

1、添加属性

变量的值是复杂数据类型时,可以简单的为其添加属性。这个很容易理解,而当变量的值是某些简单的数据类型时,为其添加属性也不会报错,但之后却不能访问,如下:

 
var person= "xiaoming";
name.age = 27;
alert(name.age); //undefined

这是因为JavaScript引擎在处理添加属性的代码时,会在内部临时创建一个对应包装类型(这里是String类型)的临时对象, 并把对基本类型的操作代理到对这个临时对象身上,但在操作完成之后,临时对象就扔掉了,下次访问时,重新建立新的临时对象,添加的属性并不会 保存。有时,在代码中直接调用基本数据类型的方法的方法也是同样的道理。因此,只能给复杂数据类型的值添加属性。

2、赋值变量的值

从一个变量向另一个变量复制值时,会为新的变量分配位置,然后把变量的值复制到该位置上。不管变量的中保存的是基本数据类型的值,还是复杂数据类型的引用,都是直接把变量中保存的值直接赋值并保存到新的位置上面。

简单的数据类型很好理解,复杂的数据类型可以参照下图:

变量obj2复制的是obj1中保存的对象的引用,复制之后,obj1和obj2中分别保存一个指向该对象的引用。

3、传递参数

ECMAScript 中所有函数的参数都是按值传递的。也就是说在传递参数时,实际上就是把变量中保存的值复制了一遍,保存在对应的参数中,从而变成了函数内部的一个变量。这时,需要注意的一点时,对于简单的数据类型,新的变量(参数)和外部的变量已经没有联系了。而对于复杂数据类型,因为两个变量中保存的都是对象的引用,因此两个变量还是仅仅联系在一起的,如下:

var a = 3;
var o = { name:'xiaoming' };
function fn(obj, num){
     num += 10;
     o.name = 'hh';
     return num;
}
var res = fn();

alert(res);     //13
alert(a);     //3
alert(o.name); //'hh'

4、检测类型

正如开头说的变量是松散的,为了确保代码可以正确的执行,很多时候都需要检测变量值的类型。变量的值是简单的数据类型时(null除外),只需要使用typeof操作符,就可以很简单的检测出来。但变量的值是复杂数据类型的引用时,就有点麻烦了,使用typeof始终只会返回‘object’。如果知识简单的检测,可以使用 instanceof 操作符。使用如下:

res = obj instanceof constructor

只要变量是给定复杂数据类型的实例,那么instanceof 操作符就会返回 true。需要说的一点是, 所有复杂数据类型的值都是 Object 的实例,使用这个操作符检测是不是Object构造函数的实例时,都会返回true。

使用这种方式检测在大多数情况下都是没有问题的,但当页面的中存在嵌套的框架或者在一些特殊的浏览器中就会出现问题。例如,在一个frame中定义了一个数组arr,而在最外层的window环境中检测,就会返回false。为了确保检测结果的正确,可以使用Object原声的toString方法,对于任何的复杂数据类型,这个方法都会返回“ [object NativeConstructorName]”格式的字符串,例如:

Object.prototype.toString.call([])          //"[object Array]"