原型与原型链

前言

在 JavaScript 中,原型是一个非常重要的概念。

如果不理解原型,很多内容都会变得很模糊,比如:

  • 构造函数
  • 实例方法共享
  • 原型链
  • 类的本质

本文重点讲清楚:什么是原型、为什么需要原型、prototype 和 proto 有什么区别、原型链


一、什么是原型?

在 JavaScript 中,每个函数都有一个特殊属性:

perl 复制代码
prototype

这个属性指向一个对象,这个对象就叫做 原型对象

看一个例子:

javascript 复制代码
function Person(name) {
  this.name = name;
}

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

const p1 = new Person('Tom');
const p2 = new Person('Alice');

p1.sayHello(); // 你好,我是 Tom
p2.sayHello(); // 你好,我是 Alice

这里:

javascript 复制代码
Person.prototype

就是构造函数

Person

的原型对象。


二、为什么需要原型?

如果我们把方法写在构造函数内部:

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

那么每创建一个实例,就会重新创建一次

sayHello

方法。

这样会导致:

  • 方法重复创建
  • 浪费内存

如果写到原型上:

javascript 复制代码
Person.prototype.sayHello = function () {
  console.log(`你好,我是 ${this.name}`);
};

那么所有实例就可以共享同一个方法。

所以原型最核心的作用就是:

让实例共享属性和方法。


三、prototype 和 proto 的区别

这是非常高频、也非常容易混淆的知识点。

1)prototype

  • 只有函数才有
  • 指向构造函数的原型对象

2)__proto__

  • 对象才有
  • 指向该对象的原型

看例子:

javascript 复制代码
function Person() {}

const p = new Person();

console.log(Person.prototype);
console.log(p.__proto__);
console.log(p.__proto__ === Person.prototype); // true

这个关系非常重要:

实例对象.__proto__ === 构造函数.prototype


四、原型上的属性和实例上的属性

ini 复制代码
function Person(name) {
  this.name = name;
}

Person.prototype.age = 18;

const p = new Person('Tom');

console.log(p.name); // Tom
console.log(p.age);  // 18

这里:

  • name

    是实例自己的属性

  • age

    是原型上的属性

当访问

p.age

时,JS 发现实例本身没有这个属性,就会去原型上找。


五、原型的实际意义

原型的最大意义就是"共享"。

例如数组为什么都有

push

pop

map

这些方法?

因为这些方法都定义在:

javascript 复制代码
Array.prototype

上。

所以数组实例本身不需要重复拥有这些方法。


六、总结

原型可以用一句话总结:

原型是 JavaScript 中实现属性和方法共享的机制。

重点记住:

  • 函数有

    prototype

  • 对象有

    __proto__

  • 实例.__proto__ === 构造函数.prototype


学完原型之后,接下来最重要的就是 原型链

原型链本质上解决的是一个问题:

当我们访问对象属性时,JavaScript 到底是怎么查找的?

理解了原型链,你就能更清楚地看懂:

  • 为什么对象可以调用某些方法

  • 为什么数组能用

    push

  • 为什么实例可以访问原型方法


原型链

一、什么是原型链?

当访问一个对象的属性或方法时,JavaScript 会先在对象本身查找。

如果找不到,就会去对象的原型上查找。

如果原型上还找不到,就继续去原型的原型上查找。

这一层一层向上查找的结构,就叫做 原型链


二、属性查找过程

javascript 复制代码
function Person(name) {
  this.name = name;
}

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

const p = new Person('Tom');

console.log(p.name); // Tom
p.sayHello();        // 你好,我是 Tom

查找p.name

  1. 先看

    p

    自身有没有

    name

  2. 有,直接返回

查找p.sayHello

  1. 先看

    p

    自身有没有

    sayHello

  2. 没有

  3. p.__proto__

    ,也就是

    Person.prototype

    上找

  4. 找到了,执行它


三、原型链的尽头是什么?

javascript 复制代码
function Person() {}

const p = new Person();

console.log(p.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null

所以原型链大致是:

javascript 复制代码
p
→ Person.prototype
→ Object.prototype
→ null

null

就是原型链的终点。


四、数组的原型链

数组也是对象,所以也有原型链。

javascript 复制代码
const arr = [1, 2, 3];

console.log(arr.__proto__ === Array.prototype); // true
console.log(Array.prototype.__proto__ === Object.prototype); // true

原型链结构大致是:

javascript 复制代码
arr
→ Array.prototype
→ Object.prototype
→ null

所以数组既能用数组方法,也能用对象原型上的某些方法。


五、为什么原型链重要?

因为 JavaScript 中很多方法并不是对象自身直接拥有的,而是通过原型链继承来的。

例如:

ini 复制代码
const arr = [1, 2, 3];

arr.push(4);
arr.toString();

这里:

  • push

    来自

    Array.prototype

  • toString

    可能继续来自更上层原型


六、总结

原型链可以简单理解为:

对象查找属性时,沿着原型一层层向上查找的链式结构。

查找规则:

  1. 先找对象自身

  2. 再找原型

  3. 再找原型的原型

  4. 直到

    null

相关推荐
这儿有一堆花8 小时前
前端三件套真的落后了吗?揭开现代 Web 开发的底层逻辑
前端·javascript·css·html5
.Cnn8 小时前
JavaScript 前端基础笔记(网页交互核心)
前端·javascript·笔记·交互
醉酒的李白、9 小时前
Vue3 组件通信本质:Props 下发,Emits 回传
前端·javascript·vue.js
小芝麻咿呀10 小时前
vue--面试题第一部分
前端·javascript·vue.js
nibabaoo10 小时前
前端开发攻略---H5页面手机获取摄像头权限回显出画面并且同步到PC页面
javascript·websocket·实时音视频·实时同步·录制
早起傻一天~G11 小时前
vue2+element-UI表格封装
javascript·vue.js·ui
这儿有一堆花11 小时前
深入解析 Video.js:现代 Web 视频播放的工程实践
前端·javascript·音视频
烤麻辣烫11 小时前
JS基础
开发语言·前端·javascript·学习
猫猫不是喵喵.13 小时前
layui表单项次大数据量导入并提交
前端·javascript·layui
Hello--_--World14 小时前
ES13:类私有属性和方法、顶层 await、at() 方法、Object.hasOwnProperty()、类静态块 相关知识点
开发语言·javascript·es13