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()
相关推荐
子兮曰19 小时前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰19 小时前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
小羊没烦恼!19 小时前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
前端小万19 小时前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝19 小时前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋20 小时前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
伞伞悦读20 小时前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
卡布鲁21 小时前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
C语言小火车21 小时前
C/C++ 为什么需要编译器?
开发语言·c++
李少兄21 小时前
JavaScript 隐式全局变量解析
javascript