15.JavaScript 函数与作用域完全指南:语法、参数、表达式与作用域链实战

目录

一、函数的基本语法与调用机制

二、关于参数个数的匹配规则

三、函数表达式

四、作用域与作用域链

[1. 作用域的基本概念](#1. 作用域的基本概念)

[2. 作用域链](#2. 作用域链)


一、函数的基本语法与调用机制

在 JavaScript 中,函数是第一类公民,其核心语法如下:

复制代码
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
    函数体
    return 返回值;
}

// 函数调用
函数名(实参列表)        // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值

关键特性:

  • 函数定义并不会执行函数体内容,必须调用才会执行,调用几次就执行几次。

  • 调用函数时进入函数内部执行,函数结束时回到调用位置继续执行,可借助调试器观察。

  • 函数的定义和调用顺序没有要求(这一点和变量不同,变量必须先定义再使用)。

示例代码:

复制代码
function hello() {
    console.log("hello");
}
// 如果不调用函数,则没有执行打印语句
hello();

动态语言特性:

JS 是一个动态语言,支持灵活的函数操作。


二、关于参数个数的匹配规则

实参和形参之间的个数可以不匹配,但实际开发一般要求形参和实参个数要匹配:

  1. 如果实参个数比形参个数多,则多出的参数不参与函数运算:

    sum(10, 20, 30); // 30

  2. 如果实参个数比形参个数少,则此时多出来的形参值为 undefined

    sum(10); // NaN,相当于 num2 为 undefined

**注意:**​ JS 的函数传参比较灵活,这一点和其他语言差别较大,事实上这种灵活性往往不是好事。

完整示例:

html 复制代码
<script>
    // 定义的没有参数列表,也没有返回值的一个函数
    function hello() {
        console.log("hello")
    }
    // 定义一个有参数列表,有返回值的一个函数
    function HelloXiaobite(num, name) {
        console.log(num + "Hello" + name)
        return 1;
    }

    let b = hello()
    console.log(typeof(b))
    let a = HelloXiaobite(1, "小明")
    console.log(typeof(a))

    // 实参个数比形参个数少
    HelloXiaobite();
    HelloXiaobite(1, "小明", 3)
</script>

三、函数表达式

除了函数声明,JS 还支持函数表达式,这是另一种函数定义方式:

html 复制代码
var add = function() {
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i];
    }
    return sum;
}
console.log(add(10, 20));        // 30
console.log(add(1, 2, 3, 4));    // 10
console.log(typeof add);         // function

此时形如 function() { }的写法定义了一个匿名函数,然后将这个匿名函数用一个变量来表示,后面就可以通过这个 add变量来调用函数了。

JS 中函数是一等公民,可以用变量保存,也可以作为其他函数的参数或者返回值。

命名函数表达式示例:

html 复制代码
let result = function Sum() {
    // 计算1~100之间的和
    ret = 0
    for(i = 0; i <= 100; i++) {
        ret += i
    }
    return ret
}
console.log(result())

也可以写成下方的匿名函数:

html 复制代码
let b = function() {
    console.log(arguments)
}
b();            
b(1, 2, 3)

四、作用域与作用域链

1. 作用域的基本概念

**作用域:**​ 某个标识符名字在代码中的有效范围。

在 ES6 标准之前,作用域主要分成两个:

  • 全局作用域:在整个 script 标签中,或者单独的 js 文件中生效。

  • 局部作用域/函数作用域:在函数内部生效。

示例:

html 复制代码
<script>
    let num = 10;
    function test01() {
        let num = 100;
        console.log(num)
    }
    function test02() {
        let num = 200;
        console.log(num)
    }
    console.log(num)
    test01()
    test02()
    for(let i = 1; i <= 100; i++) {
    }
    console.log(i)
    // 在JS中,如果定义一个变量不使用let、var此时这个变量就变成一个全局变量
</script>

上面这个代码会报错,处理方法就是把for循环里面的let去掉
注:如果在函数内使用 letvar定义变量,则是局部变量;若不使用关键字,则变成全局变量(不推荐)。


2. 作用域链

背景:

  • 函数可以定义在函数内部。

  • 内层函数可以访问外层函数的局部变量。

  • 内部函数可以访问外部函数,外部函数可以访问全局变量,依次进行查找。

作用域链示例 1:

html 复制代码
let num = 10
function test01() {
    let num = 100
    // 100
    console.log(num)
    function test02() {
        let num = 200
        // 200
        console.log(num)
    }
    test02()
}
test01()

作用域链示例 2(注释说明):

复制代码
let num = 10
function test01() {
    let num = 100
    // 100
    console.log(num)
    function test02() {
        // let num = 200
        // 200
        // 100
        console.log(num)
    }
    test02()
}
test01()

作用域链示例 3(更深嵌套):

html 复制代码
let num = 10
function test01() {
    // let num = 100
    // 100
    console.log(num)//10
    function test02() {
        // let num = 200
        // 200
        // 100
        console.log(num)//10
    }
    test02()
}
test01()
相关推荐
.千余1 小时前
【C++】C++类与对象2:C++构造函数、运算符重载与流输入输出全面解析
c语言·开发语言·前端·c++·经验分享
郭涤生1 小时前
C++ 高性能状态机
开发语言·c++
一念&1 小时前
油猴脚本教程——元数据块
javascript·浏览器·脚本·油猴
SOC罗三炮1 小时前
OpenHuman 源码深度解构:一个 Rust 驱动的本地优先 AI 个人助手
开发语言·人工智能·rust
心怀梦想的咸鱼2 小时前
OpenCode 接入 API 报错 read ECONNRESET:基于环境变量的证书校验绕过方案
开发语言·php
星栈2 小时前
Rust 单二进制部署,真没你想的那么“单”
前端·后端
angerdream2 小时前
Android手把手编写儿童手机远程监控App之webrtc聊天数据通道
前端
程序大视界2 小时前
【Python系列课程】Python入门教程
开发语言·人工智能·python
浩风祭月2 小时前
受够了每次切分支都要重装依赖:一份 Git 工作流优化指南
前端·ai编程