ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。
在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。第3章讨论了5种基本数据类型:
Undefined、Null、Boolean、Number和String。这5种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
引用类型的值是保存在内存中的对象。与其他语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的1。
动态的属性
定义基本类型值和引用类型值的方式是类似的:创建一个变量并为该变量赋值。
但是当这个值保存到变量中以后,对不同类型值可以执行的操作是不同的。
我们可以为引用类型值添加属性和方法,也可以改变和删除。
var person = new Object();
person.name = 'John';
console.log(person.name) // 'John'
如果对象不被销毁或者这个属性不被删除,则这个属性将一直存在。
但是,不能为基本类型值添加属性
var name="John";
name.age = 18;
console.log(name.age) // undefined
为字符串·name定义了一个名为age的属性,并为该属性赋值27。但在下一行访问这个属性时,发现该属性不见了。这说明只能给引用类型值动态地添加属性,以便将来使用。
复制变量值
从一个变量向另一个变量复制基本类型值和引用类型值时,也存在不同。
基本类型值:
var num1 = 5;
var num2 = num1;
image.png
引用类型值:
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"
首先,变量
obj1保存了一个对象的新实例。然后,这个值被复制到了obj2中;换句话说,obj1和obj2都指向同一个对象。这样,当为obj1添加name属性后,可以通过obj2来访问这个属性,因为这两个变量引用的都是同一个对象。
image
传递参数
基本类型值:
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); //20,没有变化
alert(result); //30
引用类型值:
function setName(obj) {
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
alert(person.name); // "John"
以上代码中创建一个对象,并将其保存在了变量
person中。然后,这个变量被传递到setName()函数中之后就被复制给了obj。在这个函数内部,obj和person引用的是同一个对象。换句话说,即使这个变量是按值传递的,obj也会按引用来访问同一个对象。于是,当在函数内部为obj添加name属性后,函数外部的person也将有所反映;因为person指向的对象在堆内存中只有一个,而且是全局对象。
注:有很多开发人员错误地认为:在局部作用域中修改的对象会在全局作用域中反映出来,就说明参数是按引用传递的。为了证明对象是按值传递的,我们再看一看下面这个经过修改的例子:
function setName(obj) {
obj.name = "John";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); // "John"
这个例子与前一个例子的唯一区别,就是在
setName()函数中添加了两行代码:一行代码为obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的name属性。在把person传递给setName()后,其name属性被设置为"John"。然后,又将一个新对象赋给变量obj,同时将其name属性设置为"Greg"。如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为"Greg"的新对象。但是,当接下来再访问person.name时,显示的值仍然是"John"。这说明即使在函数内部修改了参数的值,但原始的引用仍然保持未变。实际上,当在函数内部重写obj时,这个变量引用的就是一个局部对象了。而这个局部对象会在函数执行完毕后立即被销毁。
检测类型
typeof操作符:
var s = "Nicholas";
var b = true;
var i = 22;
var u;
var n = null;
var o = new Object();
alert(typeof s); //string
alert(typeof i); //number
alert(typeof b); //boolean
alert(typeof u); //undefined
alert(typeof n); //object
alert(typeof o); //object
instanceof操作符:
alert(person instanceof Object); // 变量person是Object吗?
alert(colors instanceof Array); // 变量colors是Array吗?
alert(pattern instanceof RegExp); // 变量pattern是RegExp吗?
根据规定,所有引用类型的值都是
Object的实例。因此,在检测一个引用类型值和Object构造函数时,instanceof操作符始终会返回true。当然,如果使用instanceof操作符检测基本类型的值,则该操作符始终会返回false,因为基本类型不是对象。






网友评论