- ECMAscript 变量包含 基本类型值和引用类型值
- 基本类型值值的是基本数据类型:Undefined, Null, Boolean, Number, String
- 引用类型值是保存在内存空间中的对象,与其他 JavaScript 不允许直接访问内存中的位置,即不能直接操作对象的内存空间,在操作对象时,实际上是在操作对象的引用而不是实际的对象;为此,引用类型的值是按引用访问的
- 在很多语言中,字符串以对象 的形式来表示,因此被认为是引用类型的,ECMAScript 放弃了这一传统
- 引用类型的值可以为其添加属性和方法,也可以改变和删除属性和方法
- 基本类型值不行
var person = new Object();
person.name = "Nicholas";
alert(person.name); // "Nicholas"
var person = "Nicholas";
person.age = 27;
alert(person.age); // undefined
- 在从一个变量复制向另一个变量复制值时,基本类型值和引用类型值存在不同
- 基本类型值会在变量对象上创建一个新值,然后把该值复制到为新变量分配的位置上,两个变量可以参与任何操作而不会互相影响
- 引用类型也会复制一个副本放到新变量中,但这个副本实际上是一个指针,这个指针指向存储在堆中的一个对象,复制操作结束后,两个变量实际上将引用同一个对象,因此改变其中一个变量,就会影响另一个变量
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); // "Nicholas"
- ECMAscript 中所有函数的参数都是按值传递的,即把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样
- 在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(即为命名参数,或者用 ECMAScript 的概念来说,就是函数的 arguments 对象中的一个元素)
- 在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数外部
- 可以把 ECMAScript 的参数想象成局部变量
// 参数 num 是函数的局部变量
// 调用这个函数时,变量 count 作为参数被传递给函数,是将 count 的值 20 复制给参数 num
// 在函数内部,参数 num 的值加上了 10,但不会影响函数外部的 count 变量,count 和 num 互不影响
function addTen(num) {
num += 10;
return num;
}
var count = 20;
var result = addTen(count);
alert(count); // 20, 没有变化
alert(result); // 30
// 以下为个人理解,原著表述不清楚不能直观理解
// 传递给参数 obj 的实际上是指向 person 对象内存地址(指针),是将地址复制了一个副本赋值给了参数 obj
// 当在函数内部为 obj 添加 name 属性后,函数内部根据地址操作了内存中的相应对象,函数外部的 person 也将有反映
// 因为 person 指向的对象在堆内存中只有一个,而且是全局对象
function setName(obj) {obj.name = "Nicholas";}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"
// 下列代码,直觉认为会 alert 出 "Greg",但却是 "Nicholas"
// 因为传递给参数 obj 的只是指针的副本,当函数内重新给 obj 赋值的时候,实际上是将一个新的 Object 对象的指针赋给 obj
// 此时操作 obj 影响的是新的 Object 对象,而 person 对象不受影响
// obj 指向的新 Object 对象在函数执行完后会立即销毁
function setName(obj) {
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
var person = new Object();
setName(person);
alert(person.name); // "Nicholas"