您的位置:首页 > Web前端 > JavaScript

javaScript基础:函数

2016-06-24 07:03 405 查看
一、函数简介

函数是定义一次但却可以调用或执行任意多次的一段JS代码。

函数有时会有参数,即函数被调用时指定了值的局部变量。

函数常常使用这些参数来计算一个返回值,这个值也成为函数调用表达式的值。 

二、函数的使用

1.函数的声明与调用

function box() { //没有参数的函数
alert('只有函数被调用,我才会被之执行');
}
box();//函数调用

function box(name, age) { //带参的函数
alert('你的姓名:'+name+',年龄:'+age);
}
box('李炎恢',28);//函数调用,并传参
注意:ECMAScript中的函数,没有像其他高级语言那种函数重载功能。 只要函数名一样就是一个函数,不会因为是否传参数而成为两个不同的函数。

2.函数中的argument对象

ECMAScript函数不介意传递进来多少参数,也不会因为参数不统一而错误。实际上,函数体内可以通过arguments对象来接收传递进来的参数。 

arguments是一个类数组对象,包含着传入函数中的所有参数,主要用途是保存函数参数。 

function box() {
var sum = 0;
if (arguments.length == 0) return sum; //如果没有参数,退出
//如果有,就累加
for(var i = 0;i < arguments.length; i++) {
sum = sum + arguments[i];
}

//返回累加结果
return sum;
alert(box(5,9,12));//调用函数,并传递参数,可以传递任意个参数

注意:函数声明时若没有指定形参,调用时也可以传递实参,只是这时候要通过argument来拿到参数。

arguments这个对象还有一个名叫callee的属性,该属性是一个指针,指向拥有这个arguments对象的函数。 

function box(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num-1);//使用 callee 来执行自身argument.callee(num-1)就相当于box(num-1) }
}


3.函数中的this对象

函数内部另一个特殊对象是this,其行为与Java和C#中的this大致相似。

换句话说,this引用的是函数据以执行操作的对象,或者说函数调用语句所处的那个作用域。函数内的this指的就是函数的调用者。

PS:当在全局作用域中调用函数时,this对象引用的就是window 

window.color = '红色的';
var box = {
color : '蓝色的'
};
function sayColor() {
alert(this.color);
}
sayColor();//此时函数中的this是window对象
box.sayColor = sayColor;
box.sayColor();//此时函数中的this是box对象


三、匿名函数
1.匿名函数的创建
//没有函数名的函数叫做匿名函数
//匿名函数会报错
function () {
return 'lee';
}


2.匿名函数的调用
//通过表达式自我执行
(function (){//封装成表达式

alert('wang');

})();//()表示执行函数并传参
3.匿名函数作为函数的返回值
var box = function  (){//将匿名函数赋值给变量

return function(){//将匿名函数作为函数的表达式返回
return 'lee';
}
};
var box2 = box();//此时box2 = function (){return 'lee';};
alert(box2());//弹出提示框lee;
注意区别下边这种写法:
var box = (function (){//将匿名函数的返回值赋值给变量

return function (){//匿名函数作为函数的返回值
return 'lee';
}
})();

alert(box());//此时box = function (){return 'lee';};


ps:函数里边套函数其实就是闭包;

四、闭包
1.什么是闭包?

闭包是指有权访问另一个函数作用域中的变量的函数 ,创建闭包的常见的方式,就是在一个函数内部创建另一个函数,通过另一个函数访问这个函数的局部变量。 

有一个函数A, 函数A内部的有一个局部变量a;

有一个函数B。

函数B在函数A的内部。函数B有权访问变量a;

函数B就是一个闭包。

闭包的优点 可以把局部变量驻留在内存中 ,可以避免使用全局变量。(全局变量污染导致应用程序不可预测性,每个模块都可调用必将引来灾难,所以推荐使用私有的,封装的局部变量)。 
闭包的缺点:由于闭包里作用域返回的局部变量资源不会被立刻销毁回收,所以可能会占用更多的内存。过度使用闭包会导致性能下降,建议在非常有必要的时候才使用闭包。 
举例:闭包将局部变量驻留在内存中

var box = function (){
var num = 100;
//创建一个闭包
return function (){
//访问函数box的局部变量,并将变量驻留在内存里
num ++;
return num;
}
};

var box1 = box();//正常情况下方法执行完,num变量就会被释放掉。因为闭包的存在它会驻留在内存内。
alert(box1());//101
alert(box1());//102
PS:如果再次调用box();那么num的值又会等于100.相当于重新赋值。

2.循环里的闭包

var box = function (){
var arr = [];
//变量i是box内的局部变量
//匿名函数会使局部变量驻留在内存中。
for(var i = 0;i<5; i++){
//数组的每个元素都是一个函数,函数的返回值都是变量i;
// 函数没有自我执行。只是将函数对象保存在数组内成为数组的元素。当调用这个函数时才会返回i的值。
arr[i] = function (){
return i;
};
}
return arr;
};

var box1 = box();//box1是一个包含5个函数元素的数组.
alert(box1);
for(var i = 0;i<5;i++){
var num = box1[i]();//数组元素是函数,执行这个函数返回变量i的值。但此时i的值已经是5;
alert(num);//返回的结果都是5;
}
PS:如果了解block的话,会发现闭包跟block很相似,都是一个代码片段,这个代码片段实质就是存储一个"方法",在需要的时候调用即可。

//void (^myBlock)(void)是一个名为myBlock的变量,但这个变量存储的是一个代码片段
//第一个void为返回值
//第二个void为参数
void (^block)(void)=^(){
//执行的代码
};
myBlock();//block调用 ()号内为传递的参数myBlock()整体就是返回值。可以发现跟方法的调用太相似
/*
^(){
//执行的代码
};
相当于闭包
function (){
return i;
}

*/


解决方法一:

arr[i] = (function (){//让内部函数立即执行,把执行结果存入数组内,这样数组内存的就不是函数而是函数的返回值
return i;
})();


解决方法二:

var box = function (){
var arr = [];
for(var i = 0;i<5; i++){
//在匿名函数内部再套一个匿名函数,将第一个匿名函数执行,并将i的值作为参数传递进去,赋值给num变量。num = i;
arr[i] = function (num){
//num也是一个局部变量。
//num被第二个匿名函数访问,驻留在内存中 需要注意的是数组每个元素的存的是不同的函数对象,函数对象不同,num也不同
//也就是在执行过程中会产生5个num变量,他们分别被赋值为0,1,2,3,4后就没有在被访问。所以放第二个匿名函数被调用时他们的值就分别是0,1,2,3,4
return function (){
return num;
};
}(i);
}
return arr;
};

var box1 = box();
alert(box1);
for(var i = 0;i<5;i++){
var box2 = box1[i]();
alert(box2);
}


3.闭包里的this指向

在闭包中使用this对象也可能会导致一些问题,this对象是在运行时基于函数的执行环境绑定的,如果this在全局范围就是window,如果在对象内部就指向这个对象。而闭包却在运行时指向window,因为闭包并不属于这个对象的属性或方法。 

var color = 'green';
var box = {
color : 'red',
run :  function (){
return function (){
//闭包不属于box,里面的this指向window
//这里的this指向的是window
return this.color;
}
}
};

alert(this.color);//green   this指向window
alert(box.run()());//green  闭包里的this同样指向window;


解决方法一:
//对象冒充:
var box2 = box.run();//拿到这个闭包函数
alert(box2.call(box));//red this指向的是box对象。对象冒充
解决方法二:
var color = 'green';
var box = {
color : 'red',
run :  function (){
//这里的this指向的是box;
var that = this;//拿到这个this对象
return function (){
//闭包不属于box,里面的this指向window。
//这里的this指向的是window
return that.color;//返回that对象的color属性
}
}
};
alert(box.run()());//red



                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  javascript