函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用

5.1 声明函数

  • 函数对任何语言来说都是核心组件,因为它们可以封装语句,然后在任何地方、任何时间执行。ECMAScript 中的函数使用 function关键字声明,此关键词小写,后跟一组参数,然后是函数体。
  • 函数的命名应该有意义,即能通过函数名来了解此函数的作用
    1. function functionName(arg0, arg1,...,argN) {
    2. statements
    3. }
    4. function 函数名(形参0, 形参1,...,形参N) {
    5. //函数内部代码
    6. }

5.2 调用函数

函数在声明后可以进行调用,调用没有次数限制,但先后顺序会影响结果

函数名(实参,实参);   //函数调用时通过函数名来使用
  • 调用函数时不要忘记后面的()
  • 函数需要通过调用来执行
  • 函数内部声明的变量为局部变量,在函数外部无法使用,需要通过return来返回结果给函数带到全局环境下。

5.3 形参和实参

  • 形参:是函数在构建声明时模拟带入的变量,不做声明,也没有任何实意
  • 实参:字面意义,在调用函数时,带入函数内部的参数变量,通常在外部声明
    //构建函数
    function 函数名(形参,形参){
    函数内部代码
    }
    //调用函数
    函数名(实参,实参)
    

函数形参和实参数量不匹配时

图片4.png

5.4 函数返回值 (return)

函数尽量不要在内部进行输出,尤其在进行多个函数参与情况下,建议函数只需返回运算结果

function 函数名(形参,形参){
函数运算;
return 返回给函数的值
}
  • 在使用 return 语句时,函数会停止执行,并返回指定的值
  • 如果函数没有 return ,返回的值是 undefined

    function sum(num1,num2){
      return num1+num2;   //将两个数的和返回给函数
    console.log(num1);  //return 后面的函数内部代码不会被执行
    }
    
  • return只能返回一个值,如果填写多个值,只会返回最后一个逗号后面的值

  • 如果需要返回多个值,可以使用数组的进行多个值的返回
  • 也可以通过对象(object)来返回多个值

break、continue、return的区别

  • break :结束当前的循环体(如 for、while)
  • continue :跳出本次循环,继续执行下次循环(如 for、while)
  • return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码

5.5 arguments

当不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参,arguments将用户输入的参数以数组的方式存储起来,在使用时用arguments[]的方式来使用。

function doAdd() { 
 if (arguments.length === 1) { 
 console.log(arguments[0] + 10); 
 } else if (arguments.length === 2) { 
 console.log(arguments[0] + arguments[1]); 
 } 
} 
doAdd(10); // 20 
doAdd(30, 20); // 50

arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:

  • 具有 length 属性
  • 按索引方式储存数据
  • 不具有数 组的 push , pop 等方法

arguments可以配合形参使用:

function doAdd(num1, num2) { 
 if (arguments.length === 1) { 
 console.log(num1 + 10); 
 } else if (arguments.length === 2) { 
 console.log(arguments[0] + num2); 
 } 
}

arguments 对象的另一个有意思的地方就是,它的值始终会与对应的命名参数同步。来看下面的例子:

function doAdd(num1, num2) { 
 arguments[1] = 10; 
 console.log(arguments[0] + num2); 
}
  • 这个 doAdd()函数把第二个参数的值重写为 10。因为 arguments 对象的值会自动同步到对应的命名参数,所以修改 arguments[1]也会修改 num2 的值,因此两者的值都是 10。
  • 但这并不意味着它们都访问同一个内存地址,它们在内存中还是分开的,只不过会保持同步而已。
  • 另外还要记住一点:如果只传了一个参数,然后把 arguments[1]设置为某个值,那么这个值并不会反映到第二个命名参数。这是因为 arguments 对象的长度是根据传入的参数个数,而非定义函数时给出的命名参数个数确定的。
  • 对于命名参数而言,如果调用函数时没有传这个参数,那么它的值就是 undefined。这就类似于定义了变量而没有初始化。比如,如果只给 doAdd()传了一个参数,那么 num2 的值就是 undefined。

注意:在函数内部使用该对象,用此对象获取函数调用时传的实参。

5.6 函数可以进行多次的嵌套

函数内部可以调用另一个函数,在同一作用域代码中,函数名即代表封装的操作,使用函数名加括号即可以将封装的操作执行。

5.7 函数的两种声明方式

事实上,JavaScript 引擎在加载数据时对它们是区别对待的。JavaScript 引擎在任何代码执行之前,会先读取函数声明,并在执行上下文中生成函数定义。而函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义。
来看下面的例子:

// 没问题 
console.log(sum(10, 10)); 
function sum(num1, num2) { 
 return num1 + num2; 
}

以上代码可以正常运行,因为函数声明会在任何代码执行之前先被读取并添加到执行上下文。这个过程叫作函数声明提升(function declaration hoisting)。

在执行代码时,JavaScript 引擎会先执行一遍扫描,把发现的函数声明提升到源代码树的顶部。因此即使函数定义出现在调用它们的代码之后,引擎也会把函数声明提升到顶部。如果把前面代码中的函数声明改为等价的函数表达式,那么执行的时候就会出错:

// 会出错
console.log(sum(10, 10)); 
let sum = function(num1, num2) { 
 return num1 + num2; 
};

上面的代码之所以会出错,是因为这个函数定义包含在一个变量初始化语句中,而不是函数声明中。这意味着代码如果没有执行到这一行,那么执行上下文中就没有函数的定义,所以上面的代码会出错。这并不是因为使用 let 而导致的,使用 var 关键字也会碰到同样的问题:

console.log(sum(10, 10)); 
var sum = function(num1, num2) { 
 return num1 + num2; 
};