当前位置: 首页 > news >正文

现实生活例子[特殊字符] 通俗易懂的解释[特殊字符] JS中的原型和原型链[特殊字符]

 

目录

1、先理解下什么是构造函数,又与普通函数的区别(可跳过这部分,回头再看)

2、原型对象

3、构造函数与原型

4、打个现实比方解释  原型 Prototype、原型链

4.1 原型(Prototype)——「家族遗传(家族基因库)」

4.2  原型链(Prototype Chain)——「家族族谱」

4.3  特殊案例——「DNA突变」‌

4.4  现代家族(ES6 Class)——「家规手册」

‌总结比喻‌

‌关键点‌:

 prototype 与 __proto__ 的关系——「基因库的访问路径」‌

5、打比方解释 constructor、prototype 和 __proto__ 的关系

6、拓展:Object.create() 和 new 的区别

6.1  ‌核心作用不同‌

6.2  原型链机制差异‌

7、拓展:new操作符都干了什么?


1、先理解下什么是构造函数,又与普通函数的区别(可跳过这部分,回头再看)

1.  通过 new 调用

2.  约定俗成 以大写字母开头(如PersonArray),(JavaScript不强制要求,但遵循约定可提高代码可读性)

3.  显式或隐式分配实例属性

  • 显式赋值‌:通过this.xxx = yyy为实例添加属性。 
  • ‌隐式分配‌:在构造函数中操作this的属性(如this.age++)。
// 一
function Car(model) {this.model = model;      // 实例属性this.wheels = 4;         // 实例属性this.drive = function() { // 实例方法(不推荐,通常用原型)console.log(`${this.model} is driving!`);};
}
const alice = new Car("WW"); // 正确// 二
function Animal(name) {this.name = name;
}
Animal.prototype.speak = function() { // 实例方法(推荐)console.log(`${this.name} makes a noise.`);
};const cat = new Animal("Whiskers");
cat.speak(); // "Whiskers makes a noise."(方法来自原型)// 三
function Person(name) {this.name = name; // 正确:通过new调用时,this指向新实例
}
const alice = new Person("Alice"); // 正确
const bob = Person("Bob");         // 错误:this指向全局对象(严格模式为undefined)

2、原型对象

原型对象是实现 JavaScript 继承和共享方法的核心机制。

  • js中,每个普通函数‌(非箭头函数)都有一个prototype 属性(可通过__proto__Object.getPrototypeOf()访问),这个属性指向的是一个对象,这个对象即为原型对象。

  • 这个原型对象(Person.prototype)默认包含一个 constructor 属性,指向函数本身(即 Person.prototype.constructor === Person)。
  • function Person() {}
    console.log(Person.prototype); // 输出: { constructor: [Function: Person] }
    

箭头函数的特殊性

  • 箭头函数(() => {})‌没有‌自己的 prototype 属性,因此不能通过 new 调用(即不能作为构造函数)。
  • 这是为了简化箭头函数的用途(通常用于函数式编程或需要绑定 this 的场景)。
  • const ArrowFunc = () => {};
    console.log(ArrowFunc.prototype); // 输出: undefined
    

原型对象干嘛的?

        ----共享属性和方法的

3、构造函数与原型

函数的 prototype 属性会在通过new创建实例时,自动成为实例的原型对象。

function Person(name) {this.name = name;
}// 向构造函数的原型添加方法
Person.prototype.sayHi = function() { console.log(`Hi, I'm ${this.name}`);
};const john = new Person("John"); // 1. new Person()时,实例的[[Prototype]] 指向Person.prototype。所有实例共享Person.prototype上的方法,节省内存。
john.sayHi(); // "Hi, I'm John"(方法来自原型)// 检测原型关系的方法
john instanceof Constructor:检查构造函数是否在原型链上。
Person.prototype.isPrototypeOf(john):检查对象是否在原型链中。
Person.getPrototypeOf(john):获取对象的原型。

现代替代方案(ES6+)

// class本质‌:语法糖,底层仍是原型继承。
class Animal {constructor(name) {this.name = name;}speak() {console.log(`${this.name} makes a noise.`);}
}class Dog extends Animal { // extends‌:通过Object.setPrototypeOf(Child.prototype, Parent.prototype)实现。speak() {console.log(`${this.name} barks.`);}
}const dog = new Dog("Rex");
dog.speak(); // "Rex barks."(方法覆盖)

    4、打个现实比方解释  原型 Prototype、原型链

    原型(Prototype)——「家族遗传(家族基因库)」

    原型链(Prototype Chain)——「家族族谱」

    现代家族(ES6 Class)——「家规手册」

    4.1 原型(Prototype)——「家族遗传(家族基因库)」

    想象你出生在一个家族,你的‌原型‌就是你的父母。父母有一些共同特征(比如眼睛颜色、身高基因),这些特征你天生就会继承:

    // 父母的特性(原型对象)
    const parent = {eyeColor: "brown",sayHello() { console.log("Hello!"); }
    };// 你继承了父母的特性
    const child = Object.create(parent); 
    console.log(child.eyeColor); // "brown"(继承自父母)
    child.sayHello();           // "Hello!"(调用父母的方法)
    
    4.2  原型链(Prototype Chain)——「家族族谱」

    现在扩展到你整个家族的血脉传承:

    // 曾祖父
    const greatGrandpa = { familyName: "Smith" };// 祖父继承了曾祖父
    const grandpa = Object.create(greatGrandpa);
    grandpa.hobby = "fishing";// 父亲继承了祖父
    const father = Object.create(grandpa);
    father.job = "engineer";// 你继承了父亲
    const you = Object.create(father);
    you.name = "Alice";console.log(you.familyName); // "Smith"(曾祖父的姓氏)
    console.log(you.hobby);      // "fishing"(祖父的爱好)
    
    • 查找过程‌(原型链):
      当你访问you.familyName时,JavaScript会按顺序查找:

      1. 你自己(you)→ 没有
      2. 父亲(father)→ 没有
      3. 祖父(grandpa)→ 没有
      4. 曾祖父(greatGrandpa)→ 找到!返回"Smith"
    • 终止条件‌:如果查到族谱顶端(Object.prototype)还没有,返回undefined

    4.3  特殊案例——「DNA突变」

    如果你自己定义了和原型相同的属性,会覆盖继承的属性(类似「基因突变」):

    const parent = { trait: "kind" };
    const child = Object.create(parent);
    child.trait = "brave"; // 覆盖原型属性console.log(child.trait); // "brave"(优先用自己的)
    
    4.4  现代家族(ES6 Class)——「家规手册」

    ES6的class相当于把家族继承规则写成了明确的手册:

    class Family {constructor(lastName) {this.lastName = lastName; // 家族姓氏}sayMotto() { console.log("Family first!"); }
    }// 你的分支家族
    class You extends Family {constructor(lastName, name) {super(lastName); // 必须调用父类构造方法this.name = name;}
    }const you = new You("Smith", "Alice");
    you.sayMotto(); // "Family first!"(继承自Family原型)
    
    总结比喻
    • 原型‌ = 直接父母(提供默认属性和方法)
    • 原型链‌ = 整个家族族谱(逐级向上查找特征)
    • 属性查找‌ = 问遍全家族,直到找到答案或确认没有(null
    • 修改原型‌ = 父母学新技能,子女自动受益
    • 覆盖属性‌ = 你决定特立独行,不跟父母一样
    // 构造函数(家族)
    function Family(lastName) {this.lastName = lastName; // 实例独有的属性(如名字)
    }// 基因库(prototype)
    Family.prototype = {familyName: "Smith", // 所有实例共享的姓氏sayMotto() {console.log(`${this.lastName} family: Family first!`);},tradition: "Annual picnic" // 共享的家族传统
    };// 创建实例(后代子孙)
    const alice = new Family("Alice");
    const bob = new Family("Bob");// 实例共享基因库中的属性和方法
    console.log(alice.familyName); // "Smith"(来自基因库)
    console.log(bob.familyName);  // "Smith"(同一个基因库)
    alice.sayMotto();             // "Alice family: Family first!"(共享方法)
    bob.sayMotto();              // "Bob family: Family first!"(共享方法)// 修改基因库会影响所有实例
    Family.prototype.tradition = "Monthly hiking";
    console.log(alice.tradition); // "Monthly hiking"(所有实例同步更新)
    
    关键点‌:
    1. 共享性‌:Family.prototype 上的属性和方法会被所有实例共享,避免重复定义。
    2. 动态性‌:修改 prototype 会影响所有现有和未来的实例(类似基因库升级)。
    3. 关联性‌:实例通过内部 [[Prototype]] 属性(__proto__)指向 prototype 对象。

     prototype 与 __proto__ 的关系——「基因库的访问路径」
    • prototype‌:构造函数独有的属性,指向基因库(原型对象)。
    • __proto__‌:实例对象的内部属性,指向构造函数的 prototype 对象(即基因库)。

    类比家族‌:

    • prototype 是‌家族基因库的实体‌(由构造函数保管)。
    • __proto__ 是‌子孙后代手中的钥匙‌,指向基因库的位置。
    function Family() {}
    const alice = new Family(); // 创建子孙后代console.log(alice.__proto__ === Family.prototype); // true
    // 实际关系:alice → [__proto__] → Family.prototype(基因库)
    
    • prototype‌ = 家族的‌基因库‌(存储所有后代共享的属性和方法)。
    • 构造函数‌ = 家族的‌族谱登记处‌,负责为每个新成员关联基因库。
    • 实例‌ = 家族的‌后代个体‌,通过 __proto__ 指向基因库,继承共享特性。
    • 原型链‌ = 从个体到基因库再到祖先基因库的‌查找路径‌,实现属性继承。

      5、打比方解释 constructorprototype 和 __proto__ 的关系

       用一个 ‌公司组织架构‌ 的比喻来解释 constructorprototype 和 __proto__ 的关系,通俗易懂:

      比喻场景:一家科技公司(JavaScript 对象系统)

      1. constructor → 部门经理

        • 比如公司有个「前端开发部」,部门经理是 Person()(构造函数)。
        • 他的职责是 ‌招聘新员工‌(new Person() 创建实例)。
        • 每个员工的名牌上会写:「直属领导:Person()」(即实例的 constructor 属性指向构造函数)。
      2. prototype → 部门共享资源库(上述比方中的 家族基因库)

        • 经理 Person() 有一个 ‌公共文件柜‌(Person.prototype)。
        • 里面放了部门通用的工具,比如《代码规范手册》(共享方法如 greet())。
        • 所有员工都可以用‌,但不需要每人复印一份(节省内存)。
      3. __proto__ → 员工的权限卡

        • 新员工 alice 入职时,会拿到一张权限卡(alice.__proto__)。
        • 刷卡后,她能访问 ‌公共文件柜‌(Person.prototype)里的资源。
        • 如果她需要工具,先找自己的工位(实例属性),找不到就刷卡去文件柜找(原型链查找)。

      关键互动流程:

      • 招人‌:new Person() → 经理 Person() 招了一个新员工 alice
      • 发权限卡‌:alice.__proto__ = Person.prototype(员工默认能访问部门资源)。
      • 查资料‌:
        • alice.greet() → 先看自己工位有没有 greet,没有 → 刷卡(__proto__)去文件柜(prototype)找。
        • 如果文件柜也没有,会去总公司(Object.prototype)找,最后没找到就报错。

      一句话总结:

      • constructor‌:谁创造了我?(构造函数)
      • prototype‌:我的共享资源库在哪?(构造函数的公共存储)
      • __proto__‌:我的权限能访问哪些资源?(实例的原型链入口)

      6、拓展:Object.create() 和 new 的区别

      6.1  ‌核心作用不同‌
      • Object.create()
        用于‌基于现有对象创建新对象‌,并可指定新对象的原型链(即设置 [[Prototype]])。

      const parent = { name: 'Parent' };
      const child = Object.create(parent); // child 的原型是 parent
      console.log(child.name); // 输出 "Parent"(继承自原型)
      
      • new

      用于‌调用构造函数创建对象‌,同时绑定 this 到新对象,并返回该对象(若构造函数无显式返回值)。
       

      function Person(name) {this.name = name;
      }
      const person = new Person('Alice'); // 调用构造函数创建实例
      console.log(person.name); // 输出 "Alice"
      
      6.2  原型链机制差异
      • Object.create()
        直接通过参数指定新对象的原型([[Prototype]]),更灵活但需手动管理属性(需后续赋值或通过属性描述符)。
         

        const obj = Object.create(null); // 无原型链的对象(常用于纯净字典)
        obj.key = 'value'; // 手动添加属性
        
      • new
        依赖构造函数的 prototype 属性作为新对象的原型,隐式绑定 this,代码更简洁但需遵循构造函数模式。
         

        function Car() {}
        Car.prototype.drive = function() { console.log('Driving...'); };
        const myCar = new Car();
        myCar.drive(); // 输出 "Driving..."(继承自原型)
        

      7、拓展:new操作符都干了什么?

      1. 创建⼀个新对象
      2. 新对象原型指向构造函数原型对象
      3. 将构建函数的this指向新对象 
      4. 根据返回值判断 

      function mynew(Func, ...args) {// 1.创建⼀个新对象
      const obj = {} // 2.新对象原型指向构造函数原型对象obj.__proto__ = Func.prototype // 3.将构建函数的this指向新对象 let result = Func.apply(obj, args) // 4.根据返回值判断 return result instanceof Object ? result : obj 
      }

      测试一下:

      function mynew(func, ...args) { const obj = {}obj. __proto__ = func.prototype let result = func.apply(obj, args)return result instanceof Object ? result : obj 
      } function Person(name, age) { this.name = name; this.age = age; 
      } Person.prototype.say = function () { console.log(this.name) 
      } 
      let p = mynew(Person, "huihui", 123)
      console.log(p) // Person {name: "huihui", age: 123} 
      p.say() // huihui

      相关文章:

    • 2018~2025:英伟达在具身智能机器人领域的关键布局详解
    • Python备忘
    • 【51单片机】1. 基础点灯大师
    • blob分析、自动阈值
    • Oracle数据库学习笔记 - 创建、备份和恢复
    • 小牛电动NXT,市场销量第一
    • SpringBoot整合RocketMQ与客户端注意事项
    • 项目课题——基于NB-IoT的智能水表设计
    • PPHGNetV2源代码解析
    • Python训练营打卡 Day46
    • C# 日志管理功能代码
    • 浅谈python如何做接口自动化
    • Qt生成日志与以及捕获崩溃文件(mingw64位,winDbg)————附带详细解说
    • 第4天:RNN应用(心脏病预测)
    • python实战:如何对word文档的格式进行定制化排版
    • 每日八股文6.6
    • 多模态+空间智能:考拉悠然以AI+智慧灯杆,点亮城市治理新方式
    • 达梦DB操作记录
    • Splash动态渲染技术全解析:从基础到企业级应用(2025最新版)
    • 学习日记-day23-6.6
    • 做转运网站/浙江网络科技有限公司
    • java 网站开发 顺序/免费收录平台
    • 代理服务器地址怎么设置/百度关键词优化多久上首页
    • 如何对网站做镜像/360推广联盟
    • wordpress点击按钮复制文字内容/seo网站外链工具
    • 做婚恋网站要多少钱/优化大师win10