第三章 JavaScript基础
第四节 函数与对象
概述
本节内容重点讲解JavaScript中的函数与对象,这是JavaScript编程的核心组成部分。函数不仅是执行代码的基本单位,也是实现代码复用和模块化的关键机制;对象则是JavaScript中存储和组织数据的主要方式。通过本节的学习,考生将掌握函数的定义、调用、参数传递、闭包及对象的创建、属性操作、内置对象使用等核心知识,为后续Web程序设计打下坚实基础。
核心概念
- 函数(Function):封装执行任务的代码块,可以接收参数并返回结果。
- 函数声明与函数表达式:两种定义函数的方式,声明有提升,表达式不提升。
- 参数与返回值:函数可以接收输入参数,执行逻辑处理并返回结果。
- 闭包(Closure):函数和声明该函数的词法环境的组合,能够访问外部函数作用域中的变量。
- 对象(Object):键值对的集合,是JavaScript中最重要的数据结构。
- 属性(Property):对象中的键值对,其中键是字符串,值可以是任意数据类型。
- 方法(Method):对象中的函数属性。
- 原型(Prototype):对象的继承属性,支持原型链机制。
原理分析
JavaScript函数是第一类对象,可以像变量一样传递和操作;函数的执行环境形成作用域链,支持闭包实现数据的私有化和持久化。对象是动态的,属性可以随时增删;通过原型链实现继承,节省内存并实现共享方法。函数与对象结合,形成JavaScript编程的灵活基础。
详细内容
1. 函数的定义与调用
JavaScript中定义函数的主要方式有两种:
- 函数声明
function add(a, b) {
return a + b;
}
函数声明会被提升(hoisting),可以在声明之前调用。
- 函数表达式
const multiply = function(a, b) {
return a * b;
};
函数表达式不会被提升,必须在定义后调用。
函数调用时,可以传入参数,若未传则参数为undefined。函数内部使用return语句返回值,若无返回值则返回undefined。
2. 函数参数与默认值
ES6支持函数参数默认值,避免参数未传导致错误:
function greet(name = 'Guest') {
console.log('Hello, ' + name);
}
函数的arguments对象是类数组结构,包含所有传入参数。注意:箭头函数没有arguments对象。
3. 作用域与闭包
函数内部可以访问外部作用域变量,形成闭包:
function outer() {
let count = 0;
return function inner() {
count++;
return count;
};
}
const counter = outer();
console.log(counter()); // 1
console.log(counter()); // 2
闭包能保存函数执行时的环境变量,常用于数据封装和私有变量实现。
4. 对象的创建
创建对象有多种方式:
- 对象字面量
const person = {
name: 'Alice',
age: 25,
greet: function() {
console.log('Hello, ' + this.name);
}
};
- 构造函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log('Hi, ' + this.name);
};
const p = new Person('Bob', 30);
- Object.create
const proto = { greet() { console.log('Hello'); } };
const obj = Object.create(proto);
5. 对象属性操作
通过点.或方括号[]访问和修改属性:
person.name = 'Tom';
person['age'] = 40;
使用delete删除属性:
delete person.age;
属性可以是数据属性或访问器属性(getter/setter),支持定义属性特性(可枚举、可配置、可写)。
6. 方法与this关键字
对象的方法中,this指向调用该方法的对象。注意不同调用场景下this的指向变化:
- 对象方法调用,
this指向该对象 - 普通函数调用,
this指向全局对象(非严格模式)或undefined(严格模式) - 构造函数中,
this指向新创建的实例 - 箭头函数没有自己的
this,继承外层作用域的this
7. 原型与继承
所有对象都有一个内部属性[[Prototype]],通过__proto__访问。构造函数的prototype属性定义了实例的原型。
原型链实现继承,查找对象属性时会沿原型链向上查找。可以通过Object.create或构造函数+prototype实现继承。
实例分析
实例1:实现计数器闭包
function createCounter() {
let count = 0;
return {
increment() { count++; return count; },
decrement() { count--; return count; },
getCount() { return count; }
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.getCount()); // 2
分析:通过闭包将变量count封装,外部无法直接访问,只能通过提供的方法操作,保证了数据安全。
实例2:构造函数与原型方法
function Car(brand, year) {
this.brand = brand;
this.year = year;
}
Car.prototype.getInfo = function() {
return this.brand + ' - ' + this.year;
};
const myCar = new Car('Toyota', 2020);
console.log(myCar.getInfo()); // Toyota - 2020
分析:构造函数创建对象实例,方法定义在原型上,实现方法共享,节省内存。
实例3:对象属性操作与getter/setter
const user = {
firstName: 'Jane',
lastName: 'Doe',
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName(name) {
const parts = name.split(' ');
this.firstName = parts[0];
this.lastName = parts[1];
}
};
console.log(user.fullName); // Jane Doe
user.fullName = 'John Smith';
console.log(user.firstName); // John
分析:通过访问器属性实现对对象属性的动态计算和赋值,提升封装性。
常见误区
混淆函数声明和函数表达式的提升机制
- 错误:在函数表达式定义前调用函数导致报错。
- 正确:函数表达式必须先定义后调用。
忽略闭包导致内存泄漏或变量共享错误
- 错误:循环中直接使用闭包变量,所有闭包共享同一变量。
- 正确:使用立即执行函数或
let声明块级变量。
误用this导致方法调用出错
- 错误:将对象方法赋值给变量再调用,导致
this丢失。 - 正确:使用
bind绑定正确的this,或通过对象调用方法。
- 错误:将对象方法赋值给变量再调用,导致
直接修改对象原型导致不可预知行为
- 错误:随意重写原型对象,破坏继承链。
- 正确:通过
Object.create或谨慎扩展原型。
误解属性访问器getter/setter的调用方式
- 错误:getter/setter像普通方法一样调用。
- 正确:直接访问属性触发getter/setter。
应用场景
- 模块化编程:使用函数封装代码,利用闭包隐藏私有变量,提高代码复用性与安全性。
- 面向对象设计:通过构造函数和原型实现对象创建和方法共享,模拟类和继承。
- 事件处理:函数作为回调处理事件,闭包保存执行上下文。
- 数据封装与访问控制:利用getter/setter实现对对象属性的动态控制和验证。
- 动态网页交互:对象保存页面元素状态,函数响应用户操作。
知识拓展
- 箭头函数与传统函数的区别:箭头函数没有自己的
this,适合处理回调函数。 - 函数式编程思想:函数作为一等公民,支持高阶函数、纯函数和不可变数据。
- ES6类语法:基于函数和原型的语法糖,更直观地实现面向对象。
- 对象的深拷贝与浅拷贝:理解对象复制的内存机制,避免引用类型陷阱。
- Proxy和Reflect:ES6新增元编程工具,拦截和定义对象行为。
总结回顾
本节详细讲解了JavaScript中函数与对象的基础与进阶内容。函数是代码执行的基本单位,支持参数传递、返回值、作用域和闭包,能够实现灵活的代码结构和数据封装。对象是键值对集合,是存储和组织数据的核心形式,通过属性和方法实现功能。原型链机制支撑了JavaScript的继承设计,理解它对于面向对象编程至关重要。掌握函数与对象的定义、调用、作用域、闭包、属性访问、原型继承等知识点,将为Web程序设计和开发提供坚实的技术保障。