JavaScript基本类型和引用类型的值

2017-11-28  本文已影响0人  Julian1009

ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是简单的数据段,而引用类型值指那些可能由多个值构成的对象。

在将一个值赋给变量时,解析器必须确定这个值是基本类型值还是引用类型值。第3章讨论了5种基本数据类型:UndefinedNullBooleanNumberString。这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中;换句话说,obj1obj2都指向同一个对象。这样,当为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。在这个函数内部,objperson引用的是同一个对象。换句话说,即使这个变量是按值传递的,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,因为基本类型不是对象。

上一篇下一篇

猜你喜欢

热点阅读