JavaScript高级程序设计复习笔记(一)

今天重新看了一遍JS高程的第一到四章,查漏补缺记录了一些容易出错的地方,做笔记如下:

变量的作用域问题

1
2
3
4
5
6
function test(){
message = "Hi";
//此时因为未进行变量声明,message默认为全局变量
}
test(); //调用函数
console.log(message); //Hi

变量未声明,且循环定义的循环变量,都是在全局的作用域中。

typeof()方法

1
2
3
var message;
console.log(message); //undefined
console.log(age); //undefined

注:Null类型表示一个空对象指针,因此使用typeof检测时会返回object。(undefined派生自Null,因此二者相等)
NaN与任何值都不相等,包括NaN本身

Number()方法进行数值转换

1
2
3
4
5
6
var num3 = Number(0xa);   //10
var num2 = Number(011); //11(不会判定为八进制)
var num1 = Number(11); //11
var num6 = parseInt(011); //9(判断为八进制,ES5以上不适用,返回11)
var num5 = parseInt(011,8);//9
var num4 = parseInt("AF",16);//175(转换为16进制)

按位操作(根据数值的二进制进行操作)

1
2
3
4
5
6
7
8
var result1 = 3 & 1;
console.log(result1); //1(按位与)
var result2 = 1 | 3;
console.log(result2); //3(按位或)
var result3 = ~result2;
console.log(result3); //-4(按位非,求反码)
var result4 = 4 ^ 3;
console.log(result4); //7(按位异或)

变量的赋值技巧

1
var num = num1 || num2;

当num1有值是,num被赋值为num1,否则被赋值为num2.

switch操作符

switch的语句中可以使用任何数据类型,这在其他的很多语言中是没有的,且switch支持表达式。
注:switch使用的是全等操作符,因此“10”和10 是不相等的。

arguments[]对象

arguments[]对象可在函数调用时使用,arguments[0]表示第一个参数,arguments[1]表示第二个参数,以此类推。

1
2
3
4
5
function anyArgs(){
console.log(arguments.length);
}
anyArgs("string",1); //2
anyArgs(); //0

JS方法不存在重载,因此不可同时var两个相同函数名的函数

基本类型和引用类型的变量赋值

基本类型:相当于在堆中创建了一个新空间,并在该空间中为新变量赋予相同的值。

1
2
3
4
var num1 = 5;
var num2 = num1;
num1 = 4;
console.log(num2); //5

引用类型:在堆中的引用空间是不变的,新的变量值与老的变量值指向同一个堆空间。

1
2
3
4
var obj1 = new Object();
var obj2 = new Object();
obj1.name = "Changer";
console.log(obj2.name); //Changer

传参问题

向参数传递基本类型值时,被传递的值会被复制给一个局部变量,其本身的值及属性不会改变。

1
2
3
4
5
6
7
8
var num1 = 1;
function count(num){
num++;
return num;
}
count(num1);
cinsole.log(num1); //1
console.log(count(num1)); //2

当给引用类型传参时,引用类型变量传递到函数中会复制到变量中,在函数内部,变量和引用类型常量实际上引用的是同一个对象,因此在函数内部为常量添加属性后,在外也可调用。(这句话,我有点儿没看懂)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function setName(obj){
obj.name = "Nicholas";
}
var person = new Object();
setName(person);
console.log(person.name); //Nicholas
//另有一例,用于说明局部变量的传参问题
function setName(obj){
obj.name = "Nicholas";
obj = new Object();
obj.name = "Greg";
}
setName(person);
console.log(person.name); //Nicholas
//原因:局部变量作用域仅在函数中,使用后即被销毁。

延长作用域链

1
2
3
4
5
6
7
function buildUrl(){
var qs = "?debug=true";
with(location){
var url = href + qs;
}
return url;
}

此函数有效,原因(个人认为)S函数无块级作用域,因此可在with外调用。

JS的垃圾回收机制

标记清除

当变量进入环境时,就将这个变量标记为“进入环境”状态,当变量离开环境时,则将其标记为“离开环境”状态,它会去掉环境中的变量及被环境中变量引用的变量的标记。大部分浏览器采用此策略。

引用计数

跟踪记录每个值被引用的次数,当声明了一个变量并将一个引用类型值赋值给该变量时,该值的引用次数则为1,当再次被引用时加一,相反,当引用的变量取消引用时,减一,减为0后将被回收。
但是该方法存在一个很严重的性能问题:

1
2
3
4
5
6
function problem(){
var objectA = new Object();
var objectB = new Object();
objectA.otherObject = objectB;
objectB.anotherObject = objectA;
}

运行上例时,其引用次数将永远不为0,若此函数被大量调用,则其垃圾将永远不会回收。
解决方案(这也是采用标记清除方法的垃圾回收最佳方案):当不需要使用该变量时,为其设置值为null。

1
2
objectA.otherObject = null;
objectB.anotherObject = null;

另:在IE中,可食用window.CollectGarbage()方法立即执行垃圾回收。

文章目录
  1. 1. 变量的作用域问题
  2. 2. typeof()方法
  3. 3. Number()方法进行数值转换
  4. 4. 按位操作(根据数值的二进制进行操作)
  5. 5. 变量的赋值技巧
  6. 6. switch操作符
  7. 7. arguments[]对象
  8. 8. JS方法不存在重载,因此不可同时var两个相同函数名的函数
  9. 9. 基本类型和引用类型的变量赋值
  10. 10. 传参问题
  11. 11. 延长作用域链
  • JS的垃圾回收机制
    1. 1. 标记清除
    2. 2. 引用计数
  • |