【21】JavaScript (函数)

1 函数

1.1 什么是函数

  • 函数就是具有特定功能的代码块,可以被多次调用
  • 函数是 JavaScript 中的一种数据类型,属于对象类型; 使用 typeof 判断可以返回 function

1.2 函数的组成

  • 函数名: 函数名本质上是个变量,函数名的命名规则与变量名的命名规则一致。
  • 参数: 参数本质上是个变量,只能在函数内使用,在调用函数的时候才能被赋值。
  • 函数体: 用大括号包裹的代码块。
  • 返回值:返回值是函数的计算结果, 作为函数调用表达式的值

1.3 声明函数

① function 关键字方式

function 函数名() {
    函数体语句 ...;
}

function 函数名(参数列表...) {
    函数体语句 ...;
}

② 表达式方式

var 函数名 = function() {
    函数体语句 ...;
}

var 函数名 = function(参数列表...) {
    函数体语句 ...;
}

1.4 函数调用和返回值

① 函数调用

  • 函数名()才是函数调用,函数体语句才能执行,才能得到函数的返回值。
  • 函数名后面没有括号,就是在使用一个变量,函数体语句不会执行,也得不到函数的返回值。

② 返回值

1. 返回值是函数的计算结果,是函数调用表达式的值(函数名加括号就是函数调用表达式)
   var res = fn();    // 把函数的返回值赋值给变量 res
   fn() + 100;        // 函数的返回值与 100 相加
   console.log(fn()); // 输出函数的返回值

2. 通过 return 关键字定义函数的返回值
   return 需写在函数体内,return 右边需写一个表达式(变量、直接量、带运算符的表达式), 表达式的值就是函数的返回值。
   如果 return 右边是空的,函数没有返回值, 没有返回值函数调用表达式的值会自动得到 undefined

3. return 还可以结束函数的执行; 一旦执行到 return,后面的语句就不会执行了。

1.5 函数的参数

①形参和实参

形参:函数声明时设置的参数,相当于没有赋值的变量,必须以变量名的形式给出。

实参:调用函数时所给的参数,用于给形参赋值, 可以是变量、直接量、表达式等形式。

② 形参和实参的数量问题

标准情况下,形参和实参的数量应一致,按顺序赋值,如果:

形参数量 > 实参数量:后面的形参没有被赋值,自动得到 undefined。

形参数量 < 实参数量:多余的实参则没有用。

③ 形参的默认值(可选参数)

  1. 具有默认值的参数即可选参数
  2. 可选参数应放在必选参数的后面,因为实参按顺序给形参赋值,不给实参则可以返回默认值。

ES5 规范中设置默认值的方式:

function fn(name, age) {
    // 如果 age 没有对应的实参, 设置一个默认值
    if (age === undefined) {
        age = 默认值;
    }
}

ES6 规范中的设置默认值的方式:

funciton fn(name, age=默认值) {
    
}

④ arguments关键字

  1. arguments 是系统定义好的变量,可以直接使用,但只能在函数内使用, 在函数外使用则会报错。
  2. arguments 是个伪数组对象,里面的成员是函数调用时传进来的实参; arguments 具有length 属性,可以通过索引获取到其中的每个成员。
  3. arguments 是除了形参之外另外一种获取实参的方式。 形参只能获取固定数量的实参,arguments 可以获取所有的实参。
  4. 使用 arguments 可以定义可变参数数量的函数。
// 计算所有参数的和,返回结果
function sumFn() {
    // 定义变量 记录和
    var sum = 0;
    // 遍历 arguments
    for (var i = 0; i < arguments.length; i ++) {
        sum += arguments[i];
    }
    // 返回结果
    return sum;
}

1.6 作用域

① 变量的作用域

作用域即变量的可作用范围,根据作用域不同,变量可分为全局变量局部变量

全局变量: 在函数以外定义,作用域是全局。如:函数外声明的函数,函数内没有用var声明的变量。

局部变量: 在函数内定义,作用域是所在的函数。如:函数的形参,函数内声明的函数。

  1. 函数名本质上是变量,所以函数本身也有作用域,由函数是在哪里声明的决定。
  2. 如果在函数里不使用var声明变量,该变量是全局的(严格模式下不允许不使用var声明的变量的)

② 作用域链

函数里还可以继续声明函数,函数的嵌套关系形成了作用域链,函数内可以使用本层作用域和上层作用域中的变量。

作用域链描述变量查找的过程:

当使用某个变量的时候,先从本作用域中查找,如果找不到就去上层作用域查找,哪里找到哪里停止,找不到则继续向上查找,直到全局作用域,如果仍然没有查找到该变量,则报错。

注:变量的作用域只与函数声明的位置有关系,与函数在哪里调用无关。

1.7 变量提升

① 变量提升

  1. 代码正式执行之前,会进行预解析,预解析时会把变量提升到本作用域的最前面(只创建了变量,却没有赋值)
  2. 全局变量在整个代码正式执行之前就发生了提升
  3. 局部变量在函数体语句执行之前进行提升

② 函数提升

  1. 函数名本质上就是变量,所以函数也会提升到本作用域的最前面。
  2. 使用 function 关键字形式声明的函数,提升比较彻底,代码执行之前不但创建了函数名并且有值。
  3. 使用表达式方式声明的函数,提升规则与普通变量没有差别。
  4. 函数提升与变量提升的区别:
    ① 函数提升更彻底
    ② 正式执行代码的时候,执行到变量声明并赋值的语句会进行赋值操作, 执行到函数声明语句会跳过

1.8 匿名函数

即没有名字的函数,用函数这种数据类型的直接量表示,适合作为自调用函数回调函数

1.9 自调用函数(立即执行的函数)

函数声明完立即被调用,主要作用是用来产生作用域,避免全局变量污染。一般以匿名函数作为自调用函数,有名字的函数也可以作为自调用函数,但没有必要。

// 匿名的自调用函数(立即执行的函数)
(function() {
    函数体语句;
})();

// 有名字的自调用函数
(function fn() {
    函数体语句;
})();

// 匿名的自调用函数 设置参数
(function(形参1, 形参2) {
    函数体语句;
})(实参1, 实参2);

1.10 回调函数

具有以下三个条件的函数称为回调函数:

  • ① 函数是我定义的
  • ② 我没有直接调用该函数
  • ③ 函数却执行了

注意: 回调函数大部分情况会作为其他函数(或方法)的参数。

1.11 递归函数

函数内部再次调用自己。

① 递归成功的条件:

  • 有明确的结束递归的条件
  • 有一个趋向于结束递归调用的趋势

② 递归函数的缺点

  • 可能发生内存泄漏
  • 效率不高

③ 递归函数应用场景

  • 后端的目录操作(删除、复制、剪切)
  • 前端对后端数据进行递归处理
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容