目录
[1. 作用域的基本概念](#1. 作用域的基本概念)
[2. 作用域链](#2. 作用域链)
一、函数的基本语法与调用机制
在 JavaScript 中,函数是第一类公民,其核心语法如下:
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {
函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
关键特性:
-
函数定义并不会执行函数体内容,必须调用才会执行,调用几次就执行几次。
-
调用函数时进入函数内部执行,函数结束时回到调用位置继续执行,可借助调试器观察。
-
函数的定义和调用顺序没有要求(这一点和变量不同,变量必须先定义再使用)。
示例代码:
function hello() {
console.log("hello");
}
// 如果不调用函数,则没有执行打印语句
hello();
动态语言特性:
JS 是一个动态语言,支持灵活的函数操作。
二、关于参数个数的匹配规则
实参和形参之间的个数可以不匹配,但实际开发一般要求形参和实参个数要匹配:
-
如果实参个数比形参个数多,则多出的参数不参与函数运算:
sum(10, 20, 30); // 30
-
如果实参个数比形参个数少,则此时多出来的形参值为
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去掉
注:如果在函数内使用let或var定义变量,则是局部变量;若不使用关键字,则变成全局变量(不推荐)。
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()