学习JavaScript函数

JavaScript中的函数

JavaScript中的函数使用function关键字,后跟一组参数以及函数体。例如:函数

function foo(arg0, arg1,...,arg) {
    ...
}

var foo = function () {
  ...
};

(function () {
  ...
})();
复制代码

JavaScript中有三种函数类型:函数声明,函数表达式和函数构造器建立的函数。下面分别介绍这三种函数类型。工具

函数声明

函数声明由一系列的function关键字组成,依次为:post

  • 有一个特定的名称
  • 函数参数列表,包围在括号中并由逗号分隔
  • 组成函数体的声明语句

例如:学习

function foo(arg0, arg1,...,arg) {
  var a = 1;
  console.log(a);
}
复制代码

函数表达式

函数表达式和函数声明很是类似,依次为:ui

  • 可选的名称(当省略函数名的时候,该函数就成为了匿名函数。)
  • 函数参数列表,包围在括号中并由逗号分隔
  • 组成函数体的声明语句

例如:spa

var foo = function () {
  var b = 2;
  console.log(b);
};

var foo = function bar() {
  var b = 2;
  console.log(b);
};

(function() {
    var c = 3;
    console.log(c);
})();
复制代码

Function构造函数

能够经过Function对象使用new操做符建立一个构造函数。例如:debug

new Function('alert('hello'); alert('world');');
复制代码

函数声明和函数表达式

这里重点学习函数声明和函数表达式。建立函数的最经常使用的两个方法是函数表达式和函数声明。调试

函数声明:code

function 函数名称 (参数:可选){ 函数体 }cdn

函数表达式:

function 函数名称(可选)(参数:可选){ 函数体 }

因此,建立一个函数若是不声明函数名称,它确定是表达式,可若是声明了函数名称的话,如何判断是函数声明仍是函数表达式呢?

区分函数声明和表达式最简单的方法是看 function 关键字出如今声明中的位 置(不单单是一行代码,而是整个声明中的位置)。若是 function 是声明中 的第一个词,那么就是一个函数声明,不然就是一个函数表达式。或者这么理解function foo(){}是做为赋值表达式的一部分的话,那它就是一个函数表达式,若是function foo(){}被包含在一个函数体内,或者位于程序的最顶部的话,那它就是一个函数声明。

例如:

function foo(){} // 声明,由于它是程序的一部分

var bar = function foo(){}; // 表达式,由于它是赋值表达式的一部分

new function bar(){}; // 表达式,由于它是new表达式

(function(){
    function bar(){} // 声明,由于它是函数体的一部分
})();

(function foo(){}); // 表达式 包含在分组操做符内
复制代码

匿名和具名函数

对于函数表达式,最熟悉的场景就是回调,例如:

setTimeout(function(){
    console.log("hello world!");
},1000);
复制代码

这是一个匿名函数表达式,在平常开发和工具库中这种模式很常见。可是它也有几个缺点须要考虑。

  1. 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难。
  2. 若是没有函数名,当函数须要引用自身时只能使用已通过期的arguments.callee引用, 好比在递归中。另外一个函数须要引用自身的例子,是在事件触发后事件监听器须要解绑 自身。
  3. 匿名函数省略了对于代码可读性/可理解性很重要的函数名。一个描述性的名称可让 代码不言自明。

例如:

具名函数

function foo(){
    return bar();
}
function bar(){
    return baz();
}
function baz(){
    debugger;
}
foo();  //当调试器debugger的调用栈,栈中显示了baz,bar,foo。
  
  
// 这是一个自执行的函数,函数内部执行自身,递归
function self() { 
    self(); 
}
复制代码

匿名函数

function foo(){
    return bar();
  }
var bar = (function(){
    return function(){
      return baz();
    };
})();
function baz(){
    debugger;
}
foo();//当调试器debugger的调用栈,栈中显示了baz,(anonymous),foo。


// 这是一个自执行的匿名函数,由于没有标示名称
// 必须使用arguments.callee属性来执行本身
var self = function () { 
    arguments.callee(); //在严格模式下,ES5禁止使用 arguments.callee()。
};
复制代码

给函数表达式指定一个函数名,不会影响其功能,反而是一个比较好的实现方式,例如:

setTimeout(function handle(){
    console.log("hello world!");
},1000);
复制代码

当即执行函数表达式

(function foo() { 
    var a = 1;
    console.log(1);
})();

(function () { /* code */ } ()); // 推荐使用这个

(function () { /* code */ })(); // 可是这个也是能够用的
复制代码

因为函数被包含在一对 ( ) 括号内部,所以成为了一个表达式,经过在末尾加上另一个 ( ) 能够当即执行这个函数,好比(function foo(){ .. })()。第一个 ( ) 将函数变成表 达式,第二个 ( ) 执行了这个函数。这种模式也叫当即执行函数表达式(IIFE)。

除了( ) 括号外,还有不少其余的方式也能让一个函数变成函数表达式,例如:

//&&,异或,逗号等操做符
true && function () { /* code */ } ();
1, function () { /* code */ } ();
//一元操做符号
!function () { /* code */ } ();
~function () { /* code */ } ();
-function () { /* code */ } ();
+function () { /* code */ } ();
复制代码

可是依然使用( ) 括号,括号内部原本指望的就是函数表达式,主要是为了方便开发人员阅读。

IIFE一些常见应用,例如:

  • 把它们看成函数调用并传递参数进去
var a = 1;
(function ( global ) {
    var a = 2;
    console.log( a ); // 2 
    console.log( global.a ); // 1
})( window );
console.log( a ); // 1

复制代码
  • 模块方法
var module = (function () {
    var i = 0;
    return {
        get: function () {
            return i;
        },
        set: function (val) {
            i = val;
        },
        add: function () {
            return ++i;
        }
    };
} ());
module.get(); // 0
module.set(1);
module.add(); // 1
module.i // undefined 由于i不是返回对象的属性
复制代码

结尾

这一节是对学习JavaScript做用域中的函数做用域的一个补充。这样把琐碎的知识串联起来,更容易造成体系。

相关文章
相关标签/搜索