ECMAScript变量有两种不同数据类型的值:基本类型值 和 引用类型值。基本类型值指的是简单的数据段,引用类型值指那些可能由多个值构成的对象。
5种基本类型: Undefined、Null、Boolean、Number、String。这五种基本数据类型是按值访问的,因为可以操作保存在变量中的实际值。
引用类型的值是保存在内存中的对象。JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是操作对象的引用而不是实际的对象。引用类型的值是按引用访问的。
1.动态的属性
定义基本类型值 和 引用类型值的方式是类似的:创建一个变量并为该变量赋值。当这个值保存到变量中以后,对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。
var person = new Object();
person.name = "Nicholas";
alert(person.name);
/*
*以上代码创建了一个对象并将其保存在了变量person中。
*然后我们为该对象添加了一个名为name的属性,并给属性赋值。
*如果对象不被销毁或设这个属性不被删除,则这个属性将一直存在。
*/
2.复制变量值: 除了保存的方式不同之外,在从一个变量向另一个变量复制值时,也存在不同
复制基本类型的值: 会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。
var num1 = 5; var num2 = num1; /* *num1中保存的值是5,当使用num1的值来初始化num2时,num2也保存了5 *但num2中的5和num1中的5是完全独立的,该值只是num1中5的一个副本。 *这两个变量可以参与任何操作而不会相互影响 */
复制引用类型的值: 同样也会将存储在变量对象中的值复制一份到位新变量分配的空间中,不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量:
var obj1 = new Object(); var obj2 = obj1; obj1.name = "Nicholas"; alert(obj2.name); //Nicholas /* *变量obj1保存了一个对象的新实例。然后,这个值被复制到了obj2中, *obj1和obj2指向同一个对象。这样,当为obj1添加name属性后,可以通过obj2来访问这个属性, *因为这两个变量引用的都是同一个对象 */
3.传递参数:ECMAScript中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递则如同引用类型变量的复制一样。
在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即命名参数,arguments对象中的一个元素)
在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数外部。
function addTen(num){ num += 10; return num; } var count = 20; var result = addTen(count); alert(result); //30 alert(count); //20 没有变化
/*
*函数addTen有一个参数num,而参数实际上是函数的局部变量,
*在调用这个函数时,变量count作为参数被传递给函数,
*变量的值是20,于是,数值20被复制给参数num以便在addTen()中使用。
*在函数内部,参数num的值被加上了10,但这并不会影响函数外部count变量。
*/
function setName(obj){ obj.name = "Nicholas"; } var person = new Object(); setName(person); alert(person.name); //Nicholas
/*
*以上代码创建一个对象,并将其保存在了变量person中,
*这个对象被传递到setName()函数中之后就被复制给了obj
*在函数内部,obj和person引用的是同一个对象。
*即使这个对象是按值传递的,obj也会按引用来访问同一个对象。
*于是在函数内部为obj添加name属性后,函数外部的person也会有所反映。
*/
function setName(obj){ obj.name = "Nicholas"; obj = new Object(); obj.name = "Greg"; } var person = new Object(); setName(person); alert(person.name); //Nicholas
/*
*setName()函数添加了两行代码: 一行为obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的name属性
*如果person是按引用传递,那么person就会自动被修改而指向新对象,
*但是 person.name值仍然是Nicholas,
*这就说明即使在函数内部修改了参数的值,但原始的引用仍保持未变。
*实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即销毁
*/
4.检测类型
typeof操作符:检测一个变量是字符串、数值、布尔值、还是Undefined
如果变量的值是一个对象或null,则typeof操作符返回object
var s = "Nicholas"; var b = true; var i = 22; var u; var n = null; var o = new Object(); alert(typeof s); //string alert(typeof b); //boolean alert(typeof i); //number alert(typeof u); //undefined alert(typeof n); //object alert(typeof o); //object
typeof在检测引用类型的值时,这个操作符的用处不大。通常,我们并不想知道这个值是对象,而是想知道他是什么类型的对象,为此,ECMAScript提供了instanceof操作符: 如果变量是给定引用类型(根据他的原型链来识别)的实例,则返回true。
var person = new Array(); alert(person instanceof Object); //true alert(person instanceof Array); //true alert(person instanceof RegExp); //false