JavaScript高级程序设计笔记(2)

变量、作用域及内存问题

基本类型与引用类型的值

基本类型值是简单的数据段,基本类型是按值访问的,可以操作保存在变量中的实际的值。

引用变量值可能有多个值构成的对象,引用类型的值是保存在内存中的对象,Javascript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的的引用而不是实际对象。为此,引用类型的值是按引用访问的。

传递参数

ECMAScript中所有函数的参数都是按值传递的。即把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。基本类型值得传递如同基本类型变量的复制一样,而引用类型值得传递,则如同引用类型变量的复制一样。注意:访问变量有按值和按引用两种方式,而参数只能按值传递。

基本类型:

1
2
3
4
5
6
7
8
function addTen(num){
num += 10;
return num;
}
var count = 10;
var result = addTen(count);
console.log(count); //10,没有变化,按值传递
console.log(result);//20

引用类型:

1
2
3
4
5
6
function setName(obj){
obj.name = 'js';
}
var person = new Object();
setName(person);
console.log(person.name);//js

另一个例子:

1
2
3
4
5
6
7
8
function setName(obj){
obj.name = 'js';
obj = new Object();
obj.name = 'node';
}
var person = new Object();
setName(person);
console.log(person.name);//js

引用类型的第二个例子和第一个例子的不同之处:在setName()函数中添加了两行代码:一行代码为obj重新定义了一个对象,另一行代码为该对象定义了一个带有不同值的name属性。在把person传递给setName()后,其name属性被设置成了js,然后又将一个新的对象赋给变量obj,同时将name属性设置成node。如果person是按引用传递的,那么person就会自动被修改为指向其name属性值为node的对象。但是,当我们访问person.name时,其值仍然是js。这说明,即使在函数内部修改了参数的值,但原始引用仍然保持不变。实际上,挡在函数内部重写obj时,这个变量的引用就是一个局部对象。而局部对象,在函数执行完毕后立即被销毁。

检测类型

typeof

要检测一个变量是否是基本数据类型,typeof操作符是一个最佳的工具:确定一个变量是字符串、数值、布尔值还是undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
var a = '122222';
var b = true;
var c = 1;
var d;
var e = null;
var f = new Object();

console.log(typeof a);//string
console.log(typeof b);//boolean
console.log(typeof c);//number
console.log(typeof d);//undefined
console.log(typeof e);//object
console.log(typeof f);//object

instanceof

如果变量值是一个对象或者null值,则typeof操作符会返回上述例子最后的object。在检测引用类型的值时,typeof操作符的用处不大。当我们想知道某个对象是什么类型的对象,ECMASCript提供了instanceof操作符:

result = varibale instanceof constructor

1
2
3
var person = new Object();
console.log(person instanceof Object);//变量person是Object吗?
console.log(person instanceof Array);//变量person是Array吗?

执行环境及作用域

执行环境

执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。

作用域链

当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途,是保证当前执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。
标识符解析是沿着作用域链一级一级地搜索标示符的过程。搜索过程始终从作用域链的前端开始,然后逐级向后回溯,直至找到标识符为止(如果找不到标识符,通常会导致错误发生)。

内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数。

延长作用域链

  • try-catch语句的catch块
  • with语句

垃圾收集

  • 标记清除
  • 引用计数

管理内存