函数声明语句
使用关键字 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 就形成了一个闭包。