定义函数的两种方式:函数声明 和 函数表达式
"use strct";
// 函数声明,指定函数名
function functionName(arg0,arg1,arg2){
// 函数体
}
// 函数声明提升,即执行代码之前会先读取函数声明
sayHi(); //再调用
function sayHi(){ //先读声明
alert("hello world"); // hello worold
}
匿名函数
"use strct";
// 函数表达式
// 匿名函数,即创建一个函数并将它赋值给变量functionName
// 没有函数提升
var functionName = function(arg0,arg1,arg2){
//函数体
};
递归
递归函数是一个在函数通过名字调用自身的情况下构成。
//经典的递归阶乘函数
function factorial(num){
if(num<=1){
return 1;
}else{
return num*factorial(num-1);
}
}
var anotherFactorial = factorial;
// 存在弊端
//如果factorial=null;anotherFactorial //error
alert(anotherFactorial(3));
// argument.callee 指向正在执行的函数指针
"use strict"; // 存在弊端 严格模式无法运行
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
var anotherFactorial=factorial;
factorial=null;
//命名函数表达式,在严格模式也能正常运行
"use strict";
var factorial=(function f(num){
if(num<=1){
return 1;
}else{
return num*f(num-1);
}
})
var anotherFactorial= factorial;
factorial=null;
alert(anotherFactorial(3));
闭包
闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
function createComparisonFunction(propertyName){
return function(obj1,obj2){
var val1=obj1[propertyName];
var val2=obj2[propertyName];
if(val1<val2){
return -1
}else if(val1>val2){
return 1;
}else{
return 0;
}
};
}
createComparisonFunction() 函数执行完毕之后,其活动对象不会被销毁,因为匿名函数的作用域链仍然在引用这个活动对象。
即createComparisonFunction() 函数返回后,其执行环境环境的作用域链会被销毁,但它活动对象仍然会留在内存中;知道匿名函数被销毁后。
销毁匿名函数 compareName=null
作用域链查找对象
if(value1<value2){
return -1;
}else if(value1>value2){
return 1;
}else{
return 0;
}
}
var result = compare(5,10);
闭包与变量
闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊变量
//每个函数的作用域链中都保存着createFunction() 函数的活动对象,引用都是同一变量i
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i] = function(){
return i;
};
}
return result;
}
//创建另一个匿名函数强制让闭包的行为符合预期
//重写createFunction() 函数后,每个函数就会返回不同的索引值
//没有直接把闭包赋值给数组,而是定义了一个匿名函数,并将立即执行该匿名函数的结果赋给数组
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i]=function(num){
return function(){
return num;
}
}(i);
}
return result;
}
关于this 对象
在闭包中使用this 对象可能会导致一些问题。this 对象是运行时基于函数执行环境绑定的:在全局函数中,this 等于window,而当函数被作为某个对象方法调用时,this 等于那个对象。
匿名函数的执行环境具有全局性,因此this 通常指向window(通过call() 或apply() 改变函数的环境下,this会指向其他对象)
var num=15;
function num1(){
var num=2;
return function(){
return this.num;
}
}
alert(num1()());
//把外部作用域中的this 对象保存在一个闭包能够访问的变量里,就可以让闭包访问该对象
var name = "The Window";
var object={
name:"My Object",
getNameFunc : function(){
var that =this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //My Object
内存泄漏
function assignHandler(){
var element=document.getElementById("someElement");
var id=element.id;
element.onclick=function(){
alert(id);
};
element=null;
}
模仿块级作用域
<script>
//JavaScript 没有块级作用域。
//意味着在块级语句中定义的变量,实际上是包含函数中而非语句中创建的。
//在Java、C++语句中,变量i只会在for 循环的语句块中有定义,循环一旦结束,变量i就会被销毁
"use strict";
function outputNumbers(count){
for(var i=0;i<count;i++){
document.write(i);
}
document.write(i);
}
outputNumbers(5);
</script>
// JavaScript 不会告诉是否多次声明同一个变量;
// 遇到这种情况,它只会对后续的声明视而不见
var i;
document.write(i);
匿名函数可以用来模仿块级作用域并避免重新声明变量这个问题。
<script>
"use strict";
//块级作用域(通常称为私有作用域)的匿名函数的语法如下
//代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对括号会立即调用这个函数。
(function(){
//这里是块级作用域
})();
</script>
理解步骤:
<script>
"use strict";
var count =5;
outputNumbers(count);
//把值直接传递给函数
outputNumbers(5); // 变量只不过是值的另一种表现形式,因此可以用实际值替换
//定义一个匿名函数,并把匿名函数赋值给变量someFunction。
//调用函数的方式是在函数名称后面添加一对圆括号,即someFunction()
var someFunction=function(){
// 这里是块级作用域
};
someFunction();
//通过上面例子,可以使用实际值来替代变量count
//那是否可以用函数值直接取代函数名?
function(){
//这里是块级作用域
}(); //出错
//上面代码会导致语法错误,因为JavaScript 将function 关键字当作一个函数声明的开始
//函数声明后面不能跟圆括号,而函数表达式可以跟圆括号
//将函数声明转换成函数表达式,只需要象下面给它加一对圆括号即可
(function(){
//这里是块级作用域
})();
</script>
<script>
//无论什么地方,只要临时需要一些变量,就可以使用私有作用域
//匿名函数中定义的任何变量,都会在执行结束时被销毁
function outputNumbers(count){
(function () {
for(var i=0;i<count;i++){
document.write(i);
}
})();
}
outputNumbers(5);
</script>
这种做法可以减少闭包占用内存的问题,因为没有指向匿名函数的引用。只要函数执行完毕,就可以立即销毁其作用链。
私有变量
严格讲,JavaScript 中没有私有成员的概念;所有对象属性都是公有的。但有一个私有变量概念,任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量
<script>
//私有变量包括函数参数、局部变量和在函数内部定义的其他函数
function add(num1,num2){
var sum = sum1+sum2;
return sum;
}
</script>
访问私有变量共有办法:通过函数内部创建一个闭包,闭包可以通过作用域链访问。
把有权访问私有变量和私有函数的共有方式称为特权方式