前言:我入门学的 java这种强类型语言,刚开始学js第一感受是挺简单,后来发现仍是too young。因此,本次就把做用域、匿名函数作一个完整总结,黑喂狗~~~javascript
-------------------分割线----------------------java
返回值:::::::::::::::::::::::::
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对象长度是由调用函数时传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。内存
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时,这个变量的引用就是一个局部变量了,这个局部变量在函数执行完毕后当即销毁。
定义什么的太多了就不写了,直接上代码
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循环执行结束后,也依旧会存在于循环外部的执行环境。
看下面例子:
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--------------------------------------------------------