# 函数声明与调用

# 什么是函数?

函数:将完成某一特定功能的代码封装起来,并且可以重复调用的代码块。

为何使用函数?

  1. 能够对代码进行复用:只要定义一次代码,就可以多次使用它。
  • 能够多次向同一函数传递不同的参数,以产生不同的结果。
  • 使程序更加简洁、具有逻辑性、维护方便

# 函数声明方式

# function关键字

function 函数名([参数1],[参数2],...[参数n]){
    函数体
    [retrun]  //返回值
}

# 字面量定义(匿名函数)

var 变量 = function ([参数1],[参数2]....){
    函数体
    [retrun]  //返回值
}

# 实例化构造函数

var 变量 = new Function([参数1],[参数2]...,"函数体");

# 函数调用方式

# 通过括号调用

用于具名函数的调用

  • 函数名()
  • 变量名()
function fun1(){}
fun1()

var fun2 = function (){}
fun2()

# 自调用(IIFE)

用于匿名函数的调用,匿名函数还可以通引用变量来调用。

//第一种
(function (){})()

//第二种
!function(){

}()

//第三种
(function(){

}())

注意: 在进行函数自调用时,上一条语句必须结尾有;

# 通过事件调用

<script>
    function fun(){}
</script>
<div onclick="fun()"></div>

# 注意事项

创建/调用函数注意问题:

  1. 如果两个函数的命名相同,后面的将会覆盖前面的函数。
  2. 以function声明的函数可以前置调用,以字面量方式声明方式后置调用。
  3. 在不同的<script></script>块中声明函数,声明之后块中调用。

# 问题1:函数声明覆盖

如果两个函数的命名相同,后面的将会覆盖前面的函数。

function bb(){
    alert("这是第一个声明");
}
function bb(){
    alert("这是第二个声明");
}
bb(); //结果为  “这是第二个声明

# 问题2:函数调用顺序

以基本语法声明的函数,会在页面载入的时候提前解析到内存中,以便调用。所以可以在函数的前面调用。但是以字面量形式命名的函数,会在执行到他的时候,才进行赋值。所以只能在函数的后面调用。

aa();      // 结果为 弹出 1
function aa(){
    alert(1)
}
aa();      // 结果为 弹出 1
aa();      // 报错 aa is not a function
var aa = function(){
    alert(1)
}
aa();

# 问题3:函数在不同块调用顺序

在不同的<script></script>块中,因为浏览器解析的时候是分块解析的,所以前面的块不能调用后面块的函数,所以在不同的块之间调用函数的时候,应该先定义后调用。

<script>
    aa();      //报错
</script>
<script>
    function aa(){
        alert(1)
    }
</script>
<script>
    aa()       //结果为 弹出 1
</script>

# 箭头函数 ES6

ES6标准新增了一种新的函数:Arrow Function(箭头函数)

# 箭头函数语法

箭头函数表达式的语法比普通函数表达式更简洁。

(参数1, 参数2,, 参数N) => { 函数声明 }

(参数1, 参数2,, 参数N) => 表达式(单一)
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

当只有一个参数时,圆括号是可选的:

(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号:

() => {函数声明}

# 没有局部this的绑定

TIP

和一般的函数不同,箭头函数不会绑定this。 或者说箭头函数不会改变this本来的绑定。它没有自己的this对象,内部的this就是定义时上层作用域中的this。也就是说,箭头函数内部的this指向是固定的,相比之下,普通函数的this指向是可变的。

# 箭头函数需要注意的点

  • 箭头函数没有自己的this对象。
  • 不可以当作构造函数,也就是说,不可以对箭头函数使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

# 不适用场合

由于箭头函数使得this从“动态”变成“静态”,下面两个场合不应该使用箭头函数。

  • 第一个场合是定义对象的方法,且该方法内部包括this。
const cat = {
  lives: 9,
  jumps: () => {
    this.lives--;
  }
}

上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。