javascript 函数

函数的作用

  • 解决代码冗余问题,提高代码复用率
  • 实现代码的模块化
  • 封装代码,是函数内部代码对外部不可见

函数三要素

  • 函数名,最好使用动词,经常使用 getset 作为前缀
  • 参数,定义函数是括号内的为形参,调用函数时传递实参,形参一般是变量,实参是具体的值
  • 返回值,函数通常会通过 return 返回值作为函数调用表达式的值,若无 return 默认返回 undefined
  • 函数是否需要参数和返回值需要具体判断

函数的使用

字面量定义

1
2
3
funcation funcName (argument1, argument2) {
statement;
}

表达式定义

1
2
3
var funcName funcation (argument1, argument2) {
statement;
}

函数调用

1
2
3
4
5
funcName(value1, value2);                 //函数调用表达式

console.log(funcName(value1, value2)); //控制台直接输出返回值

var result = funcName(value1, value2); //使用变量存储返回值

函数实参伪数组

  • 每个函数内部都会有一个名为 arguments 的实参伪数组
  • 可以通过 arguments.length 获取参数个数,arguments[i] 获取第 i 个参数

函数作用域

  • 作用域表示变量起作用的范围,主要用来隔离变量(函数外部与函数内部的同名变量没有关系)
  • 通常情况函数外部是全局作用域,函数内部是局部作用域(函数作用域)
  • 全局作用域中的变量称为全局变量,局部作用域中的变量称为局部变量
  • 全局变量可以在函数内部操作,但局部变量无法在全局作用域中操作
  • 特殊情况 在函数内部的变量没有使用 var 关键字时:
    • 首先判断该变量是否是形参,是形参作为局部变量处理
    • 若该变量不是形参,判断全局作用域中有无该变量,有则直接操作全局变量
    • 若全局作用域中无该变量,则相当于在函数外部定义新的全局变量
  • 作用域在函数定义时就已经确定了

作用域链

  • 作用域链指的是变量通过一定的规则去查找,查找的过程称为作用域链:
    • 先从自己的作用域中查找,找不到则去上级作用域查找,找到该变量则不再继续查找
    • 若直到全局作用域都没有找到,则会报错(提示变量未定义)
  • 作用域链在函数调用时才会存在,每个执行环境都有自己独立的作用域链

预解析(变量提升)

  • 代码执行之前会进行预解析,域解析会解析所有包含 var 关键字的变量和函数:
  • 预解析时函数优先级比变量要高,先解析所有的函数,再解析变量:
    • 函数重名,后面的覆盖前面的
    • 变量重名,会忽略后面的变量
    • 字面量定义函数,整个函数被提升
    • 表达式定义函数,只提升变量(函数当做使用 var 关键字的变量)
    • 没有 var 关键字的变量不是进行预解析

立即调用函数表达式

1
2
3
(function() {
console.log("hello function!");
})();
  • IIFE 全称 Immediately Invoked Function Expression,中文立即调用函数表达式,别名匿名函数自调用表达式
  • 声明函数的同时会立即调用这个表达式,特点:
    • 函数只执行一次
    • 定义的同时执行
    • 函数不参与预解析,但函数内部会进行预解析
  • 作用:
    • 隐藏代码实现,只向外部暴露必要部分,封装插件可能用到
    • 防止外部命名空间被污染
    • 对项目进行初始化

函数的递归调用

  • 一个函数在内部又调用了自身称为函数的递归调用
  • 函数的递归调用比较消耗内存,使用时应该注意:
    • 必须有一个明显的结束条件
    • 必须有一个趋近结束条件的趋势

求阶乘

1
2
3
4
5
6
function getFactorial(n) {
if (n <= 1) {
return 1;
}
return n * arguments.callee(n - 1);
}

回调函数

  • 定义一个函数后,没有调用,但是函数却执行了,这种函数称为回调函数
  • 回调函数一般都是作为参数传递的
  • dom 事件多为回调函数