转自javascript 高级程序设计(第三版):
javascript基本类型:
Undefined,Null,Boolean,Number,String
这五种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。
javascript引用类型:
引用类型的值是保存在内存中的对象。引用类型是按照引用访问的,因为是操作对象的引用而不是实际的对象。
1)动态的属性
操作的区别:对于引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法。
<html>
<head>
<script type="text/javascript">
function test(){
var person=new Object();
person.name="nick";
alert(person.name);
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
在上述例子中,我们给引用类型的对象person添加了属性name。如果对象不被销毁或者这个属性不被删除,那么这个属性将一直存在。
但是,我们不能给基本类型的值添加属性,尽管这样做也不会导致任何错误。
<html>
<head>
<script type="text/javascript">
function test(){
var person="boy";
person.name="nick";
alert(person.name);
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
在上述例子中,我们给基本类型的字符串person定义了一个属性,但是在alert调用person.name的时候,返回的结果为“undefined”。说明只能给引用类型值动态地添加属性。
2)复制变量值
在从一个变量向另一个变量复制基本类型值和引用类型值的时候,也存在不同。
如果对于基本类型的值,会在原有的变量对象上创建一个新值,然后把该值复制到为新变量分配到的位置上。
例如:var num1=5;
var num2=num1;
这两个变量可以参与任何操作而不会相互影响。
<html>
<head>
<script type="text/javascript">
function test(){
var num1=5;
var num2=num1;
num2=10;
alert(num1);
alert(num2);
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
如果是对于引用类型的值,同样也会将存储在变量对象中的值复制一份到为新变量分配的空间中。不同的是,这个值的副本实际上是一个指针,指针指向存储在堆中的一个对象。也就是说,先后两个引用类型的变量指向堆中的同一个对象。
<html>
<head>
<script type="text/javascript">
function test(){
var person=new Object;
person.name="red";
var person2=person;
person2.name="blue";
alert(person.name);//blue
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
当我们改变person2的name属性的值的时候,我们会发现person对象的name属性的值也随之改变。由此,进一步证明了person与person2指向的堆中的同一个对象。
3)参数传递
ECMAScript中所有参数的值都是按值传递的。
在向参数传递基本类型的值时,被传递的值会被赋值给一个局部变量。
在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量。因此这个局部变量的变化会反映在函数的外部。
也就是说,传递基本类型的值时,被传递的基本类型的变量,值不会发生变化;而传递引用类型的值时,被传递的引用类型的变量,值会发生变化。
我们来看一下下面的例子。首先是基本类型的变量:
<html>
<head>
<script type="text/javascript">
function test(){
var count=5;
function add(count){
count+=5;
return count;
}
var result=add(count);
alert("result:"+result);//10
alert("count:"+count);//5
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
<html>
<head>
<script type="text/javascript">
function test(){
var person=new Object();
person.name="red";
function change(person){
person.name="blue";
}
change(person);
alert(person.name);//blue
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
来看接下来一个例子。注意:我们说,在传递引用类型的参数的时候,传递的是该对象在内存中的地址。那么,如果在函数中,改变了该地址,又会出现什么情况呢?
<html>
<head>
<script type="text/javascript">
function test(){
var person=new Object();
person.name="red";
function change(person){
person.name="blue";
person=new Object();
person.name="green";
}
change(person);
alert(person.name);//blue
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
如果改变了该地址,那么操作的也就不是原有地址上的对象了。因此,对于外部的person对象而言,其name属性的值依然为"blue"。
实际上,在函数内部重写person对象时,这个变量引用的就是一个局部对象了,而且这个局部对象会在函数执行完毕后立即被销毁。
4)检测类型
<html>
<head>
<script type="text/javascript">
function test(){
var u;
var s="testString";
var n=123;
var b=false;
var k=null;
var o=new Object();
alert(typeof u);//undefined
alert(typeof s);//string
alert(typeof n);//number
alert(typeof b);//boolean
alert(typeof k);//object
alert(typeof o);//object
}
</script>
</head>
<body>
<button οnclick="test();">hhhh</button>
</body>
</html>
typeof可以用于检测基本数据类型,但是如果想检测具体是哪一种引用类型的话,还需要通过instanceof 操作符来识别。