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()
相关推荐
恋猫de小郭7 分钟前
AI Agent 开发究竟是啥?如何用 AI 开发 Agent ?深入浅出给你一套概念
android·前端·ai编程
前端双越老师10 分钟前
我开发 AI Agent 项目踩过的 5个坑
前端·agent·全栈
晓得迷路了31 分钟前
栗子前端技术周刊第 134 期 - React Router v8、TypeScript 7 RC、React Native 0.86...
前端·javascript·react.js
Carson带你学Android32 分钟前
Android 17 正式发布:AI 终于成了系统能力
android·前端·ai编程
Mike_jia44 分钟前
ZbxTable:Zabbix开源报表神器,从运维数据到决策洞察的最后一公里
前端
LinXunFeng10 小时前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
乘风gg14 小时前
为什么AI 时代来临,大部分人吃不到红利
前端·ai编程·claude
恋猫de小郭14 小时前
Android 限制侧载新进展,谷歌联合国内厂商推验证计划
android·前端·flutter
IT_陈寒14 小时前
Redis内存爆了,原来我漏掉了这个致命配置
前端·人工智能·后端
恋猫de小郭14 小时前
解读 Android 17 全新内存限制,有没有“豁免”后门?
android·前端·flutter