JavaScript学习:基本类型和引用类型

王叨叨 | 2014-07-07 | 分类 笔记  | 标签 js  reading_notes 

ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值。基本类型值指的是那些保存在栈内存中的简单数据段,即这种值完全保存在内存中的一个位置。而引用类型值则是指那些保存在堆内存中的对象。

在将一个值赋给变量时,解析器必须确定这个值是基本类型值,还是引用类型值。Undefined、Null、Boolean、Number 和 String这5种基本数据类型的值在内存中占有固定大小的空间,因此可以把它们的值保存在栈内存中。而且,这样也可以提高查询变量的速度。对于保存基本类型值的变量,我们说它们是按值访问的,因为我们操作的是它们实际保存的值。

如果赋给变量的是一个引用类型的值,则必须在堆内存中为这个值分配空间。由于这种值的大小不固定,因此不能把它们保存到栈内存中。但内存地址的大小是固定的,因此可将内存地址保存在栈内存中。这样,当查询引用类型的变量时,就可以首先从栈中读取内存地址,然后再“顺藤摸瓜”地找到保存在堆中的值。对于这种查询变量的方式,我们把它叫做按引用访问,因此我们操作的不是实际的值,而是被那个值引用的对象。

动态的属性

定义基本类型和引用类型的方式是类似的:创建一个变量并为该变量复制。但是,当这个值保存到变量中以后,对不同类型值可以执行的操作则大相径庭。对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。

var person = new Object();
person.name = "Nicholas";
alert(person.name); //"Nicholas"

基本类型是没有动态属性的。

复制变量值

除了保存的方式不同之外,在从一个变量向另一个变量复制基本类型值和引用类型值时,也存在不同。如果从一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上。

var num1 = 5;
var num2 = num1;

如图:

num1=5

num2=num1

当从一个变量向另一个变量复制引用类型的值时,同样也会将存储在变量对象中的值复制一份放到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。复制操作结束后,两个变量实际上将引用同一个对象。因此,改变其中一个变量,就会影响另一个变量。

var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"

如图:

obj2=obj1

传递参数(!!)

ECMAScript中所有函数的参数都是按值传递的。也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值的传递如同基本类型变量的复制一样,而引用类型值的传递,则如同引用类型变量的复制一样。

function addTen(num) {
    num += 10;
    return num;
}
var count = 20
var result = addTen(count);
alert(count);    //20
alert(result);   //10

如果换成对象,有点难以理解了:

function setName(obj) {
    obj.name = "Nicholas";
    obj = new Object();
    obj.name = "Greg";
    alert(obj.name);
}
//alert(obj.name);
var person = new Object();
setName(person);
alert(person.name);

这里我是这样理解的,一开始obj和person都指向第一次new的对象(var person = new Object();),然后函数体内obj指向了新的object,但是person还是指向第一次的object对象,而且这个对象被它的另一个引用obj形参修改name属性为Nicholas。

检测类型

要检测一个变量是不是基本数据类型,typeof操作符是最佳的工具。typeof操作符是确定一个变量是字符串、数值、布尔值,还是undefined的最佳工具。如果变量的值是一个对象或null,则typeof操作符会像下面例子中所示的那样返回“object”:

var s = "Nicholas";
var b = true;
var i = 2;
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

虽然在检测基本数据类型时typeof是非常得力的助手,但在检测引用类型的值时,这个操作符的用处不大。通常,我们并不想知道某个值是对象,而是想知道它是什么类型的对象。为此,ECMAScript提供了instanceof操作符,其语法如下:

result = variable instanceof constructor

如果变量是给定引用类型的示例,那么instanceof操作符就会返回true。

alert(person instanceof Object);   //变量person是Object吗?
alert(colors instanceof Array);    //变量colors是Array吗?
alert(pattern instanceof RegExp);  //变量pattern是RegExp吗?

根据规定,所有引用类型的值都是Object的实例。因此在检测一个引用类型值和Object构造函数时,instanceof操作符始终会返回true。当然,如果使用instanceof操作符检测基本类型的值,则该操作符始终会返回false,因为基本类型不是对象。

如果觉得此篇文章对您有帮助,希望可以请我喝雪碧!请我喝雪碧

上一篇   下一篇   返回顶部