JavaScript高级程序设计 第四章 — 变量、作用域和内存问题
基本类型和引用类型
ECMAScript变量可能包含两种类型的值:基本类型值和引用类型值。
- 基本类型值:简单的数据段
- 引用类型值:哪些可能由多个值构成的 对象
复制变量值
基本类型值的复制
引用类型值的复制
两个变量实际引用同一个对象,改变一个变量,就会影响另一个变量,比如:
var obj1 = new Object();
var obj2 = obj1;
obj1.name = "Nicholas";
alert(obj2.name); //"Nicholas"
传递参数
ECMAScript中所有函数的参数都是按值传递的。
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); //"Nicholas"
可以把ECMAScript函数的参数想象成局部变量
执行环境及作用域
执行环境(有时也称“环境”)定义了变量或函数有权访问的其它数据,决定了各自行为。
全局执行环境被认为是 window对象,所有全局变量和函数都是作为 window对象的属性和方法创建的。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。如果这个环境是函数,则其活动对象为变量对象。
延长作用域链
执行环境有两种:全局和局部。
当执行流进入下列任何语句,作用域链加长:
- try-catch 语句的 catch块
- with 语句
function buildUrl(){
var qs = "?debug=true";
with(location){
var url = href + qs ;
} //with语句接收的是location对象,因此其变量对象包含了location对象的所有属性和方法。
return true ;
}
声明变量
初始化变量没有var声明,该变量会被自动添加成全局变量。
function add(num1,num2){
var sum = num1 +num2 ;
return sum;
}
var result = add(10,20); //30
alert(sum); //由于sum不是有效变量,因此会错误
function add(num1,num2){
sum = num1 +num2 ;
return sum;
}
var result = add(10,20); //30
alert(sum); //30
查询标识符
当某个环境,读取或写入标识符时,通过搜索来确定标识符。
搜索过程从作用域前端开始,向上逐级查询,如果局部环境找到,搜索停止。如果局部没有,继续沿作用域链向上搜素。如果全局环境也没有,则意味着变量未声明。
var color = "blue" ;
function getColor(){
return color;
}
alert(getColor()); //"blue"
var color = "blue" ;
function getColor(){
var color = "red";
return color;
}
alert(getColor()); //"red"
小结
变量可以保存两种类型的值:基本类型和引用类型。
5种基本类型:Undefined、Null、Boolean、Number和String。
基本类型和引用类型的特点
- 基本类型值在内存中占据固定大小空间,被保存在栈内存中
- 一个变量向另个变量复制基本类型值,会创建这个值的一个副本
- 引用类型是对象,保存在堆内存中
- 包含引用类型值的变量实际包含的并不是对象本身,而是指向该对象的指针
- 复制引用类型值,复制的其实是指针,两个变量最终指向同一个对象
执行环境总结
- 执行环境有全局执行环境和函数执行环境
- 每次进入新执行环境,会创建一个用于搜索变量和函数的作用域链
- 函数局部环境不仅可以访问函数作用域中的变量,也可以访问其父环境,乃至全局环境
- 全局环境只能访问全局环境定义的变量和函数,不能直接访问局部环境中的任何数据