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()
相关推荐
Cao_Ron8 分钟前
用 SVG image symbol 画 ECharts graph 圆形节点
前端
hxy060113 分钟前
React-Call让你的React组件像异步函数一样调用
前端·react.js
Hilaku14 分钟前
为什么 AI 写前端时,总是优先选择 React,而不是 Vue?
前端·javascript·程序员
京东云开发者16 分钟前
GPT-5.6、ChatGPT Work 与 Codex 更新食用指南
前端
Cao_Ron27 分钟前
用 ECharts graph 画出卡片式矩形节点
前端
skiyee35 分钟前
换个底座的 Wot Starter 居然让 AI 更懂项目!
前端·ai编程
anyup42 分钟前
这一套绝了!AI 大模型写故事,星云 SDK 驱动 3D 数字人实时演绎
前端·人工智能·aigc
耀耀切克闹灬1 小时前
短链跳转
前端
孟陬1 小时前
高质量全方位的 AI 工具 sse-stuntman — Mock SSE 接口
前端·node.js·openai
Cao_Ron1 小时前
给 ECharts 6 graph 节点叠加角标:从原理到性能优化
前端