【JavaScript】day26-prototype-inheritance

作者:mario 发布时间: 2026-08-26 阅读量:2 评论数:0

第二十六天:原型与继承 — JS 的对象"基因"

蜗牛往上爬 · 前端工业可视化学习笔记 第 26 篇
JS 没有传统语言的 class 继承(ES6 的 class 也是原型链的语法糖),它的继承靠"原型链"实现。今天学构造函数、prototype、原型链,理解 JS 对象最核心的机制——这是面试必考,也是理解 ES6 class 的前提。


目录


一、为什么需要构造函数

用工厂函数创建对象有个问题:每个实例都会复制一份方法,浪费内存。

// ❌ 工厂函数:每个对象都有一份 check 方法
function createDevice(id, name) {
  return {
    id: id,
    name: name,
    check: function () { return this.id + " 正常"; }
  };
}

var d1 = createDevice("CNC-001", "数控机床");
var d2 = createDevice("AGV-002", "搬运机器人");
console.log(d1.check === d2.check);  // false!两份不同的函数

1000 台设备就有 1000 份 check 函数。构造函数 + 原型能解决这个问题:方法只存一份,大家共享。


二、构造函数 + new

// 构造函数:普通函数,约定首字母大写
function Device(id, name) {
  this.id = id;
  this.name = name;
  this.status = "离线";
}

// 用 new 调用
var d1 = new Device("CNC-001", "数控机床");
var d2 = new Device("AGV-002", "搬运机器人");

console.log(d1.id);    // "CNC-001"
console.log(d1 instanceof Device);  // true

new 做了 4 件事

1. 创建空对象 {}
2. 空对象的原型 → 指向构造函数的 prototype
3. this → 指向空对象,执行构造函数体
4. 返回这个对象

三、prototype 原型对象

方法放在 prototype 上,所有实例共享同一份:

Device.prototype.check = function () {
  if (this.status === "离线") return this.id + " 已离线";
  return this.id + " 运行正常";
};

Device.prototype.start = function () {
  this.status = "运行中";
  return this.id + " 已启动";
};

var d1 = new Device("CNC-001", "数控机床");
var d2 = new Device("AGV-002", "搬运机器人");

// ✅ 两个实例共享同一个方法
console.log(d1.check === d2.check);  // true!

// 属性在实例上,方法在原型上
console.log(d1.hasOwnProperty("id"));     // true(实例自己的)
console.log(d1.hasOwnProperty("check"));  // false(原型上的)

分工

  • 属性(id/name/status)→ 放构造函数里(每个实例一份)

  • 方法(check/start)→ 放 prototype 上(所有实例共享)


四、原型链

JS 的继承就是"原型链"——访问属性时沿链向上查找。

console.log(d1.toString());  // "[object Object]" ← 来自 Object.prototype

// 查找过程:d1 自身 → Device.prototype → Object.prototype → null
console.log(d1.__proto__ === Device.prototype);  // true
console.log(Device.prototype.__proto__ === Object.prototype);  // true
console.log(Object.prototype.__proto__);  // null(链条终点)
原型链图示:

d1 ──__proto__──> Device.prototype ──__proto__──> Object.prototype ──> null
     自身属性:id/name/status     方法:check/start     方法:toString/hasOwnProperty

五、原型链实现继承

// 父类:设备
function Device(id, name) {
  this.id = id;
  this.name = name;
}
Device.prototype.check = function () {
  return this.id + " 状态正常";
};

// 子类:数控机床
function CNCDevice(id, model, axis) {
  Device.call(this, id, "数控机床");  // 调用父构造函数,继承 id/name
  this.model = model;
  this.axis = axis;
}

// ⭐ 关键:子类原型指向"父类原型的副本"
CNCDevice.prototype = Object.create(Device.prototype);
CNCDevice.prototype.constructor = CNCDevice;  // 修正 constructor

// 子类自己的方法
CNCDevice.prototype.startMachining = function () {
  return this.name + " " + this.model + " 开始加工";
};

// 覆盖父类方法(多态)
CNCDevice.prototype.check = function () {
  return this.id + " 数控系统正常,轴数:" + this.axis;
};

var cnc = new CNCDevice("CNC-001", "VMC850", 5);
console.log(cnc.check());          // "CNC-001 数控系统正常,轴数:5"
console.log(cnc.startMachining()); // "数控机床 VMC850 开始加工"
console.log(cnc instanceof CNCDevice);  // true
console.log(cnc instanceof Device);     // true(在继承链上)

继承的核心一句话:子类.prototype = Object.create(父类.prototype)。ES6 的 class extends(第 15 周)会自动完成这些,但现在理解原理很重要。


六、查找规则与 hasOwnProperty

// 访问 obj.xxx 的查找规则:
// 1. obj 自身有?→ 用
// 2. 没有 → 沿 __proto__ 找 prototype
// 3. 一路向上到 Object.prototype → 还没有 → undefined

// 判断属性归属
function Device(id) { this.id = id; }
Device.prototype.check = function () {};
var d = new Device("CNC-001");

console.log(d.hasOwnProperty("id"));     // true(自身属性)
console.log(d.hasOwnProperty("check"));  // false(原型方法)
console.log("check" in d);               // true(原型链上能找到)

七、总结

概念

关键点

构造函数

首字母大写,用 new 调用

new 4 步

建对象 → 连原型 → this 赋值 → 返回

prototype

放共享方法,所有实例共用一份

原型链

属性查找沿 proto 向上,直到 null

继承

子.prototype = Object.create(父.prototype)

hasOwnProperty

判断属性是不是实例自身的

🎯 原型是 JS 对象机制的核心。明天学 DOM——用 JS 操作网页,把原型对象的方法用到真正的页面交互上。

评论