JS函数与自定义对象

JS函数与自定义对象

2026年9月29日·#编程学习/javaweb学习笔记JavaWeb/JavaScript/前端·5317 字 27 分钟
浏览量加载中...
AI 摘要- DeepSeek

JS 函数用 function 定义(具名、函数表达式、箭头函数三种写法),自定义对象用字面量描述一个东西;再加上 JSON 互转与数组常用方法

封面图
JS函数与自定义对象 - 封面图

14 篇把变量、类型、运算符、流程控制讲完了——代码会写,但都是”一次性”的:同样的逻辑要用第二次就得复制一遍。这一篇补上两个”打包”的工具:函数把代码打包成可复用的块,自定义对象把相关的数据和方法打包成一个整体。最后再补上对象在网络上的形态 JSON、以及数组常用方法——它们是下一步 DOM 操作和后面 Vue、Ajax 的地基。

函数:把代码块打包复用#

介绍:函数(function)是被设计用来执行特定任务的代码块,方便程序的封装复用。

定义语法:

function functionName(参数1, 参数2 ...){
//要执行的代码
}

调用语法:函数名称(实际参数列表)

课程代码 04. JS-函数.html 的具名函数:

//1. 函数定义及调用 - 具名函数
function add(a, b){
return a + b; // return 返回结果
}
let result = add(10,20); // 调用函数,实参是 10 和 20
console.log(result); // 30

写代码时把定义放在调用前面(课程代码就是这么排的),读起来最清楚。

Important

由于 JS 是弱类型语言,形参、返回值都不需要指定类型——function add(a, b) 里不写 a、b 是什么类型,也不写返回什么类型(Java 要写成 int add(int a, int b))。另外:调用函数时,实参个数与形参个数可以不一致,但是建议一致。

实参个数不一致会发生什么(课程代码注释里没展开,这里补上):

function add(a, b){
return a + b;
}
console.log(add(10)); // NaN —— b 是 undefined,10 + undefined 得不到数字
console.log(add(10, 20, 30)); // 30 —— 多出来的 30 被忽略
Warning

“实参个数可以不一致”是 JS 的灵活之处,也是 bug 的高发区:少传一个参数,函数照样执行,只是默默算出一个 NaN(或 undefined),不会报错。写代码时老老实实保证个数一致,让问题暴露在调用处。

匿名函数:函数表达式与箭头函数#

匿名函数是指一种没有名称的函数,可以通过两种方式定义:函数表达式 和 箭头函数。

//2.1 函数表达式:把一个没有名字的函数赋给变量
let add = function(a, b){
return a + b;
}
//2.2 箭头函数:=> 代替 function
let add = (a, b) => {
return a + b;
}
// 匿名函数定义后,可以通过变量名直接调用
let result = add(100, 200);
console.log(result); // 300

(上面两段来自课程 04. JS-函数.html:函数表达式演示的是 add(100,200),箭头函数演示的是 add(1000,2000);两者选一个用即可。)

Tip

为什么叫”匿名”?function 后面没有名字,函数本身被赋给了变量 add,所以调用时要写 add(...)(用变量名,不是原来的 functionName)。两种写法的区别:函数表达式内还是熟悉的 function;箭头函数用 => 把参数和函数体连起来,写起来更短——这也是后面写事件监听时最常用的写法(如 addEventListener('click', () => { ... }))。

箭头函数还有一个”极简形态”(了解):只有一个表达式时,{} 和 return 都能省掉——

// 完整写法
let add = (a, b) => {
return a + b;
}
// 简写:只有一个表达式,省略 {} 和 return(结果会被自动返回)
let add2 = (a, b) => a + b;

自定义对象:把”一个东西”打包#

定义格式:let 对象名 = { 属性名1: 属性值1, 属性名2: 属性值2, 属性名3: 属性值3, 方法名: function (形参列表) {} }

课程代码 05. JS-自定义对象.html 用一个大括号描述了”一个人”:

//1. 自定义对象
let user = {
name: 'Tom',
age: 18,
gender: '男',
sing: function(){
alert(this.name + '悠悠的唱着最炫的民族风~')
}
}

对象的方法还有一种简写——把 : function 去掉,直接写 方法名(){}:

let user = {
name: 'Tom',
age: 18,
gender: '男',
sing(){
alert(this.name + '悠悠的唱着最炫的民族风~')
}
}

调用格式(PPT 的两行总结):

// 对象名.属性名;
// 对象名.方法名();
alert(user.name); // Tom
user.sing(); // 弹出:Tom悠悠的唱着最炫的民族风~

前面用过的 console.log(user.name)、user.sing() 都是这个套路:点号(.)就是”取这个对象身上的东西”。

方法里的 this#

方法里要拿”当前对象自己”的属性,用 this——上面 sing() 里的 this.name 就是 user.name。

Warning

课程代码里专门演示了一种错误写法:定义对象中的方法时,尽量不要使用箭头函数(this)。

let user = {
name: 'Tom',
age: 18,
gender: '男',
sing: () => { //注意: 在箭头函数中, this并不指向当前对象 - 指向的是当前对象的父级 【不推荐】
alert(this + ':悠悠的唱着最炫的民族风~')
}
}

箭头函数的 this 不指向”调用它的对象”,而是指向外层(父级)作用域——在我们这种顶层写法里就是 window(浏览器窗口对象),所以弹出来的是 [object Window] 而不是 Tom。给对象写方法,用 方法名(){} 或 方法名: function(){},不写箭头函数。

JSON:对象在网络上的形态#

概念:JavaScript Object Notation,JavaScript 对象标记法(JS 对象标记法书写的文本)。

由于其语法简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输。

把”JS 对象”和”JSON 文本”摆在一起就能看出区别:

// JS 对象:属性名可以不加引号,字符串可以用单引号,还能带方法
let person = {
name: 'Tom',
age: 20,
gender: '男'
}
{
"name": "Tom",
"age": 20,
"gender": "男"
}

JSON 格式特点:json 格式的文本所有的 key 必须使用双引号引起来("name" 不能写成 name 或 'name')。

对象和 JSON 之间的转换靠两个方法(PPT 的两问两答):

方法作用
JSON.parse(..)将 json 字符串转为 js 对象
JSON.stringify(..)将 js 对象转为 json 字符串

课程代码 05. JS-自定义对象.html 的最后一段:

//3. JSON - JS对象标记法
let person = {
name: 'itcast',
age: 18,
gender: '男'
}
alert(JSON.stringify(person)); //js对象 --> json字符串
let personJson = '{"name": "heima", "age": 18}';
alert(JSON.parse(personJson).name); // heima —— 先转成对象,再取 name

浏览器里弹出来的第一句是:

{"name":"itcast","age":18,"gender":"男"}

为什么要有这一步? PPT 用一张”请求/响应”的图说明了数据的流向:

步骤数据形态
浏览器里的 JS 对象{ name: "Tom", age: 20, gender: "男" }
发请求前用 JSON.stringify(..) 转成文本{"name":"Tom","age":20,"gender":"男"}
网络传输(请求 / 响应)JSON 文本(纯字符串,任何语言都能解析)
收到响应用 JSON.parse(..) 转回对象又是 JS 对象,可以 对象.属性名 取值
Tip

记住这个方向感:stringify 是”对象 → 文本”(准备发出去),parse 是”文本 → 对象”(收进来用)。后面学 Ajax / Vue 时,从后端拿到的响应就是一个 JSON 文本,第一步永远是 JSON.parse(或让 Axios 自动转)。

补充:数组常用方法#

数组是 JS 里最常用的”容器”(14 篇的对照表里提过:Java 的数组长度固定,JS 的数组长度可变)。用中括号定义、元素用逗号隔开:

let arr = [10, 20, 30, 'JS', true]; // 元素类型可以混搭(弱类型)
console.log(arr.length); // 5 —— 长度
console.log(arr[0]); // 10 —— 索引从 0 开始
console.log(arr[4]); // true
方法作用
push(元素)在末尾添加一个或多个元素,返回新长度
pop()删除并返回末尾的元素
unshift(元素)在开头添加元素
shift()删除并返回开头的元素
splice(开始索引, 删除个数, 新增元素…)从中间删除 / 插入元素(会改变原数组)
slice(开始, 结束)截取一段,返回新数组(不改原数组)
join(分隔符)把数组元素拼成字符串
concat(数组)拼接数组,返回新数组
indexOf(元素)返回元素第一次出现的索引,找不到返回 -1
includes(元素)判断是否包含某元素,返回 true / false
forEach(函数)遍历每个元素(类似 for 循环)
map(函数)遍历并加工每个元素,返回新数组
filter(函数)筛选符合条件的元素,返回新数组
let arr = [10, 20, 30];
arr.push(40); // 末尾加:arr 变成 [10, 20, 30, 40]
arr.pop(); // 末尾删:arr 又变回 [10, 20, 30]
arr.splice(1, 0, 15); // 在索引 1 处插入 15:arr 变成 [10, 15, 20, 30]
console.log(arr.join('-')); // 10-15-20-30(拼成字符串)
console.log(arr.includes(20)); // true
// 遍历:箭头函数在这里最常见
arr.forEach(item => {
console.log(item);
});

数组里放对象是最常用的组合(“多条数据”就是这样存的,后面的员工列表案例全靠它):

let users = [
{ name: 'Tom', age: 18 },
{ name: 'Jerry', age: 20 }
];
console.log(users.length); // 2
console.log(users[0].name); // Tom —— 先按索引取出对象,再 .属性名取属性
for (let i = 0; i < users.length; i++) {
console.log(users[i].name); // 依次打印 Tom、Jerry
}
Important

遍历数组最标准、最不容易出错的写法是 for (let i = 0; i < arr.length; i++)——课程后面的员工列表案例里遍历数据行用的就是它(for (let i = 0; i < trList.length; i++))。forEach()、map()、filter() 属于进阶写法,认识即可,后面写 Vue 时会大量出现。

小结#

问题答案
函数是什么?被设计用来执行特定任务的代码块,方便程序的封装复用;用 function 定义,用 函数名称(实际参数) 调用
函数要写类型吗?不用——JS 是弱类型,形参、返回值都不需要指定类型;实参个数与形参个数可以不一致(建议一致)
匿名函数怎么写?函数表达式 let add = function(a,b){...}、箭头函数 let add = (a,b) => {...};定义后通过变量名调用
自定义对象的格式?let 对象 = {属性名: 属性值, 方法名: function(){}},方法可简写成 方法名(){}
怎么访问对象成员?对象名.属性名、对象名.方法名();方法内用 this.属性名 取自己的属性
对象方法能用箭头函数吗?不要——箭头函数的 this 指向外层(window),拿不到对象自己的属性
JSON 是什么?JavaScript Object Notation(JS 对象标记法),是文本,用作数据载体在网络中传输;key 必须用双引号
两个 JSON 方法?JSON.stringify(对象) 对象 → json 字符串;JSON.parse(字符串) json 字符串 → 对象
数组怎么定义、怎么取元素?let arr = [10, 20, 30];arr[0] 按索引取(从 0 开始)、arr.length 拿长度
数组常用方法?push() 末尾加、pop() 末尾删、splice() 中间删/插、join() 拼字符串、forEach() 遍历

相关#

练习题#

一、知识回顾(读完直接做下面的实践题)#

  1. 函数(function) 是被设计用来执行特定任务的代码块,方便程序的封装复用;定义用 function 关键字,调用写 函数名称(实际参数列表)
  2. 因为 JS 是弱类型语言,定义函数时形参、返回值都不需要指定类型;调用时实参个数与形参个数可以不一致(但建议一致)——少传参数会默默算出 NaN,多传的会被忽略,都不报错
  3. 匿名函数(没有名称的函数)有两种定义方式:函数表达式 let add = function(a,b){...} 和 箭头函数 let add = (a,b) => {...};定义后通过变量名调用(add(10,20))
  4. 箭头函数只有一个表达式时,可以省略 {} 和 return(如 let add = (a,b) => a + b;);后面写事件监听(如 addEventListener('click', () => {...}))最常用它
  5. 自定义对象格式:let 对象名 = { 属性名1: 属性值1, 属性名2: 属性值2, 方法名: function (形参列表) {} };方法还能简写成 方法名(){}
  6. 调用格式:对象名.属性名、对象名.方法名();方法内部用 this 取当前对象自己的属性(this.name)
  7. 对象方法里不要用箭头函数:箭头函数的 this 不指向当前对象,而是指向外层(父级)——顶层写法里就是 window,拿不到属性
  8. JSON 全称 JavaScript Object Notation(JavaScript 对象标记法),是文本,语法简单、层次结构鲜明,多用于作为数据载体在网络中传输;格式特点是所有的 key 必须用双引号引起来(不能带方法、不能用单引号)
  9. JSON.stringify(js对象) 把 js 对象转为 json 字符串;JSON.parse(json字符串) 把 json 字符串转为 js 对象
  10. 数组用 [ ] 定义、索引从 0 开始、数组.length 取长度;常用方法:push() 末尾加、pop() 末尾删、splice() 中间删/插、join() 拼成字符串、includes() 判断包含、forEach() 遍历;数组里放对象就是”多条数据”的存法

二、裸写题#

  • 2-1 写一个具名函数做加法 定义一个函数:接收两个参数,返回它们的和。调用它计算 10 + 20,把结果打印到控制台。 做完想一想:这个函数在 Java 里要写成什么样?多了哪两种类型声明? (练习文件 test_15_具名函数.html 里已经给了骨架和写作区。)

    提示(先自己想,实在想不出再点开)

    一级 · 思路:函数 = 名字 + 参数 + 返回值;“返回”是把结果交回给调用方,还需要一个地方把结果打印出来 二级 · 方法:定义用 function 函数名(参数){ return ...; };调用写 函数名(10, 20);打印用 console.log() 三级 · 骨架:function add(____, ____){ return ____ + ____; } / let result = add(10, 20); / console.log(____);

    参考答案(做完再点开)
    // 定义函数:求两个数的和
    function add(a, b){
    return a + b;
    }
    // 调用函数并打印结果
    let result = add(10, 20);
    console.log(result); // 30

    对照课程 04. JS-函数.html 的第一段。Java 版本要写成 int add(int a, int b){ return a + b; }——多出的两个 int 就是因为 JS 是弱类型,形参和返回值都不用写类型。

  • 2-2 用箭头函数重写一边加法,再故意少传一个参数 分两步:

    1. 用箭头函数(匿名函数的一种)实现同样的加法,把 100 和 200 传进去、打印结果
    2. 再调用一次这个函数,只传一个参数,看看打印出来是什么——解释一下为什么不是报错 (练习文件 test_15_箭头函数.html 里已经给了写作区。)
    提示(先自己想,实在想不出再点开)

    一级 · 思路:匿名函数没有名字,要把它”存”在变量里才能调用;箭头函数用 => 连接参数和函数体 二级 · 方法:let 变量名 = (参数) => { return ...; };调用用变量名;打印用 console.log() 三级 · 骨架:let add = (a, b) => { return ____ + ____; } / let result = ____(100, 200); / 再调用一次 add(____) 观察结果

    参考答案(做完再点开)
    // 箭头函数:匿名函数赋给变量 add
    let add = (a, b) => {
    return a + b;
    }
    let result = add(100, 200);
    console.log(result); // 300
    // 少传一个参数:b 是 undefined
    console.log(add(100)); // NaN —— 100 + undefined 得不到数字,但不报错

    对照课程 04. JS-函数.html 的第 2 部分(函数表达式与箭头函数二选一)。第 2 步说明:JS 里实参个数与形参个数可以不一致,缺的形参是 undefined,参与算术运算就变成 NaN(Not a Number)——这正是弱类型语言”灵活但容易埋 bug”的地方。

  • 2-3 定义一个员工对象并打印它的属性 定义一个对象表示一名员工:姓名 Tom、年龄 18、性别 男,另外给它一个”自我介绍”的方法(打印一句带上自己名字的话)。 然后:打印这个对象的姓名和年龄,再调用它的自我介绍方法。 (练习文件 test_15_自定义对象.html 里已经给了写作区。)

    提示(先自己想,实在想不出再点开)

    一级 · 思路:对象用一对大括号装”属性名: 属性值”;方法就是”值是函数的属性”;取值用点号 二级 · 方法:let user = { name: 'Tom', age: 18, gender: '男', intro(){ ... } };取值 user.name、调用 user.intro();方法里用 this.name 拿自己的名字;打印用 console.log() 三级 · 骨架:let emp = { name: '____', age: ____, gender: '____', intro(){ console.log('我是' + ____.name); } } / console.log(emp.____); / emp.____();

    参考答案(做完再点开)
    // 定义员工对象
    let emp = {
    name: 'Tom',
    age: 18,
    gender: '男',
    // 方法:打印一句自我介绍
    intro(){
    console.log('我是' + this.name + ',今年' + this.age + '岁');
    }
    }
    // 访问属性
    console.log(emp.name); // Tom
    console.log(emp.age); // 18
    // 调用方法
    emp.intro(); // 我是Tom,今年18岁

    对照课程 05. JS-自定义对象.html 的第一段(课程里方法名是 sing,用 alert 弹出 this.name + '悠悠的唱着最炫的民族风~')。注意:方法不要写成箭头函数——箭头函数的 this 指向 window,this.name 就取不到 Tom 了。

  • 2-4 写一个函数判断成绩等级 定义一个函数:接收一个分数,返回对应的等级文字——90 及以上返回 优秀、80 及以上返回 良好、60 及以上返回 及格、其余返回 不及格。 调用它分别在 95、85、72、50 四个分数上测试,把返回的等级打印出来。 (练习文件 test_15_成绩等级.html 里已经给了写作区。)

    提示(先自己想,实在想不出再点开)

    一级 · 思路:函数里做”多重条件判断”,每个分支把等级返回出去(不是打印);测试时循环几个分数调用它 二级 · 方法:function 函数名(分数){ if (… >= 90) { return '优秀'; } else if (…) { … } };打印用 console.log() 三级 · 骨架:function level(score){ if (score >= 90) { return '____'; } else if (score >= 80) { return '良好'; } else if (score >= ____) { return '及格'; } else { return '不及格'; } } / console.log(level(95));

    参考答案(做完再点开)
    // 判断成绩等级
    function level(score){
    if (score >= 90) {
    return '优秀';
    } else if (score >= 80) {
    return '良好';
    } else if (score >= 60) {
    return '及格';
    } else {
    return '不及格';
    }
    }
    // 测试四个分数
    console.log(level(95)); // 优秀
    console.log(level(85)); // 良好
    console.log(level(72)); // 及格
    console.log(level(50)); // 不及格

    三个检查点:① 判断顺序必须从高到低——score >= 60 若写在最前面,95 分也会被判成”及格”;② 每个分支用 return 把结果交回去,函数里不打印;③ return 执行后函数立刻结束,后面的 else if 不会再判断。

三、综合题#

  • 3-1 用”对象 + 数组 + 函数 + JSON”做一份员工列表数据 不碰页面(DOM 以后再学),先在控制台里把”多条数据”处理明白:

    1. 用对象描述 3 名员工,每人四个属性:姓名、年龄、性别、职位(自己编数据)
    2. 把这 3 个对象放进一个数组
    3. 写一个函数 describe(emp):接收一个员工对象,返回一句话(如 Tom,18岁,男,讲师)——用模板字符串拼
    4. 遍历这个数组,对每个员工调用 describe,把结果打印出来
    5. 打印这个数组的长度
    6. 最后把整个数组转成 JSON 字符串打印出来(模拟发给服务器的数据),再把这段 JSON 字符串转回对象,取出第一个员工的姓名打印 (练习文件 test_15_综合_员工列表.html 里已经给了写作区。)
    提示(先自己想,实在想不出再点开)

    一级 · 思路:第 12 步是”对象装数据、数组装对象”;第 34 步是”函数加工 + 循环遍历”;第 6 步是对象与 JSON 文本之间的两个互转方法 二级 · 方法:数组 let emps = [ {…}, {…} ];函数 function describe(emp){ return …; };遍历 for (let i = 0; i < emps.length; i++);长度 emps.length;互转 JSON.stringify(emps)、JSON.parse(字符串) 三级 · 骨架:let emps = [ { name: '____', age: 18, gender: '男', position: '____' }, … ]; / function describe(emp){ return emp.name,{emp.name},{emp.____}岁,…; } / for (let i = 0; i < emps.____; i++) { console.log(describe(____[i])); } / let json = JSON.stringify(____); / let obj = JSON.parse(____); console.log(obj[0].____);

    参考答案(做完再点开)
    //1. 用对象描述员工,放进数组(多条数据)
    let emps = [
    { name: 'Tom', age: 18, gender: '男', position: '讲师' },
    { name: 'Jerry', age: 20, gender: '女', position: '班主任' },
    { name: 'Lucy', age: 22, gender: '女', position: '学工主管' }
    ];
    //2. 写一个函数:接收员工对象,返回一句描述
    function describe(emp){
    return `${emp.name},${emp.age}岁,${emp.gender},${emp.position}`;
    }
    //3. 遍历数组,逐个打印描述
    for (let i = 0; i < emps.length; i++) {
    console.log(describe(emps[i]));
    }
    //4. 数组长度
    console.log(emps.length); // 3
    //5. 对象数组 → JSON 字符串(准备发给服务器)
    let json = JSON.stringify(emps);
    console.log(json); // [{"name":"Tom","age":18,...}, ...]
    //6. JSON 字符串 → 对象,再取值
    let obj = JSON.parse(json);
    console.log(obj[0].name); // Tom

    三个检查点:① describe(emp) 里用 emp.name 取的是传进来的那个对象,不能写成固定的名字;② 模板字符串的引号是反引号,${} 里放的是表达式(emp.age);③ 第 5 步打印出的 JSON 里所有 key 都是双引号的文本——它就是”网络传输时数据的样子”,第 6 步的 JSON.parse 是它的逆向操作。

评论区

[ 标签 ]
# AI37# AI 编程2# AI工具1# AI绘图1# AI辅助开发2# Ajax7# Apifox1# AstrBot3# Astro2# CC Switch1# CDN2# Claude Code1# claudecode2# ClaudeCode1# Cloudflare2# CloudFlare2# CloudFlare-ImgBed3# coc4# CSS10# DeepSeek6# deepseek2# DELETE1# Docker5# EdgeOne3# Gist1# git1# GitHub1# hexo-circle-of-friends1# HTML9# HTTP10# ImageManager1# Java23# java13# JavaScript11# JavaWeb113# JDBC7# JSON2# JUnit1# LangChain25# Linux4# Logback1# Maven17# Muse Spark1# Mybatis1# MyBatis18# MySQL45# MySql1# NapCat1# Node.js1# obsidian2# Obsidian5# OpenCode4# ORM1# PathVariable1# PicGo1# PyCharm1# Python70# RequestBody1# RequestMapping1# RESTful风格1# skills1# Slf4j1# SpringBoot37# SpringMVC5# SQL2# Streamlit5# Svelte2# TailwindCSS1# Telegram3# Tlias2# Vercel1# vscode2# Vue20# Waline3# Web3# WebDAV1# Web基础6# Web开发6# WinSCP1# YAML1# 三层架构1# 中二宣言1# 书籍1# 使用文档10# 写作1# 函数2# 刷步数1# 前端52# 动态1# 动漫1# 包1# 单词2# 博客8# 博客工作流1# 博客开发2# 参数接收1# 友链1# 反思2# 后端48# 图床6# 地图1# 备份2# 大模型1# 奇思妙想1# 存储1# 学习方法6# 学校1# 宝塔面板3# 宝宝10# 实战4# 对象1# 导航栏1# 工具2# 布局2# 开发1# 开发工具1# 开发规范1# 开心1# 异常处理1# 影视2# 微信1# 性能优化2# 总结1# 想法15# 感受1# 感悟11# 指南1# 提示词工程2# 插件5# 故障排除1# 效率工具2# 教程10# 数据分析9# 数据库27# 数据结构1# 文件操作2# 斩神1# 日常95# 日志框架1# 朋友圈1# 朱元璋1# 模块1# 模板1# 正则表达式2# 测试3# 游戏2# 爬虫7# 生活迁移1# 电影2# 电脑1# 碎碎念1# 视觉识别1# 类1# 类型注解1# 网络基础2# 网络教室1# 羊毛2# 脚本2# 脚本工具1# 自动化2# 蓝奏云1# 表单1# 订阅推荐2# 记录2# 评论系统1# 词根1# 词缀1# 说说1# 足迹1# 跑步2# 路径参数1# 转载2# 运动1# 部署11# 部落冲突1# 配置1# 随机图1# 面向对象5# 音乐3# 音标1# 项目实战11# 饮食1# 驼峰命名1# 高德地图1
[ 公告 ]

如果你喜欢,那么欢迎来到我的世界!

了解更多
[ 音乐 ]
封面

音乐

暂未播放

0:000:00
暂无歌词
找不到相关结果。
[ contents ]
[ 全部文章 ]