理解函数声明和函数表达式
1、函数声明
function functionName(arg0,arg1,arg2){
}
重要特征:函数声明的提升,即在代码执行前解析器会先读取函数声明
2、函数表达式
var functionName = function(){
//函数体
};
匿名函数:像等号右边这样没有函数名的的函数就是匿名函数
一、递归
递归函数是在一个函数通过名字调用自身的情况下构成的
function factorial(num) {
if(num <= 1){
return 1;
}else{
return num * factorial(num - 1);
}
}
var anotherFactorial = factorial;
factorial = null;
console.log(anotherFactorial(4));
以上代码运行会报错,因为当运行anotherFactorial的时候,函数体内部的factorial已经是null,所以要通过arguments.callee来解决,arguments.callee 是一个指向正在执行的函数的指针,因此可以用它来实现对函数的递归调用
function factorial(num) {
if(num <= 1){
return 1;
}else{
return num * arguments.callee(num - 1);
}
}
但是在“use strict”模式下不能访问arguments.callee。所以我们要换一种方法解决,使用命名函数表达式来达成相同的结果
var factorial = (function f(num) {
if(num <= 1){
return 1;
}else{
return num * f(num - 1);
}
});
以上代码创建了一个名为f()的命名函数表达式,然后将它赋值给变量factorial。即便把函数赋值给了另一个变量,函数的名字f 仍然有效,所以递归调用照样能正确完成。这种方式在严格模式和非严格模式下都行得通。
二、闭包
1、概念
闭包是(指有权访问另一个函数作用域中的变量的)函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数
变量对象:每创建一个执行环境都有一个对应的变量对象,这个对象包含着这个作用域中的所有变量。在浏览器中,全局变量对象就是window
作用域链本质上是一个指向变量对象的指针列表,它只引用但不实际包含变量对象
无论什么时候在函数中访问一个变量时,就会从作用域链中搜索具有相应名字的变量。一般来讲,当函数执行完毕后,局部活动对象就会被销毁,内存中仅保存全局作用域(全局执行环境的变量对象)。但是,闭包的情况又有所不同。
看了一遍JS红皮书的这一章,感觉还是有点懵逼。就我现在所知道的闭包的知识:
用途:
1、访问函数内部变量。
2、让变量的值始终保持在内存中。
三、模仿块级作用域
匿名函数可以用来模仿块级作用域并避免这个问题。用作块级作用域(通常称为私有作用域)的匿名函数的语法如下所示。
(function(){
//这里是块级作用域
})();
以上代码定义并立即调用了一个匿名函数。将函数声明包含在一对圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号会立即调用这个函数。
function outputNumbers(count) {
(function(){
for(var i=0; i<count; i++){
console.log(i);
}
})();
console.log(i);
}
outputNumbers(6); //Uncaught ReferenceError: i is not defined
四、私有变量
任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。 私有变量包括函数的参数、局部变量和在函数内部定义的其他函数。
我们把有权访问私有变量和私有函数的公有方法称为特权方法(privileged method)。
在对象上创建特权方法的方式: