【JS】JS基础--原型和原型链

JavaScript性能优化实战 10w+人浏览 427人参与

JavaScript 中的原型 (Prototype)原型链 (Prototype Chain),是 JavaScript 面向对象编程的基石,也是它与其他基于类的语言(如 Java、C++)最大的不同之处。

1. 核心概念:为什么需要原型?

JavaScript 在诞生之初,为了简化语言,被设计为一种基于原型 (Prototype) 而不是类 (Class) 的语言。它的继承机制是通过对象之间的关联来实现的,而不是通过类复制。

每个 JavaScript 对象(除 null 外)都有一个隐藏属性 [[Prototype]](在 ES5 标准中可通过 __proto__ 访问),它指向另一个对象,这个对象就是它的原型

核心目的:实现属性和方法的共享,节省内存,实现继承。


2. 理解 __proto__prototype

这是最容易混淆的两个概念。记住它们的区别:

特性__proto__prototype
所有者每一个对象都拥有只有函数对象才拥有 (ES6+ 的类也是函数)
含义指向该对象的原型对象 (谁是我的父亲?)作为构造函数时,它创建的实例的 __proto__ 将指向它 (我的孩子应该以谁为原型?)
标准非标准属性,但被大多数浏览器实现。ES6 中将其标准化,但推荐使用 Object.getPrototypeOf()标准属性

简单关系公式:

// 当一个函数 Func 被作为构造函数(通过 new 关键字)调用时
instance = new Func();

// 会有以下关系成立:
instance.__proto__ === Func.prototype // true

3. 图解原型链

让我们通过一个最简单的例子来构建原型链。

// 1. 创建一个构造函数
function Person(name) {
  this.name = name;
}

// 2. 在构造函数的 prototype 上添加方法
Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name}`);
};

// 3. 使用 new 创建实例
const alice = new Person('Alice');
const bob = new Person('Bob');

// 4. 访问属性和方法
alice.sayHello(); // "Hello, my name is Alice"
bob.sayHello();   // "Hello, my name is Bob"

// 验证关系:
console.log(alice.__proto__ === Person.prototype); // true
console.log(bob.__proto__ === Person.prototype);   // true

// Person.prototype 本身也是一个对象,它也有 __proto__
console.log(Person.prototype.__proto__ === Object.prototype); // true

// Object.prototype 是绝大多数对象的原型链终点
console.log(Object.prototype.__proto__); // null

此时的完整原型链如下图所示:

在这里插入图片描述

查找机制(原型链的工作原理):
当访问 alice.sayHello() 时,JavaScript 引擎会:

  1. 首先在 alice 对象自身查找是否有 sayHello 方法。
  2. 如果没有,就通过 alice.__proto__(也就是 Person.prototype)去它的原型上找。
  3. Person.prototype 上找到了,于是调用它。
  4. 如果还没找到,就继续通过 Person.prototype.__proto__(也就是 Object.prototype)往上找。
  5. 如果在 Object.prototype 上也没找到,再往上就是 null,查找停止,返回 undefined

这条由 __proto__ 串联起来的链状结构,就是原型链。


4. 完整的原型链

在上面的例子中,原型链是:
alicePerson.prototypeObject.prototypenull

对于数组、函数等内置对象,它们的原型链更长:

const arr = [1, 2, 3];
// arr -> Array.prototype -> Object.prototype -> null

function fn() {}
// fn -> Function.prototype -> Object.prototype -> null

甚至构造函数本身也是函数:

// Person -> Function.prototype -> Object.prototype -> null
console.log(Person.__proto__ === Function.prototype); // true

5. 相关方法与操作

  1. 获取原型: Object.getPrototypeOf(obj)

    console.log(Object.getPrototypeOf(alice) === Person.prototype); // true
    // (推荐使用这种方式,而不是 obj.__proto__)
    
  2. 设置原型: Object.setPrototypeOf(obj, prototype) (性能差,不推荐) 或 Object.create()

    const parent = { familyName: 'Smith' };
    const child = Object.create(parent); // 以 parent 对象为原型创建 child
    console.log(child.familyName); // 'Smith'
    console.log(Object.getPrototypeOf(child) === parent); // true
    
  3. 检查自身属性: obj.hasOwnProperty(prop)

    console.log(alice.hasOwnProperty('name')); // true (来自构造函数)
    console.log(alice.hasOwnProperty('sayHello')); // false (来自原型链)
    
  4. instanceof 运算符
    检查构造函数prototype 属性是否出现在实例对象的原型链上。

    console.log(alice instanceof Person); // true
    console.log(alice instanceof Object); // true (因为 Object.prototype 在 alice 的原型链上)
    

6. ES6 中的 Class 语法糖

ES6 引入的 class 本质上是原型继承的语法糖,让写法更清晰、更像传统面向对象语言。

class Person {
  constructor(name) {
    this.name = name; // 实例属性
  }

  // 这个方法会自动添加到 Person.prototype 上
  sayHello() {
    console.log(`Hello, my name is ${this.name}`);
  }

  // 静态方法,直接存在于 Person 上,实例无法访问
  static describe() {
    console.log('I am a Person class');
  }
}

const alice = new Person('Alice');
alice.sayHello(); // "Hello, my name is Alice"

// 其底层原型关系与之前的函数构造方式完全一致
console.log(alice.__proto__ === Person.prototype); // true
console.log(Person.prototype.hasOwnProperty('sayHello')); // true

总结

概念描述
原型 (Prototype)一个对象,用于共享属性和方法。Func.prototype 是构造函数创建实例时的蓝图。
原型链 (Prototype Chain)__proto__ 链接起来的对象链,用于实现继承和属性查找。查找规则是自下而上
__proto__对象的一个属性,指向它的原型对象。
prototype函数的一个属性,指向一个对象,该对象将成为由此函数创建的实例的原型。
核心思想委托 (Delegation):对象自身没有的属性或方法,会委托给它的原型去查找。

理解原型和原型链是理解 JavaScript 对象模型、继承、new 关键字工作原理以及许多现代框架和库的基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝莓味的口香糖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值