JavaScript篇:JavaScript原型与原型链:深入理解对象继承的奥秘

🎓 作者简介前端领域优质创作者

🚪 资源导航: 传送门=>

🎬 个人主页: 江城开朗的豌豆

🌐 个人网站: 江城开朗的豌豆 🌍

📧 个人邮箱: [email protected] 📩

💬 个人微信: y_t_t_t_ 📱

📌 座 右 铭: 生活就像心电图,一帆风顺就证明你挂了 💔

👥 QQ群: 906392632 (前端技术交流群) 💬

记得刚学习JavaScript时,面对原型和原型链这个概念,我一度感到非常困惑。直到在项目中遇到一个实际问题,才让我真正理解了它的重要性。今天,就让我们通过几个实际的例子,来揭开JavaScript对象继承的神秘面纱。

从一个实际案例说起

杨涛在开发一个员工管理系统时,写了如下代码:

javascript 复制代码
function Employee(name, age) {
  this.name = name;
  this.age = age;
  this.sayHello = function() {
    console.log(`大家好,我是${this.name}`);
  };
}

const emp1 = new Employee('杨涛', 28);
const emp2 = new Employee('李四', 30);

console.log(emp1.sayHello === emp2.sayHello); // false

他发现每个Employee实例都创建了自己的sayHello方法副本,这显然造成了内存浪费。如何解决这个问题呢?这就是原型大显身手的时候了。

原型的基本概念

在JavaScript中,每个函数都有一个特殊的prototype属性,它指向一个对象,这个对象就是我们所说的原型对象。当我们使用new操作符创建实例时,实例会继承其构造函数的原型对象上的属性和方法。

改进后的代码:

javascript 复制代码
function Employee(name, age) {
  this.name = name;
  this.age = age;
}

Employee.prototype.sayHello = function() {
  console.log(`大家好,我是${this.name}`);
};

const emp1 = new Employee('杨涛', 28);
const emp2 = new Employee('李四', 30);

console.log(emp1.sayHello === emp2.sayHello); // true

现在,所有实例共享同一个sayHello方法,大大节省了内存。

原型链的运作机制

原型链是JavaScript实现继承的基础。当访问一个对象的属性时,JavaScript引擎会:

  1. 先在对象自身属性中查找
  2. 如果找不到,就去对象的原型(__proto__)上查找
  3. 如果还找不到,就继续往原型的原型上查找
  4. 直到找到属性或者到达原型链顶端(null)为止
javascript 复制代码
// 创建经理类,继承自Employee
function Manager(name, age, department) {
  Employee.call(this, name, age);
  this.department = department;
}

// 设置原型继承
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;

// 添加经理特有方法
Manager.prototype.assignTask = function(task) {
  console.log(`${this.name}经理正在分配任务:${task}`);
};

const mgr = new Manager('杨涛', 35, '技术部');
mgr.sayHello(); // 继承自Employee
mgr.assignTask('完成项目原型设计'); // Manager自有方法

原型链的实际应用

1. 内置方法的继承

javascript 复制代码
const arr = [1, 2, 3];
console.log(arr.map); // 来自Array.prototype
console.log(arr.toString); // 来自Object.prototype

2. 属性遮蔽(Property Shadowing)

javascript 复制代码
Employee.prototype.position = '员工';

const emp = new Employee('杨涛', 28);
console.log(emp.position); // "员工"

emp.position = '高级工程师'; // 创建实例自身属性
console.log(emp.position); // "高级工程师"

delete emp.position;
console.log(emp.position); // 又变回"员工"

3. 检查原型关系

javascript 复制代码
console.log(emp instanceof Employee); // true
console.log(Employee.prototype.isPrototypeOf(emp)); // true
console.log(Object.getPrototypeOf(emp) === Employee.prototype); // true

ES6中的class语法糖

ES6的class语法让原型继承更加直观:

javascript 复制代码
class Employee {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  sayHello() {
    console.log(`大家好,我是${this.name}`);
  }
}

class Manager extends Employee {
  constructor(name, age, department) {
    super(name, age);
    this.department = department;
  }
  
  assignTask(task) {
    console.log(`${this.name}经理正在分配任务:${task}`);
  }
}

const mgr = new Manager('杨涛', 35, '技术部');
mgr.sayHello();

原型链的调试技巧

在Chrome开发者工具中,可以通过以下方式查看原型链:

  1. 使用console.dir()查看对象的完整结构
  2. 在控制台输入对象名,展开__proto__属性
  3. 使用Object.getPrototypeOf()获取对象的原型

常见误区与最佳实践

  1. 不要直接修改内置对象的原型

    javascript 复制代码
    // 不推荐的做法
    Array.prototype.myMethod = function() {
      // ...
    };
  2. 注意原型链的性能影响

    javascript 复制代码
    // 过长的原型链会影响查找性能
  3. 优先使用Object.create而不是__proto__

    javascript 复制代码
    // 更好的方式
    const child = Object.create(parent);
    
    // 不推荐的方式
    child.__proto__ = parent;

总结

理解原型和原型链是掌握JavaScript面向对象编程的关键。通过原型链,JavaScript实现了灵活的对象继承机制。记住几个要点:

  1. 每个函数都有prototype属性,每个对象都有__proto__属性
  2. 原型链的终点是Object.prototype,再往上就是null
  3. ES6的class语法是原型继承的语法糖

正如JavaScript之父Brendan Eich所说:"JavaScript的继承是基于原型的,这与传统的类继承有很大不同。"掌握原型链,你就能真正理解JavaScript对象系统的精妙之处。

相关推荐
Bunury16 分钟前
element-plus添加暗黑模式
开发语言·前端·javascript
心走20 分钟前
八股文中TCP三次握手怎么具象理解?
前端·面试
Aiolimp29 分钟前
React常见Hooks使用(二)
前端·react.js
By北阳29 分钟前
CSS 中实现 div 居中有以下几种常用方法
前端·css
在广东捡破烂的吴彦祖32 分钟前
window配置Flutter开发环境
前端·flutter
辣椒粉丝34 分钟前
记rspack想提issuse,提太慢白嫖不上了
前端·javascript
腰间盘突出的红利36 分钟前
npm组件库搭建
前端
火星思想37 分钟前
前端基础布局写法详解:左右、左中右及弹性布局实践
前端·css
小桥风满袖37 分钟前
Three.js-硬要自学系列10 (创建纹理贴图、自定义顶点UV坐标)
前端·css·three.js
七月丶39 分钟前
🧼 为什么我开始在项目里禁用 CSS 文件?
前端·javascript·后端