1、什么是构造函数?
构造函数(Constructor)的本身其实就是我们常用的函数,传入一个或者多个参数,处理出我们想要的一个结果;而用于创建和初始化对象的函数,就称之为构造函数(Constructor);常见的就是当我们使用“new”关键字去实例化一个函数的时候,此时,这个函数就被称为构造函数。
// 这就是一个是函数
function MyWorld(name, grade, figure) {
this.userId = {
name: name,
grade: grade,
figure: figure
}
// this.userId = {name, grade, figure}
}
// 此时,被调用实例化的函数就称之为构造函数
const myworld = new MyWorld('史蒂芬', '0', '形象1')
构造函数其实就是函数,只是和普通函数用的地方不一样,所以换了个名字便于区分而已。
注意:构造函数内使用this来初始化值是因为this的指向在new实例化后会指向新创建的对象,对this指向不熟悉的可以回顾一下 《点击这里》。
1.1、这就是构造函数
构造函数(Constructor)是JavaScript中用于创建和初始化对象的特殊函数,作为对象的模版,定义了对象的初始化状态和基本结构,当使用“new”关键字调用构造函数时,它会创建一个新的对象实例。
1.2、构造函数的三大核心特征
1. 命名约定:通常以大写字母开头(区别于普通函数)。
2. 使用 this 关键字:在函数内部使用 this 设置实例属性。
3. 配合 new 操作符:通过 new 关键字创建实例。
1.3、构造函数的工作原理
当使用 new 调用构造函数时,JavaScript 引擎会执行以下步骤:
1. 创建新对象:在内存中创建一个新的空对象 { }。
2. 设置原型链:将新对象的原型(__proto__)指向构造函数的 prototype 属性。
3. 绑定 this:将构造函数中的 this 绑定到这个新对象。
4. 执行构造函数:运行构造函数内部的代码(初始化对象)。
5. 返回对象:自动返回新创建的对象(除非显式返回其它对象)。
1.4、构造函数和普通函数的对比
| 特性 | 构造函数 | 普通函数 |
|---|---|---|
| 调用方式 | 必须使用 new 关键字 | 直接调用 |
| 命名约定 | 首字母大写 | 首字母小写 |
| 返回值 | 隐式返回新对象(this) | 显示返回值或 undefined |
| this 指向 | 指向新创建的实例 | 取决于调用上下文 |
| 用途 | 创建对象实例 | 执行特定任务 |
2、什么是实例?
在面向对象编程中,实例是指通过类(Class)或者构造函数(Constructor)创建的具体对象,每个实例都是根据 类 / 构造函数 的基础信息创建出来的独立的实体,拥有自己的属性和方法。
// 类
class MyWorld {
constructor(name, grade, figure) {
this.name = name
this.grade = grade
this.figure = figure
}
// 实例方法
SpaceJump(key) {
if (key === 'Space' || key === ' ') {
console.log(`${this.name}触发了跳跃`)
}
}
// 静态方法
static EnterChat(key) {
if (key === 'Enter') {
console.log('触发了聊天')
}
}
}
const myworld1 = new MyWorld('史蒂芬', '0', '形象1')
const myworld2 = new MyWorld('我不叫菜只因', '0', '自定义形象')
// 这里的 myworld1 和 myworld2 是两个独立的实体
myworld1 和 myworld2 是两个独立的实体,以下是输出:

再比如一些常见的实例:
// DOM元素实例,每个DOM元素都是 HTMLElement的实例
const button = document.createElement("button")
console.log(button instanceof HTMLElement) // true
button.textContent = "Click me"
// 日期对象,Date对象的实例标识特定时间点
const now = new Date()
const birthday = new Date("2000-5-29")
console.log(now.getFullYear()) // 当前年份
console.log(birthday.getDay()) // 生日是周几
1.1、实例的核心要点
1. 具体对象:实例是根据类 / 构造函数创建的具体对象。
2. 独立状态:每个实例有自己独立的属性值。
3. 共享行为:同类实例共享方法(通过原型)
4. 创建方式:使用 new 关键字创建。
5. 面向对象基础:实例是实现封转、继承和多态的基础。
3、什么是原型对象,以及三者的关系(原型对象、构造函数和实例)
原型对象(Prototype)是JavaScript实现继承和共享属性的核心机制。每个JavaScript对象(除 ‘null’ 外)在创建时都会关联另一个对象,这个关联对象就是原型对象。当访问对象的属性时,如果对象自身没有该属性,JavaScript会沿着原型链向上查找,直到找到该属性或到达原型链末端。
下面的代码中详细描述了原型对象(prototype)、构造函数(constructor)和实例之间的关系。
// 类
class MyWorld {
constructor(name, grade, figure) {
this.name = name
this.grade = grade
this.figure = figure
}
// 实例方法
SpaceJump(key) {
if (key === 'Space' || key === ' ') {
console.log(`${this.name}触发了跳跃`)
}
}
// 静态方法
static EnterChat(key) {
if ('key' === 'Enter') {
console.log('触发了聊天')
}
}
}
MyWorld.prototype.c_Squat = function() {
console.log(`${this.name}触发了蹲下`)
}
const myworld1 = new MyWorld('史蒂芬', '0', '形象1')
const myworld2 = new MyWorld('我不叫菜只因', '0', '自定义形象')
console.log(myworld1, myworld1.__proto__, MyWorld.prototype)
console.log(myworld1.__proto__.constructor, MyWorld.prototype.constructor, MyWorld)
console.log(myworld1.__proto__.constructor === MyWorld.prototype.constructor)
console.log(MyWorld.prototype.constructor === MyWorld)
console.log(myworld1.__proto__.constructor === MyWorld)
console.log(myworld1, myworld2)
以下是运行结果,便于对比熟悉:

4、原型对象的四大特性
4.1、原型链继承机制
1. 对象通过 __proto__ 属性连接原型(现代代码应使用 Object.getPrototypeOf())。
2. 属性查找路径:对象自身 → 原型 → 原型的原型 → ... ... → null。
3. 原型链的终点:Object.prototype.__proto__ === null。

4.2、构造函数与原型
1. 每个函数都有 prototype 属性(指向原型对象)。
2. 原型对象自动获得 constructor 属性(指向构造函数)。
3. 实例通过 __proto__ 连接构造函数的原型。
4.3、共享属性与方法
1. 定义在原型上的方法被所有实例共享。
2. 避免每个实例重复创建方法,节省内存。

4.4、动态修改
1. 原型修改立即影响所有实例。
2. 即使实例在修改前已创建。
4.5、原型操作的三类方法
1. 原型访问
const obj = {
name: 'obj',
id: 1
}
const newProto = {
name: 'newProto',
id: 2
}
// 获取原型(推荐)
const proto = Object.getPrototypeOf(obj)
// 设置原型(谨慎使用)
Object.setPrototypeOf(obj, newProto)
// 非标准历史方法(避免使用)
console.log('obj', obj)
console.log('obj.__proto__', obj.__proto__)
输出结果

2. 属性检测
// 检查对象自身属性
obj.hasOwnProperty('name') // true
// 检查整个原型链
'toString' in obj // true
// 获取所有属性(包括原型链)
Object.keys(obj) // 自身可枚举属性
Object.getOwnPropertyNames(obj) // 自身所有属性
输出结果

3. 原型创建
// 基于现有原型创建
const newObj = Object.create(obj)
// 纯字典对象(无原型)
const pureDict = Object.create(null)
pureDict.toString // undefined
输出结果

4.6、原型继承的三种模式
1. 经典继承(组合继承)
function Parent(name) {
this.name = name
}
Parent.prototype.sayName = function() {
console.log(this.name)
}
function Child(name, age) {
Parent.call(this, name) // 继承属性
this.age = age
}
// 继承方法
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child // 修复constructor
// 添加子类方法
Child.prototype.sayAge = function() {
console.log(this.age)
};
console.log('Parent', Parent.prototype)
console.log('Child', Child.prototype)
输出结果

2. 原型式继承(Object.create)
const personProto = {
introduce() {
return `I'm ${this.name}, ${this.age} years old`;
}
};
const john = Object.create(personProto);
john.name = "John";
john.age = 30;
console.log('john', john)
输出结果

3. ES6类继承(语法糖)
class Vehicle {
constructor(wheels) {
this.wheels = wheels;
}
info() {
return `Has ${this.wheels} wheels`;
}
}
class Car extends Vehicle {
constructor(model) {
super(4); // 调用父类构造
this.model = model;
}
// 方法覆盖
info() {
return `${this.model}: ${super.info()}`;
}
}
const vehicle = new Vehicle('这是Vehicle')
const car = new Car('这是Car')
console.log('vehicle', vehicle)
console.log('vehicle.info()', vehicle.info())
console.log('car', car)
console.log('car.info()', car.info())
输出结果

4.7、原型系统的六大关键点
1. 所有对象都有原型(除了 Object.create(null) 创建的对象)
2. 函数也是对象,因此函数也有原型
function foo() {}
console.log(Object.getPrototypeOf(foo) === Function.prototype); // true
3. 内置构造函数的原型
Array.prototype.__proto__ === Object.prototype // true
Function.prototype.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true
4. 原型与性能:过长的原型链会影响查找性能
5. 原型污染:修改内置原型可能引发意外行为
// 危险操作!
Array.prototype.push = function() {
console.log("Array push modified!");
};
6. 现代替代方案:ES6类语法是原型的语法糖,更易理解
4.8、原型对象总结表
| 特性 | 描述 |
|---|---|
| 本质 | 实现继承和属性共享机制 |
| 核心关系 | 构造函数 ⇄ 原型对象 ⇄ 实例 |
| 关键属性 | prototype(函数),__proto__(实例),constructor(原型) |
| 内存优势 | 共享方法节省内存 |
| 动态性 | 修改原型立即影响所有实例 |
| 终点 | Object.prototype 的原型是 null |
| 最佳实践 | 方法放在原型上,属性放在构造函数中 |
理解原型对象是掌握 JavaScript 核心的关键,它揭示了 JavaScript 不同于传统类继承语言的独特继承模型——基于原型的继承。随着 ES6 类的普及,虽然语法更接近传统面向对象编程,但底层仍然基于原型系统。
439






