如何从一个组件的实现来深刻理解JS中的继承

发布时间:2021-11-16 17:33:48 作者:柒染
来源:亿速云 阅读:95
# 如何从一个组件的实现来深刻理解JS中的继承

## 目录
1. [引言:为什么选择组件作为切入点](#引言)
2. [JavaScript继承机制全景图](#继承机制全景图)
3. [组件设计中的继承需求分析](#组件设计需求)
4. [原型链继承的实战应用](#原型链继承)
5. [构造函数继承的组件实践](#构造函数继承)
6. [组合继承的完美平衡](#组合继承)
7. [原型式继承与Object.create](#原型式继承)
8. [寄生式继承的增强模式](#寄生式继承)
9. [寄生组合继承的终极方案](#寄生组合继承)
10. [ES6 Class的语法糖本质](#ES6-Class)
11. [组件生命周期中的继承表现](#生命周期继承)
12. [多继承的模拟实现](#多继承模拟)
13. [继承与组合的哲学思考](#继承与组合)
14. [TypeScript中的继承增强](#TypeScript继承)
15. [总结:从组件到语言特性的闭环](#总结)

<a id="引言"></a>
## 1. 引言:为什么选择组件作为切入点

在现代前端开发中,组件化开发已经成为主流范式。一个典型的UI组件往往需要:
- 属性继承(props)
- 状态管理(state)
- 生命周期控制
- 方法复用

```javascript
class Button extends React.Component {
  constructor(props) {
    super(props);  // 这里就发生了继承调用
    this.state = { clicked: false };
  }
  
  handleClick = () => {
    this.setState({ clicked: true });
  };
  
  render() {
    return (
      <button onClick={this.handleClick}>
        {this.props.children}
      </button>
    );
  }
}

通过这个简单案例,我们可以立即发现三个继承特征: 1. extends 关键字的使用 2. super() 的构造函数调用 3. 实例方法自动绑定到原型

2. JavaScript继承机制全景图

JavaScript采用原型继承机制,这与经典面向对象语言有本质区别:

继承方式 特点描述 组件应用场景
原型链继承 通过__proto__链接形成链条 基础组件扩展
构造函数继承 在子类中调用父类构造函数 状态初始化
组合继承 原型链+构造函数的组合 完整组件实现
原型式继承 Object.create创建新对象 轻量级对象扩展
寄生式继承 工厂函数增强对象 组件功能扩展
寄生组合继承 最优的ES5继承方案 高性能组件开发
ES6 Class 语法糖,底层仍是原型 现代组件开发

3. 组件设计中的继承需求分析

3.1 基础组件与业务组件

// 基础组件
class BaseTable {
  constructor(config) {
    this.columns = config.columns;
  }
  
  renderHeader() {
    // 通用表头渲染逻辑
  }
}

// 业务组件
class UserTable extends BaseTable {
  constructor(config) {
    super(config);
    this.userData = config.userData;
  }
  
  renderBody() {
    // 定制化用户数据渲染
  }
}

3.2 混入模式(Mixin)实现

const Loggable = {
  log(message) {
    console.log(`[${this.name}]: ${message}`);
  }
};

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

// 混入实现
Object.assign(Component.prototype, Loggable);

const comp = new Component('App');
comp.log('Initialized');  // 输出: [App]: Initialized

4. 原型链继承的实战应用

4.1 基本实现

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

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

function Dog(name) {
  this.name = name;
}

Dog.prototype = new Animal();  // 关键点

const dog1 = new Dog('Buddy');
dog1.colors.push('green');
console.log(dog1.colors);  // ['red', 'blue', 'green']

const dog2 = new Dog('Max');
console.log(dog2.colors);  // ['red', 'blue', 'green'] 问题出现!

4.2 组件中的应用

function BaseComponent() {
  this.id = Math.random().toString(36).substr(2);
}

BaseComponent.prototype.mount = function() {
  console.log(`Mounting ${this.id}`);
};

function UserComponent() {
  this.userId = null;
}

UserComponent.prototype = new BaseComponent();

const comp = new UserComponent();
comp.mount();  // 可以调用父类方法

5. 构造函数继承的组件实践

5.1 基本实现

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

function Dog(name) {
  Animal.call(this, name);  // 关键点
}

const dog1 = new Dog('Buddy');
dog1.colors.push('green');
console.log(dog1.colors);  // ['red', 'blue', 'green']

const dog2 = new Dog('Max');
console.log(dog2.colors);  // ['red', 'blue'] 问题解决

5.2 组件中的状态隔离

function Store() {
  this.state = {};
  this.subscribers = [];
}

function UserStore() {
  Store.call(this);
  this.user = null;
}

const store1 = new UserStore();
store1.state.count = 1;

const store2 = new UserStore();
console.log(store2.state.count);  // undefined 状态隔离成功

6. 组合继承的完美平衡

6.1 经典实现

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

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

function Dog(name, age) {
  Animal.call(this, name);  // 第二次调用父类
  this.age = age;
}

Dog.prototype = new Animal();  // 第一次调用父类
Dog.prototype.constructor = Dog;

const dog = new Dog('Buddy', 2);

6.2 组件中的完整应用

function ReactComponent(props) {
  this.props = props;
  this.state = {};
}

ReactComponent.prototype.setState = function(newState) {
  this.state = Object.assign({}, this.state, newState);
  this.render();
};

function MyComponent(props) {
  ReactComponent.call(this, props);  // 构造函数继承
  this.localState = {};
}

MyComponent.prototype = new ReactComponent();  // 原型链继承
MyComponent.prototype.constructor = MyComponent;

MyComponent.prototype.render = function() {
  console.log('Rendering with state:', this.state);
};

7. 原型式继承与Object.create

7.1 基本模式

const animal = {
  init(name) {
    this.name = name;
  },
  sayName() {
    console.log(this.name);
  }
};

const dog = Object.create(animal);
dog.init('Buddy');
dog.sayName();  // Buddy

7.2 组件配置继承

const baseConfig = {
  maxWidth: 1024,
  minWidth: 320,
  getBreakpoints() {
    return [this.minWidth, this.maxWidth];
  }
};

const mobileConfig = Object.create(baseConfig);
mobileConfig.maxWidth = 768;
console.log(mobileConfig.getBreakpoints());  // [320, 768]

8. 寄生式继承的增强模式

8.1 工厂函数实现

function createEnhancedComponent(base) {
  const clone = Object.create(base);
  clone.enhancedMethod = function() {
    console.log('Enhanced functionality');
  };
  return clone;
}

const baseComponent = {
  baseMethod() {
    console.log('Base method');
  }
};

const enhanced = createEnhancedComponent(baseComponent);
enhanced.enhancedMethod();  // Enhanced functionality

8.2 组件功能扩展

function withLogging(Component) {
  const proto = Component.prototype;
  
  const originalDidMount = proto.componentDidMount;
  proto.componentDidMount = function() {
    console.log(`Component ${this.constructor.name} mounted`);
    if (originalDidMount) {
      originalDidMount.apply(this, arguments);
    }
  };
  
  return Component;
}

class MyComponent {
  componentDidMount() {
    console.log('Original mount logic');
  }
}

const EnhancedComponent = withLogging(MyComponent);
const comp = new EnhancedComponent();
comp.componentDidMount();
// 输出:
// Component MyComponent mounted
// Original mount logic

9. 寄生组合继承的终极方案

9.1 完美继承实现

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

function Animal(name) {
  this.name = name;
}

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

function Dog(name, breed) {
  Animal.call(this, name);
  this.breed = breed;
}

inheritPrototype(Dog, Animal);

const dog = new Dog('Buddy', 'Golden');
dog.sayName();  // Buddy

9.2 组件库开发实践

// 核心库
function CoreComponent() {
  this.id = generateId();
}

CoreComponent.prototype.mount = function() {
  console.log(`Mounted ${this.id}`);
};

// UI库
function UIComponent(config) {
  CoreComponent.call(this);
  this.config = config;
}

inheritPrototype(UIComponent, CoreComponent);

UIComponent.prototype.render = function() {
  console.log('Rendering UI');
};

10. ES6 Class的语法糖本质

10.1 类继承示例

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

class Dog extends Animal {
  constructor(name) {
    super(name);
  }
  
  speak() {
    console.log(`${this.name} barks`);
  }
}

const dog = new Dog('Buddy');
dog.speak();  // Buddy barks

10.2 Babel转译结果

// 转译后的ES5代码
function _inherits(subClass, superClass) {
  subClass.prototype = Object.create(
    superClass && superClass.prototype,
    {
      constructor: {
        value: subClass,
        writable: true,
        configurable: true
      }
    }
  );
  if (superClass) _setPrototypeOf(subClass, superClass);
}

// ...其他辅助函数

11. 组件生命周期中的继承表现

11.1 React组件示例

class BaseComponent extends React.Component {
  componentDidMount() {
    console.log('Base mounted');
    this.startTime = Date.now();
  }
  
  componentWillUnmount() {
    const duration = Date.now() - this.startTime;
    console.log(`Lived for ${duration}ms`);
  }
}

class UserComponent extends BaseComponent {
  componentDidMount() {
    super.componentDidMount();  // 关键调用
    console.log('User mounted');
  }
  
  render() {
    return <div>User Component</div>;
  }
}

11.2 生命周期调用顺序

BaseComponent constructor
UserComponent constructor
BaseComponent componentDidMount
UserComponent componentDidMount
UserComponent componentWillUnmount
BaseComponent componentWillUnmount

12. 多继承的模拟实现

12.1 混入模式实现

class Serializable {
  serialize() {
    return JSON.stringify(this);
  }
}

class Loggable {
  log() {
    console.log(JSON.stringify(this, null, 2));
  }
}

function applyMixins(derivedCtor, baseCtors) {
  baseCtors.forEach(baseCtor => {
    Object.getOwnPropertyNames(baseCtor.prototype).forEach(name => {
      derivedCtor.prototype[name] = baseCtor.prototype[name];
    });
  });
}

class Component {
  constructor() {
    this.id = Math.random();
  }
}

class SmartComponent extends Component {}
applyMixins(SmartComponent, [Serializable, Loggable]);

const comp = new SmartComponent();
comp.log();  // 来自Loggable
console.log(comp.serialize());  // 来自Serializable

13. 继承与组合的哲学思考

13.1 继承层次过深的问题

Component
  └── BaseComponent
       └── UserComponent
            └── AdminComponent
                 └── SpecialAdminComponent

13.2 组合模式改进

class Component {
  constructor(behaviors = []) {
    this.behaviors = behaviors;
  }
  
  execute(name, ...args) {
    const behavior = this.behaviors.find(b => b[name]);
    if (behavior) {
      return behavior[name].apply(this, args);
    }
  }
}

const LogBehavior = {
  log() {
    console.log('Logging:', this);
  }
};

const SerializeBehavior = {
  serialize() {
    return JSON.stringify(this);
  }
};

const comp = new Component([LogBehavior, SerializeBehavior]);
comp.execute('log');
console.log(comp.execute('serialize'));

14. TypeScript中的继承增强

14.1 接口继承

interface Component {
  id: string;
  render(): void;
}

interface StatefulComponent extends Component {
  state: object;
  setState(newState: object): void;
}

class Button implements StatefulComponent {
  id: string;
  state = {};
  
  constructor(id: string) {
    this.id = id;
  }
  
  setState(newState: object) {
    this.state = { ...this.state, ...newState };
  }
  
  render() {
    console.log(`Rendering button ${this.id}`);
  }
}

14.2 抽象类约束

abstract class AbstractComponent {
  abstract render(): void;
  
  commonMethod() {
    console.log('Common functionality');
  }
}

class ConcreteComponent extends AbstractComponent {
  render() {
    console.log('Concrete implementation');
  }
}

15. 总结:从组件到语言特性的闭环

通过组件开发的视角,我们完整探索了JavaScript继承体系的七个关键阶段:

  1. 原型链继承 - 理解[[Prototype]]链接的本质
  2. 构造函数继承 - 解决实例属性隔离问题
  3. 组合继承 - 结合两者优势的经典方案
  4. 原型式继承 - Object.create的轻量级继承
  5. 寄生式继承 - 工厂模式的增强方案
  6. 寄生组合继承 - 最完美的ES5继承实现
  7. ES6 Class - 语法糖背后的继承本质

在组件开发中,继承的最佳实践是: - 使用ES6 class作为基础 - 深度不超过3层继承链 - 复杂功能优先考虑组合模式 - 生命周期方法必须调用super - 使用TypeScript增强类型安全

// 终极组件继承示例
class UltimateComponent extends React.Component {
  constructor(props) {
    super(props);  // 必须调用
    this.state = {};
  }
  
  // 生命周期方法
  componentDidMount() {
    super.componentDidMount?.();  // 安全调用
    // 组件逻辑
  }
  
  // 自定义方法
  enhancedMethod = () => {
    // 使用箭头函数自动绑定this
  };
  
  render() {
    return null;
  }
}

通过组件这个具体载体,我们不仅理解了JavaScript继承机制,更重要的是掌握了如何在实际项目中合理应用这些知识,构建出既灵活又可靠的代码结构。 “`

推荐阅读:
  1. js中的继承
  2. JS如何实现继承?

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

javascript

上一篇:怎么简单分析Flask框架

下一篇:如何进行Web中前后端模板引擎的使用

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》