1.8 函数

函数就是把一段代码打包成一个"工具包",起个名字,想用的时候喊一声就行。不用每次都从头写。

函数的核心价值:代码复用逻辑封装

1.8.1 定义和调用

function 关键字定义函数,用函数名() 调用函数。

定义语法function 函数名() { 函数体 }

调用语法函数名(); —— 不调用不执行!

演示:点击按钮调用函数

sayHello 函数

sayHello()
等待调用...

sayGoodbye 函数

sayGoodbye()
等待调用...

多次调用演示

click ×3
点击观察计数
1// 定义函数 2function sayHello() { 3 console.log('你好!欢迎学习JavaScript!'); 4} 5 6// 调用函数 7sayHello(); // 输出:你好!欢迎学习JavaScript! 8 9// 可以多次调用 10sayHello(); 11sayHello();

1.8.2 参数(形参和实参)

参数让函数更灵活——调用时传不同的值,函数就做出不同的反应。

形参(parameter):定义函数时写在括号里的"占位符"。

实参(argument):调用函数时传进去的"实际值"。

演示:输入姓名和年龄,调用函数
输入姓名和年龄后点击按钮
1// 定义:name 是形参 2function greet(name) { 3 console.log('你好,' + name + '!'); 4} 5 6// 调用:传不同的实参 7greet('小明'); // 输出:你好,小明! 8greet('小红'); // 输出:你好,小红! 9 10// 多个参数 11function introduce(name, age) { 12 console.log('我叫' + name + ',今年' + age + '岁'); 13} 14 15introduce('李四', 25); // 输出:我叫李四,今年25岁

1.8.3 返回值

函数处理完数据后,可以用 return 把结果"还回来"。

关键点return 会把值返回给调用者,同时函数立即结束

如果没有 return,函数默认返回 undefined

演示:add 函数的返回值

add(10, 20)

add(10, 20)
等待调用...

add(5, 7)

add(5, 7)
等待调用...

嵌套调用

add(add(1,2), add(3,4))
等待调用...
1// 定义一个加法函数 2function add(a, b) { 3 let result = a + b; 4 return result; // 把结果返回 5} 6 7// 调用函数,把返回值存起来 8let sum = add(10, 20); 9console.log('10 + 20 = ' + sum); // 输出:10 + 20 = 30 10 11// 返回值可以直接使用 12let total = add(add(1, 2), add(3, 4)); 13console.log(total); // 输出:10(3 + 7)

1.8.4 箭头函数(ES6 简写)

箭头函数是 ES6 提供的一种更简洁的函数写法

function 变成 =>,如果只有一行代码可以省略 {}return

三种写法对比
写法 代码 说明
传统 function function double(n) { return n * 2; } 标准写法
箭头函数(完整) let double = (n) => { return n * 2; }; function 换成 =>
箭头函数(简写) let double = (n) => n * 2; 单行省略 {} 和 return

传统写法 double1(5)

double1(5)
等待调用...

箭头函数 double2(5)

double2(5)
等待调用...

简写 double3(5)

double3(5)
等待调用...
1// 传统写法 2function double1(n) { 3 return n * 2; 4} 5 6// 箭头函数写法 7let double2 = (n) => { 8 return n * 2; 9}; 10 11// 最简写法(只有一行,省略{}和return) 12let double3 = (n) => n * 2; 13 14console.log(double1(5)); // 10 15console.log(double2(5)); // 10 16console.log(double3(5)); // 10

📋 函数核心要点

要点 说明
定义 function 函数名() {}
调用 函数名() —— 不调用不执行
形参 定义时写括号里,是占位符
实参 调用时传进去,是实际值
返回值 return 返回结果,函数立即结束
箭头函数 let fn = () => {},更简洁

1.9 数组 — 定义数组

数组就是一个有序的列表,可以把一堆数据排好队放在一起。好比一个购物清单。

中括号 [] 定义,元素之间用逗号分隔。

下标从 0 开始:第一个元素是 [0],最后一个是 [长度-1]

下标与元素对应关系
下标 [0]
苹果
下标 [1]
香蕉
下标 [2]
橘子
下标 [3]
西瓜

数组长度:fruits.length = 4  |  最后一个元素:fruits[fruits.length - 1]

1// 定义一个数组 2let fruits = ['苹果', '香蕉', '橘子', '西瓜']; 3 4console.log(fruits); // ["苹果", "香蕉", "橘子", "西瓜"] 5console.log(fruits.length); // 4(有4个元素) 6 7// 通过下标(索引)访问元素,下标从0开始 8console.log(fruits[0]); // 第一个元素:苹果 9console.log(fruits[1]); // 第二个元素:香蕉 10console.log(fruits[3]); // 第四个元素:西瓜 11console.log(fruits[4]); // 不存在的下标:undefined

1.9.2 遍历数组

遍历就是把数组里的元素一个个取出来。

for 循环 + .length 配合,可以逐个访问每个元素。

演示:for 循环遍历成绩数组
85
[0]
92
[1]
78
[2]
96
[3]
88
[4]
点击"开始遍历"查看过程
1let scores = [85, 92, 78, 96, 88]; 2let total = 0; 3 4// 遍历数组求和 5for (let i = 0; i < scores.length; i++) { 6 total += scores[i]; 7} 8 9let average = total / scores.length; 10console.log('总分:' + total); // 439 11console.log('平均分:' + average); // 87.8

1.9.3 常用方法

JavaScript 给数组准备了一些"工具方法",可以直接用。

交互演示:push / pop / unshift / shift
初始数组: [1, 2, 3]
方法速查表
方法 作用 示例 结果
push(值) 末尾添加 [1,2].push(3) [1,2,3]
pop() 末尾删除 [1,2,3].pop() [1,2]
unshift(值) 开头添加 [1,2].unshift(0) [0,1,2]
shift() 开头删除 [1,2,3].shift() [2,3]
indexOf(值) 查找位置 ['a','b'].indexOf('b') 1
concat(数组) 拼接数组 [1].concat([2]) [1,2]
join('分隔符') 转字符串 [1,2,3].join('-') "1-2-3"
1let arr = ['a', 'b', 'c']; 2 3// push:往末尾加 4arr.push('d'); 5console.log(arr); // ["a", "b", "c", "d"] 6 7// pop:从末尾删 8arr.pop(); 9console.log(arr); // ["a", "b", "c"] 10 11// unshift:往开头加 12arr.unshift('z'); 13console.log(arr); // ["z", "a", "b", "c"] 14 15// shift:从开头删 16arr.shift(); 17console.log(arr); // ["a", "b", "c"] 18 19// 查找元素位置 20let index = arr.indexOf('b'); 21console.log(index); // 1 22 23// 拼接数组 24let arr2 = [1, 2, 3]; 25let arr3 = [4, 5, 6]; 26let merged = arr2.concat(arr3); 27console.log(merged); // [1, 2, 3, 4, 5, 6]

1.10 对象 — 创建对象

对象就是一组相关数据的集合,每个数据都有一个名字(属性名)和一个值(属性值)。好比一张"个人信息表"。

花括号 {} 创建对象,里面是键值对(key: value)。

演示:person 对象的结构

👤 person 对象

name'小明'
age18
city'北京'
sayHellofunction() {...}
点击按钮调用方法
1// 创建一个"人"对象 2let person = { 3 name: '小明', // 属性:姓名 4 age: 18, // 属性:年龄 5 city: '北京', // 属性:城市 6 sayHello: function() { // 方法(对象里的函数) 7 console.log('你好,我叫' + this.name); 8 } 9}; 10 11// 访问属性:用 对象名.属性名 12console.log(person.name); // 小明 13console.log(person.age); // 18 14 15// 另一种访问方式:用 对象名['属性名'] 16console.log(person['name']); // 小明 17 18// 调用方法 19person.sayHello(); // 你好,我叫小明

1.10.2 属性与方法访问

访问对象属性有两种方式:点语法方括号

对象里的函数叫做方法,调用时必须加括号 ()

this 在对象方法里表示"这个对象自己"。

演示:product 对象的属性和方法

📦 product 商品对象

name'笔记本'
price29.9
quantity100
totalValue()this.price × this.quantity
info()打印商品信息
点击按钮调用方法

📝 访问方式对比

方式 语法 结果
点语法 person.name '小明'
方括号 person['name'] '小明'
方法(加括号) person.sayHello() 执行方法
方法(不加括号) person.sayHello 函数本身
1// 创建一个商品对象 2let product = { 3 name: '笔记本', 4 price: 29.9, 5 quantity: 100, 6 // 方法:计算总价值 7 totalValue: function() { 8 return this.price * this.quantity; 9 }, 10 // 方法:显示商品信息 11 info: function() { 12 console.log('商品:' + this.name + ',单价:' + this.price + '元'); 13 } 14}; 15 16// 调用方法 17let total = product.totalValue(); 18console.log('总价值:' + total + '元'); // 2990元 19 20product.info(); // 商品:笔记本,单价:29.9元,库存:100

1.11 作用域

作用域就是变量的"可视范围"——变量在哪些地方能被访问到,哪些地方不能。

简单说:函数内部声明的变量,外面用不了;函数外面声明的变量,里面都能用。

1.11.1 全局变量 vs 局部变量

全局变量:在函数外面声明的,整个页面都能用。

局部变量:在函数里面声明的,只有函数内部能用。

演示:全局与局部作用域

🌐 全局作用域

let globalVar = '我是全局变量'
整个页面任何地方都能访问

🔒 函数 testScope() 内部

let localVar = '我是局部变量'
只有函数内部能访问
变量类型 在哪里声明 在哪能访问
全局变量 所有函数外面 整个页面的任何地方
局部变量 函数内部 只有这个函数内部
1// 全局变量 2let globalVar = '我是全局变量'; 3 4function testScope() { 5 // 局部变量 6 let localVar = '我是局部变量'; 7 8 console.log(globalVar); // ✅ 函数内部能访问全局变量 9 console.log(localVar); // ✅ 函数内部能访问自己的局部变量 10} 11 12testScope(); 13 14console.log(globalVar); // ✅ 函数外面能访问全局变量 15// console.log(localVar); // ❌ 报错!函数外面访问不到局部变量

1.11.2 变量提升(var 的特殊行为)

变量提升是 var 的一个特点:用 var 声明的变量,会被"提升"到当前作用域的最顶部。

letconst 不会变量提升,使用前必须先声明。

var 变量提升过程

⚠️ var 的行为

console.log(a); // undefined
var a = 10;
console.log(a); // 10
声明被提升,赋值留在原地

✅ let 更安全

// console.log(b); // ❌ 报错!
let b = 20;
console.log(b); // 20
不会提升,声明前访问直接报错
1// var 的变量提升 2console.log(a); // undefined(不报错,因为变量被提升了) 3var a = 10; 4console.log(a); // 10 5 6// 实际过程相当于: 7var a; // 声明被提升到最前面 8console.log(a); // undefined(还没赋值) 9a = 10; // 赋值还在原地 10console.log(a); // 10 11 12// let 不会有变量提升 13// console.log(b); // ❌ 报错!let 不会提升 14let b = 20; 15console.log(b); // 20

1.11.3 作用域链

当你在函数内部访问一个变量时,JavaScript 会先在当前函数里找,找不到就去外层函数找,再找不到就去全局找——这条查找路径就是作用域链

查找规则:从里往外找,找到就停,找不到就报错。

作用域链可视化:从内向外逐层查找
🌐 全局作用域
let global = '全局变量'
📦 outer() 函数
let outerVar = '外部变量'
🔒 inner() 函数
let innerVar = '内部变量'
inner 找变量:
① 自己有 → 直接用
② 没有 → 去 outer 找
还没有 → 去全局找
点击按钮查看变量查找过程
1let global = '全局变量'; 2 3function outer() { 4 let outerVar = '外部变量'; 5 6 function inner() { 7 let innerVar = '内部变量'; 8 9 console.log(innerVar); // ✅ 当前函数有,直接取 10 console.log(outerVar); // ✅ 当前函数没有,去 outer 找 11 console.log(global); // ✅ 当前和 outer 都没有,去全局找 12 } 13 14 inner(); 15} 16 17outer();

📋 作用域核心要点

要点 说明
全局变量 函数外声明,全局可用
局部变量 函数内声明,仅函数内可用
变量提升 var 会把声明提到顶部,let/const 不会
作用域链 从内向外逐层查找变量,找到就停