代码改变世界

Java Script 读书笔记 (三) 函数

2017-12-14 16:28  钱先生  阅读(163)  评论(0编辑  收藏  举报

1. 函数作用域

    在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。

   变量v在函数内部定义,所以是一个局部变量,函数之外就无法读取。

   函数内部定义的变量,会在该作用域内覆盖同名全局变量。

  

1 var v=1;
2 function f(){
3    var v=2;
4    console.log(v);
5 }
6 
7 f() //2
8 v  // 1
View Code

   注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。

  

1 if (true){
2    var x=5;
3 }
4 console.log(x);  //5
View Code

  上面代码中,变量x在条件判断区块之中声明,结果就是一个全局变量,可以在区块之外读取。

 

 

2. 函数内部的变量提升

    与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的  头部。

  

 1 function foo(x){
 2   if (x>100){
 3       var tmp = x -100;
 4    }
 5 }
 6 
 7 
 8 //上面的代码等同于
 9 
10 function foo(x){
11    var tmp;
12    if (x>100){
13        tmp -x -100;
14    };
15 }
View Code

 

 

3. 函数本身的作用域

    函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。

   

 1 var a=1;
 2 var x =function(){
 3      console.log(a);
 4 };
 5 
 6 function f(){
 7     var a=2;
 8     x();
 9 }
10 f() //1
View Code

上面的代码中, 函数x是在函数f的外部声明的,所以它的作用域绑定外层,内部变量a不会到函数f体内取值,所以输出1,而不是2.

 

 

4. 默认值

   通过下面的方法, 可以为函数的参数设置默认值。

  

1 function f(a){
2    a=a||1;
3    return a;
4 }
5 
6 f("") //1
7 f(0) //1
View Code

   上面代码的||表示 “或运算”,即如果a有值,则返回a, 否则返回事先设定的默认值。
   这种写法会对a进行一次布尔运算, 只有为true时,才会返回a. 可是, 除了undefined以外,0、空字符、null等的布尔值也是false.也就是说,在上面的函数中,不能让a等于0或者空字符串, 否则在明明有参数的情况下,也会返回默认值 。为了避免这个问题, 可以采用下面更精确的写法.

  

1 function f(a){
2    (a!== undefined && a!==null)? a=a:a=1;
3    return a;
4 }
5 
6 f() //1
7 f("") // ""
8 f(0) //0
View Code

 

 

 

5. 传递方式

   传值传递 (passes by value): 函数参数是原始类型的值(Int,String,Boolean...), 在函数体内修改参数值,不会影响到函数外部。

   传址传递 (pass by reference) : 函数参数是复合类型的值(数组,对象,其他函数),在函数内部修改参数,将会影响到原始值。

  

  

1 var obj={p:1};
2 function f(0){
3     o.p=2;
4 |
5 f(obj);
6 obj.p //2
View Code

  上面代码中, 传入函数f的是参数对象obj的地址,因此,在函数内部修改obj的属性p,会影响到原始值。

   注意,如果函数内部修改的,不是参数对象的某个属性, 而是替换掉整个参数,这时不会影响到原始值,例: 

1 var obj=[1,2,3];
2 function f(0){
3   o=[2,3.4];
4 }
5 f(obj);
6 
7 obj //[1,2,3]
View Code

   上面代码中, 在函数f内部,参数对象obj被整个替换成另一个值,这时不会影响到原始值,因为形式参数(o)与实际参数obj存在一个赋值关系。

  如果需要对某个原始类型的变量, 获取传址传递的效果,可以将它写成全局对象的属性:

 

1 var a=1;
2 function f(p){
3    window[p] =2;
4 }
5 f("a");
6 
7 a//2
View Code

  上面代码中, 变量a本来是传值传递,但是写成window对象的属性,就达到了传址传递的效果。

 

 

6. 同名参数

    如果有同名的参数,则取最后出现的那个值。例:   

1 function f(a,a){
2     console.log(a);
3 }
4 f(1,2) //2
View Code

    即使后面的a没有值或被省略,也是以其为准.

    

1 function f(a,a){
2     console.log(a);
3 }
4 f(1) // undefined
View Code

 

   调用函数f的时候,如果没有提供第二个参数,a的取值就变成了undefined.这时, 如果要获得第一个a的值,可以使用arguments对象。
  

1 function f(a,a){
2      console.log(arguments[0]);
3 }
4 f(1) //1
View Code