六十天前端强化训练之第十三天之JavaScript 原型与继承详解

发布于:2025-03-09 ⋅ 阅读:(11) ⋅ 点赞:(0)

=====欢迎来到编程星辰海的博客讲解======

目录

一、原型系统底层探秘

1.1 对象体系构建原理

内存模型示意图

1.2 原型链工作机制

1.3 原型相关方法详解

(1) Object.getPrototypeOf

(2) Object.setPrototypeOf

(3) Object.create

1.4 构造函数运行机制

二、八种继承模式深度剖析

2.1 原型链继承(经典方式)

2.2 构造函数继承

2.3 组合继承(伪经典继承)

2.4 原型式继承

2.5 寄生式继承

2.6 寄生组合继承(终极方案)

2.7 ES6类继承

2.8 多重继承实现

三、原型操作最佳实践

3.1 原型污染防护

3.2 原型方法扩展规范

3.3 原型调试技巧

四、实战案例:完整电商系统类设计

4.1 类结构设计

4.2 原型关系图

五、扩展阅读推荐

5.1 必读文档

5.2 经典图书

5.3 视频资源

5.4 在线实验


一、原型系统底层探秘

1.1 对象体系构建原理

JavaScript 的对象系统基于三大核心要素:

  • 构造函数:用于创建对象的函数模板(本质仍是函数)
  • 原型对象:包含共享属性和方法的对象
  • 实例对象:通过 new 操作符创建的具体对象
内存模型示意图

BASH

实例对象 (obj)
  ├── [[Prototype]] --> 原型对象 (Constructor.prototype)
  │       ├── constructor --> 构造函数 (Constructor)
  │       └── [[Prototype]] --> Object.prototype
  └── 私有属性

1.2 原型链工作机制

属性访问过程详解

  1. 在实例自身属性中查找
  2. 未找到则向上查找原型对象
  3. 递归直到 Object.prototype
  4. Object.prototype 的 [[Prototype]] 为 null

JAVASCRIPT

const animal = { eats: true };
const rabbit = { jumps: true, __proto__: animal };

console.log(rabbit.eats); // true(原型链查找)
console.log(rabbit.jumps); // true(自有属性)

1.3 原型相关方法详解

(1) Object.getPrototypeOf

JAVASCRIPT

function Person() {}
const p = new Person();
console.log(Object.getPrototypeOf(p) === Person.prototype); // true
(2) Object.setPrototypeOf

JAVASCRIPT

const basic = { version: 1.0 };
const extended = {};
Object.setPrototypeOf(extended, basic);
console.log(extended.version); // 1.0
(3) Object.create

JAVASCRIPT

const protoObj = { log() { console.log(this.msg) } };
const child = Object.create(protoObj, {
  msg: { value: 'Hello World' }
});
child.log(); // "Hello World"

1.4 构造函数运行机制

new 操作符完整执行流程:

  1. 创建空对象 const obj = {}
  2. 绑定原型 obj.__proto__ = Constructor.prototype
  3. 执行构造函数 Constructor.call(obj, args)
  4. 返回对象(如果构造函数返回非对象,则返回 obj)

手动实现 new 操作符

JAVASCRIPT

function myNew(Con, ...args) {
  const obj = Object.create(Con.prototype);
  const result = Con.apply(obj, args);
  return result instanceof Object ? result : obj;
}

二、八种继承模式深度剖析

2.1 原型链继承(经典方式)

JAVASCRIPT

function Parent() {
  this.parentProp = true;
}
Parent.prototype.getParentProp = function() {
  return this.parentProp;
};

function Child() {
  this.childProp = false;
}

// 实现继承
Child.prototype = new Parent();

const instance = new Child();
console.log(instance.getParentProp()); // true

存在问题

  • 引用类型共享问题
  • 无法向父类传参

2.2 构造函数继承

JAVASCRIPT

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

function Child(name) {
  Parent.call(this, name); // 关键代码
}

const child1 = new Child('Tom');
child1.colors.push('green');

const child2 = new Child('Jerry');
console.log(child2.colors); // ['red', 'blue'](独立副本)

优势与局限

  • ✔ 解决属性共享问题
  • ✖ 无法继承原型方法

2.3 组合继承(伪经典继承)

JAVASCRIPT

function Parent(name) {
  this.name = name;
  this.colors = ['red', 'blue'];
}

Parent.prototype.sayName = function() {
  console.log(this.name);
};

function Child(name, age) {
  Parent.call(this, name); // 第二次调用
  this.age = age;
}

Child.prototype = new Parent(); // 第一次调用
Child.prototype.constructor = Child;

const child = new Child('Lucy', 12);
child.sayName(); // "Lucy"

效率问题
父构造函数被调用两次导致属性重复(实例属性和原型属性)

2.4 原型式继承

JAVASCRIPT

const person = {
  name: 'Default',
  friends: ['Alice', 'Bob']
};

const another = Object.create(person, {
  name: { value: 'Greg' }
});

another.friends.push('Charlie');
console.log(person.friends); // ['Alice', 'Bob', 'Charlie']

适用场景
不需要构造函数的简单对象继承

2.5 寄生式继承

JAVASCRIPT

function createEnhance(obj) {
  const clone = Object.create(obj);
  clone.sayHi = function() {
    console.log('Hi!');
  };
  return clone;
}

const base = { name: 'Base' };
const enhanced = createEnhance(base);
enhanced.sayHi(); // "Hi!"

特点

  • 为对象添加额外方法
  • 无法实现函数复用

2.6 寄生组合继承(终极方案)

JAVASCRIPT

function inheritPrototype(child, parent) {
  const prototype = Object.create(parent.prototype);
  prototype.constructor = child;
  child.prototype = prototype;
}

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;
}

inheritPrototype(Child, Parent);

const child = new Child('Sam', 10);
child.sayName(); // "Sam"

优势分析

  • 只调用一次父构造函数
  • 原型链保持正确
  • 无属性冗余

2.7 ES6类继承

JAVASCRIPT

class Animal {
  constructor(name) {
    this.name = name;
  }

  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

class Dog extends Animal {
  constructor(name, breed) {
    super(name);
    this.breed = breed;
  }

  speak() {
    super.speak();
    console.log(`${this.name} barks.`);
  }
}

const d = new Dog('Buddy', 'Golden Retriever');
d.speak();
// "Buddy makes a noise."
// "Buddy barks."

2.8 多重继承实现

JAVASCRIPT

function mix(...mixins) {
  class Mix {
    constructor() {
      for (let mixin of mixins) {
        copyProperties(this, new mixin());
      }
    }
  }

  function copyProperties(target, source) {
    for (let key of Reflect.ownKeys(source)) {
      if (key !== 'constructor') {
        Object.defineProperty(target, key, 
          Object.getOwnPropertyDescriptor(source, key));
      }
    }
  }

  return Mix;
}

class A { methodA() {} }
class B { methodB() {} }

class C extends mix(A, B) {}

三、原型操作最佳实践

3.1 原型污染防护

JAVASCRIPT

// 安全的对象创建
const safeObj = Object.create(null);
safeObj.toString = function() { /* custom */ };

// 冻结原型
Object.freeze(Object.prototype);

3.2 原型方法扩展规范

JAVASCRIPT

// 正确的方式
if (!Array.prototype.customMethod) {
  Array.prototype.customMethod = function() {
    // 实现代码
  };
}

// 错误示例(可能引发问题)
Array.prototype = {
  newMethod: function() { /*...*/ }
};

3.3 原型调试技巧

使用 Chrome DevTools 检查原型链:

JAVASCRIPT

function Parent() {}
function Child() {}
Child.prototype = Object.create(Parent.prototype);

const obj = new Child();

// 控制台输入
console.log(obj);
// 展开 __proto__ 链查看继承关系

// 验证继承关系
console.log(obj instanceof Child);  // true
console.log(obj instanceof Parent); // true

四、实战案例:完整电商系统类设计

4.1 类结构设计

JAVASCRIPT

class Product {
  constructor(id, name, price) {
    this.id = id;
    this.name = name;
    this.price = price;
  }

  display() {
    console.log(`Product: ${this.name} ($${this.price})`);
  }
}

class DigitalProduct extends Product {
  constructor(id, name, price, fileSize) {
    super(id, name, price);
    this.fileSize = fileSize;
  }

  download() {
    console.log(`Downloading ${this.name} (${this.fileSize}MB)`);
  }
}

class ShoppingCart {
  constructor() {
    this.items = [];
  }

  addItem(product, quantity = 1) {
    this.items.push({ product, quantity });
  }

  calculateTotal() {
    return this.items.reduce((sum, item) => 
      sum + item.product.price * item.quantity, 0);
  }
}

// 使用示例
const book = new Product(1, 'JS Guide', 39.99);
const course = new DigitalProduct(2, 'React Course', 99, 2048);

const cart = new ShoppingCart();
cart.addItem(book, 2);
cart.addItem(course);

console.log(cart.calculateTotal()); // 39.99*2 + 99 = 178.98

4.2 原型关系图

TEXT

ShoppingCart.prototype --> Object.prototype
DigitalProduct.prototype --> Product.prototype --> Object.prototype

五、扩展阅读推荐

5.1 必读文档

5.2 经典图书

  • 《JavaScript 设计模式与开发实践》第三章
  • 《编写可维护的JavaScript》第6章
  • 《JavaScript 悟道》第9章 对象系统

5.3 视频资源

5.4 在线实验


以上内容通过 Chrome 95+ 浏览器验证测试,所有代码示例均可直接复制到开发者工具控制台运行。建议配合浏览器调试工具逐步跟踪原型链变化,可加深理解。