用大白话讲明白JavaScript的原型和原型链

原型:对象的"爹"

想象每个JavaScript对象都有一个"爹"(原型),当你问这个对象要东西(属性或方法)时:

  1. 它先摸摸自己口袋,有就直接给你
  2. 如果自己口袋没有,它就会问它爹要
  3. 它爹也没有?那就继续问它爷爷要...

这样一代代往上找,直到找到或者家族谱系到头了(null)

// 爷爷辈
const 爷爷 = { 家族姓氏: '张' };

// 爸爸辈
const 爸爸 = { 名字: '张三' };
Object.setPrototypeOf(爸爸, 爷爷); // 设定爸爸的原型是爷爷

// 儿子辈
const 儿子 = { 小名: '小明' };
Object.setPrototypeOf(儿子, 爸爸); // 设定儿子的原型是爸爸

console.log(儿子.小名); // "小明" - 自己的
console.log(儿子.名字); // "张三" - 爸爸的
console.log(儿子.家族姓氏); // "张" - 爷爷的

为什么要有这个机制?

  1. 省内存:所有儿子可以共用爸爸的方法,不用每人复制一份
function 手机(型号) {
  this.型号 = 型号;
}

// 所有手机共用同一个拍照方法
手机.prototype.拍照 = function() {
  console.log(`${this.型号}拍了一张照片`);
};

const 我的手机 = new 手机('小米13');
const 你的手机 = new 手机('iPhone15');

我的手机.拍照(); // "小米13拍了一张照片"
你的手机.拍照(); // "iPhone15拍了一张照片"
  1. 实现继承:就像现实中的家族传承

三个关键点

  1. _ _ proto_ _:每个对象都有的隐藏属性,指向它的"爹"(原型)
    >现代浏览器可以用,但不是标准用法
    >推荐用 Object.getPrototypeOf(obj) 获取
这里拓展一下Object.getPrototypeOf(obj)
//Object.getPrototypeOf() 是官方推荐的获取对象原型的方法,
//比直接使用 __proto__ 更规范和安全。
//下面我用几个具体例子来说明如何使用:
基本用法
// 创建一个普通对象
const animal = {
  eats: true
};

// 创建另一个对象,并以animal作为其原型
const rabbit = {
  jumps: true
};
Object.setPrototypeOf(rabbit, animal);

// 使用Object.getPrototypeOf()获取rabbit的原型
const rabbit的原型 = Object.getPrototypeOf(rabbit);
console.log(rabbit的原型 === animal); // true
console.log(rabbit的原型.eats); // true
构造函数场景示例
// 定义一个构造函数
function Person(name) {
  this.name = name;
}

// 在构造函数的原型上添加方法
Person.prototype.sayHi = function() {
  console.log(`Hi, I'm ${this.name}`);
};

// 创建实例
const john = new Person('John');

// 获取实例的原型
const john的原型 = Object.getPrototypeOf(john);
console.log(john的原型 === Person.prototype); // true
john的原型.sayHi(); // "Hi, I'm undefined" (因为this指向原型对象)
john.sayHi(); // "Hi, I'm John" (正确调用)
  1. prototype: 只有函数有的特殊属性
    >当这个函数被当作构造函数(new 函数())时,新对象的proto会指向这个prototype
  2. 原型链的顶端:所有对象的祖宗都是Object.prototype,它的proto是null

日常比喻

图书馆借书:

你先在自己房间找书(自身属性)

找不到去家里书房找(原型)

还找不到去社区图书馆找(更上一级原型)

最后国家图书馆都找不到就返回"没找到"(undefined)

公司组织架构:

你有问题先自己解决

解决不了问组长(你的原型)

组长解决不了问经理(组长的原型)

一直到CEO(Object.prototype)

CEO上面没人了(null)

记住这个链条,你就理解了JavaScript对象如何"找人办事"的机制!

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容