js函数:参数、做用域、匿名函数总结

前言:我入门学的 java这种强类型语言,刚开始学js第一感受是挺简单,后来发现仍是too young。因此,本次就把做用域、匿名函数作一个完整总结,黑喂狗~~~javascript

-------------------分割线----------------------java

1.函数

返回值/参数

返回值:::::::::::::::::::::::::
js的函数在定义时没必要指定返回值,并且任何函数均可以经过return随时返回值。
函数在执行完return以后中止并当即退出,所以return后面的代码永远不会执行。数组

function sum(num1,num2){
        return num1 + num2;
        alert("Hello World");  //这段代码永远不会执行
    }

参数:::::::::::::::
js函数不介意传递进来多少个参数,也不在意传递进来的是什么参数类型。
参数在内部是由一个数组来表示的,函数接收的永远都是这个数组,函数体内部能够经过arguments对象来访问这个参数数组,从而能够获取传递给函数的每个参数。函数

以下代码:code

function howManyArgs(){
        alert(arguments.length);
    }
    
    howManyArgs("String",45);  //2
    howManyArgs();             //0
    howManyArgs(12);           //1

从上面的代码能够看出来,定义函数时没有给函数指定参数名字,而调用时依然能够传递进去任何数量和类型的参数,所以在js函数中:命名的参数只是提供便利,但不是必须的。理解这点很重要。对象

不完美的重载:::::::::::::::::
既然能够用arguments.length判断传入参数的个数,那么js函数也能够实现不完美的重载。
以下代码:事件

function doAdd(){
        if(arguments.length == 1){
            alert(arguments[0] + 10);
        }
        if(arguments.length == 2){
            alert(arguments[0] + arguments[1]);
        }
    }
    
    doAdd(10);   //20
    doAdd(30,20);    //50

arguments[i]和对应命名参数的关系:::::::::::::::::
看以下代码:ip

function doAdd(num1,num2){
        arguments[1] = 10;          //重写第二个参数
        alert(arguments[0] + num2);
    }

arguments对象中的值会自动反映到对应的命名参数,可是读取这两个值不会访问相同的内存空间,
修改命名参数并不会改变arguments中对应的值
arguments对象长度是由调用函数时传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。内存

2.传递参数

js中全部的函数都是按值传递的。
在向参数传递基本类型时,被传递的值会被复制给一个局部变量。
在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,所以这个局部变量的变化会反映在函数的外部。作用域

来看几个例子:

function addTen(num){
        num += 10;
        return num;
    }
    var count = 20;
    var result = addTen(count);
    alert(count);       //20,没有变化
    alert(result);      //30

count传递给参数num,函数内部num作了修改,可是没有反映到count上。

function setName(obj){
        obj.name = "Jack";
    }
    var person = new Object();
    setName(person);
    alert(person.name);     //Jack

这个例子很容易让人以为,引用类型作为函数参数传递是按引用传递的,由于局部的修改:obj.name = "Jack",反映在了全局的做用域上:person.name,事实上并非如此。
事实上:咱们建立了一个对象,并把它保存在person变量中,而后把person当作参数传递到setName()函数中复制给了obj,在这个函数内部obj和person引用的是同一个对象。

再看一个例子:

function setName(obj){
        obj.name = "Jack";
        obj = new Object();
        obj.name = "Rose";
    }
    var person = new Object();
    setName(person);
    alert(person.name);       //Jack

这个例子中在setName()函数中,为obj从新定义了一个对象,另外一行代码为该对象定义了一个带有不一样值的name属性。若是person传递给函数setName()以后是按引用传递的,那么对obj.name的修改就会反映到person.name上,事实上person.name依然是Jack。
当在函数内部重写obj时,这个变量的引用就是一个局部变量了,这个局部变量在函数执行完毕后当即销毁。

3.执行环境及做用域

定义什么的太多了就不写了,直接上代码

var color = "blue";
    function changeColor(){
        var anotherColor = "red";
        function swapColors(){
            var tempColor = anotherColor;
            anotherColor = color;
            color = tempColor;
            //这里能够访问 color,anotherColor 和tempColor
        }
        
        swapColor();
        //这里能够访问color, anotherColor
    }
    
    changeColor();  //这里只能访问color

上面代码中有三个执行环境:全局环境、changeColor()的局部、和swapColors()的局部环境。
全局环境中有一个color变量和changeColor()函数。
changeColor()的局部环境中有一个名为anotherColor的变量和一个swapColors()的函数,可是它也能够访问全局环境中的变量color
swapColors()局部环境中有一个变量tempColor,只能在这个环境中访问到。

不管是全局环境仍是changeColor()的局部环境都无权访问tempColor,在swapColors()内部能够访问其余两个环境中的全部变量,由于那两个环境是它的父执行环境。

总结:内部环境能够经过做用域链访问全部的外部环境,但外部环境不能访问内部环境中的任何变量和函数,每一个环境内部没有这个变量或者函数时,均可以向上搜索变量和函数名,直到找到为止。

没有块级做用域

java等语言话括号括起来的代码块都有本身的做用域,可是js中总有例外,看下面代码:

if(true){
        var color = "blue";
    }
    alert(color);    //blue

这里是在if语句中定义了一个变量color,和做用域函数里面定义变量的例子不一样,在if语句中的变量声明将添加到当前的执行环境中,看下面for循环的例子:

for(var i = 0; i<10; i++){
        doSomething(i);
    }
    alert(i);   //10

对于js,由for语句建立的变量i即便在for循环执行结束后,也依旧会存在于循环外部的执行环境。

4.匿名函数

看下面例子:

window.onload = 
           function(){
               alert("Hello World");
           };
           
       var person = {
           callName: function(){
               alert("My name is Jack");
           }
       };
       person.callName();  
           
       setTimeout(
           function(){alert("Hello World");},
           500);

1.首先,为load事件建立了一个函数作为事件处理程序,不会直接调用这个函数,而是在页面加载时自动调用,因此不必为这个函数命名,像这样:

function sayHello(){alert("Hello World");};
    window.onload = sayHello;

2.声明了一个匿名函数,作为person对象的一个属性callName,能够经过该属性来调用这个方法:
如:person.callName();

3.将匿名函数作为回调函数传递给另一个函数,代码中将匿名函数作为一个参数传递给window对象的setTimeout()方法,该方法将在半秒后被调用。

-------------------------------------------------------end--------------------------------------------------------

相关文章
相关标签/搜索