函数声明语句
使用关键字 function
声明函数,声明的函数在所有代码执行之前已经被解析,所以函数声明可以写在调用函数的代码之后
//声明一个名称为fun函数
function fun(){
//...
}
fun();
函数表达式
用函数表达式给变量赋值,只在代码运行到代码所在行才会被解释执行,因此函数表达式不能写在调用的代码之后
//函数表达式
var fun = function(){};
fun();
自执行函数
错误的实验
当你声明类似 function foo(){}
或 var foo = function(){}
函数的时候,通过在函数名后面加个括弧就可以实现执行函数,例如 foo()
。
是不是意味着在函数表达式后面加个括弧都可以自动执行函数?
function(){ /* code */ }();
事实上这样做会报错,因为在解析器在解析 function
关键字的时候,默认认为是 function
声明,而不是 function
表达式。如果你不显式告诉编译器,它默认会声明成一个缺少名字的 function
,并且抛出一个语法错误信息,因为 function
声明需要一个名字。
有趣的是,即便你为上面那个错误的代码加上一个名字,他也会提示语法错误,只不过和上面的原因不一样。在一个表达式后面加上括号(),该表达式会立即执行,但是在一个语句后面加上括号(),是完全不一样的意思,他的只是分组操作符
// 下面这个function在语法上是没问题的,但是依然只是一个语句
// 加上括号()以后依然会报错,因为分组操作符需要包含表达式
function foo(){ /* code */ }(); // SyntaxError: Unexpected token )
// 但是如果你在括弧()里传入一个表达式,将不会有异常抛出
// 但是foo函数依然不会执行
function foo(){ /* code */ }( 1 );
// 因为它完全等价于下面这个代码,一个function声明后面,又声明了一个毫无关系的表达式:
function foo(){ /* code */ }
( 1 );
正确的自执行方式
由上面的错误实验可知,function
关键字必须被解析为表达式,表达式后面再跟一组括号,才可以实现自执行:
将
function(){}
放在括号()
中间,括号中间不能包含语句,所以放在括号中间的一定会被解析为表达式(function(){
//...
})();
(function(){
//...
}());
将
function(){}
与运算符一起使用,也会被解析为表达式fale || function(){
//...
}();
//
true && function(){
//...
}();
//通过一元运算符
!function(){
//...
}();
#
+function(){
//...
}();
#
-function(){
//...
}();
函数作为类使用
function People(name)
{
this.name = name;
//对象方法
this.inside = function(){
console.log("我是内部定义的,我叫" + this.name);
}
}
//类方法
People.Run = function(){
console.log("我是外部定义的类方法,我叫" + this.name);
};
//原型方法
People.prototype.outside = function(){
console.log("我是外部定义的原型方法,我叫"+this.name);
};
//实例化类
var p = new People("fdh");
//调用对象方法
p.inside();//fdh
//调用原型方法
p.outside();//fdh
//调用类方法
People.Run();//People
JS 闭包
官方对闭包的解释是:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
闭包的特点:
- 作为一个函数变量的一个引用,当函数返回时,其处于激活状态。
- 一个闭包就是当一个函数返回时,一个没有释放资源的栈区。
简单的说,javascript
允许使用内部函数—-即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
function closure(){
var str = "I'm a part variable.";
return function(){
alert(str);
}
}
var fObj = closure();
fObj();
在上面代码中,str
是定义在函数 closure
中局部变量,若 str
在 closure
函数调用完成以后不能再被访问,则在函数执行完成后 str
将被释放。但是由于函数 closure
返回了一个内部函数,且这个返回的函数引用了 str
变量,导致了 str
可能会在 closure
函数执行完成以后还会被引用,所以 str
所占用的资源不会被回收。这样 closure
就形成了一个闭包。