1.变量类型
在JavaScript中包含了两种不同数据类型的值,即基本类型值和引用类型值。
基本类型值仅有5种类型:undefined、Null、Boolean、Number和String。而引用类型可以认为就是对象。
那么基本类型和引用类型有什么区别呢?看起来似乎没什么不同。它们的区别在于基本类型值是按值访问的,而引用类型值是按引用访问的。按值访问可以直接操作保存在内存中的实际的值,而按引用访问,除了为对象添加属性之外,操作的只是对象的引用。
还有一个很大的区别就是,引用类型的值可以添加属性与方法而基本类型值不可以。
var phone = new Object();
phone.brand = 'Apple';
console.log(phone.brand) //"Apple"
以上代码我们新建了一个对象并将其保存在phone变量里,然后我们为这个对象添加了一个brand属性,并将’Apple’赋给这个对象。
但是我们不能为基本类型值添加属性 尽管对基本类型值执行上述代码里的操作并不会产生任何错误。
var book = 'Software Engineer';
book.page = 100;
console.log(book.page); //undefined
上面代码将一个字符串赋给book对象,并为book添加一个page属性,然而输出时却是undefined。这就说明基本类型值不能添加属性。
除了以上两个区别之外,基本类型值与引用类型值在复制的时候也存在差别。
var a = 1;
var b = a;
console.log(a); //1
console.log(b); //1
console.log(++a); //2
console.log(b); //1
从上述代码中我们可以得到一个结论,基本类型值在复制的时候是直接将被复制变量的值的副本赋给了复制变量。换句话说,复制变量与被复制变量是完全独立的,对其中任一个进行操作都不会影响到另一个。
不过如果变量的值是一个引用类型值,情况就会完全不同了。
var a = new Object();
var b = a;
a.name = 'JavaScript';
console.log(a.name); //JavaScript
console.log(b.name); //JavaScript
console.log(a == b); //true
a变量保存了一个引用类型值(对象),然后将a赋值给b。为a变量添加了name属性之后,我们会发现a、b变量都出现了一样的属性(name)和一样的属性值(‘JavaScript’)。看到这里结论已经呼之欲出了,下一行代码更是直接就证实了我们的猜想----a与b的值是相同的。
尽管JavaScript里没有指针,我们依然可以使用指针的概念来理解这一现象。实际上就是a和b都持有同样的指针,该指针指向新建的那个对象。所以不论操作a还是b,实际操作的都是同一个对象。
2.参数传递
在JavaScript中所有函数的参数都是按值传递的。也就是说,与上面提到的基本类型值的复制一样。
function foo(num){
return num++;
}
var a = 1;
console.log(foo(a)); //2
console.log(a); //1
若传递的参数是一个基本类型值,那么就与基本类型值的复制一样,参数num被赋予的是a的副本,也就是说变量a与参数num是完全独立的,换句话说函数内对于num的任何改变都不会影响到a。
不过若是传递的参数是一个引用类型值,情况可就不太一样了。
function foo(obj){
obj.name = 'JavaScript';
}
var b = new Object();
foo(b);
console.log(b.name); //JavaScript
上面的运行结果似乎与传递的参数为基本类型值时不同,也与开始说的“所有函数的参数都是按值传递的”相矛盾,因为对函数的参数obj添加属性竟然使外部的b变量也发生了相同的改变。
其实按照之前我们使用指针对引用类型值的理解便可以解释这种情况。“按值传递”是没有错的,因为我们传递的不是b变量所保存的对象,而是b变量指向该对象的指针(b变量保存的是对象的指针)。也就是说,参数obj和变量b的值都是对象指针,那么自然对参数obj进行修改也会影响到b变量了。