只定义一次,但能被执行调用任意次。
定义
函数使用function关键字定义,可以使用函数定义表达式或函数声明语句。
//计算两个笛卡尔坐标之间的距离
function distance(x1,y1,x2,y2){
var dx = x2-x1;
var dy = y2-y1;
return Marh.sqrt(dx*dx+dy*dy);
}
//计算阶乘的递归函数(调用自身的函数)
function factorial(x){
if(x <=1) return 1;
return x*factorial(x-1);
}
//函数表达式定义了一个函数用来求参数的平方,并把它赋值给一个变量
var square = function(x){ return x*x;}
//函数表达式可以包含名字,在递归时很有用
var f = function fact(x){
if(x<=1) return 1;
else return x*fact(x-1);
};
//函数表达式定义后立即调用
var tensquared = (function(x){return x*x;}(10));
以表达式定义的函数,函数的名称是可选的,以表达式方式定义的函数在定义之前无法调用。
构造函数
函数或者方法调用之前带有new关键字,它就构成构造函数调用。构造函数调用和普通函数调用在实参处理、调用上下文和返回值方面不同。
如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传人函数内。如果构造函数没有形参,构造函数调用的语法允许省略实参列表和圆括号。
var o = new Object();
var o = new Object; 等价。
构造函数通常不使用return关键字,他们通常初始化新对象,当构造函数的函数体执行完毕时,会显示返回。
函数的实参和形参
当调用函数的时候传入的实参比函数声明时指定的形参个数要少,剩下的形参都将设置为undefined值。
//将对象o中可枚举的属性名称追加到数组a中,并返回这个数组a
//如果数组a未定义,则创建一个新的在数组
function getPropertyNmaes(o,/*optional*/ a){
a = a || [];//如果为定义,使用新的数组
for( var property in o) a.push(property);
return a;
}
var a = getPropertyNames(o);//将o的属性存储到一个新的数组中
getPropertyNames(p,a);//将p的属性追加到数组a中
当使用这种可选实参来实现函数时,需要将可选实参放在实参列表的最后。
可变长的实参列表
当调用函数的时候传入的实参个数超过函数定义时的形参个数时,可以使用实参对象。
在函数体内,标示符arguments是指向实参对象的引用,实参对象时一个类数组对象,可以通过数字下标访问传入函数的实参值、
//验证实参个数
function f(x,y,z){
if(arguments.length !=3){
throw new Error("reeor");
}
else{
..........
}
}
闭包
我觉得,闭包在JS中是一个比较强大的语言特色,但是,在使用闭包的过程中,有很多途径会引起内存泄漏的问题。。先看下面这段代码:
<body>
<div class='menu-bar' id='myMenu'></div>
<mce:script language='javascript'><!--
var menu = document.getElementById('myMenu');
AttachEvent(menu);
function AttachEvent(element) {
element.attachEvent( "onmouseover", mouseHandler);
function mouseHandler(){ /* whatever */ }
}
// --></mce:script></body>
这是一个典型的闭包引用。但是我们可以注意到一个问题,在该闭包函数的作用域内维持了一个对element的引用(这里的elment指的是munu这个DOM对象),而该DOM对象同时又包含着一个对该闭包的引用。因此,这便形成了一个循环引用。要释放DOM对象,那么先要删除闭包对它的引用,而要释放闭包,又要等待DOM引用的释放。这样,边造成了内存泄漏的问题。
还有一点,因为闭包存在于外层函数中,那么它是作为一个“临时对象存在的”,当外层函数执行完毕时,那么我们便失去了对闭包的引用,这时,我们又该如何去调用detachEvent来清除引用呢?
解决方案:
将闭包赋值给element对象的一个属性,如element.handler=function mouseHandler(){};那么,在body的onunload事件中,可以直接通过element.handler来引用它,从而释放事件引用。。