快速掌握JavaScript原型与原型链

1. 构造函数

  • 什么是构造函数:主要用来初始化对象,即为对象成员变量赋初始值,与new一起使用。

  • 在构造函数中添加成员:

    • 实例成员:实例成员是属于类的每个实例(对象)的属性或方法。当你创建了类的一个实例时,实例成员将成为该实例的一部分。每个对象都有自己独立的实例成员。
      • (1)实例成员通常在构造函数中初始化

      • (2)实例成员通过类的实例来访问

        js 复制代码
           class Student {
             constructor(name, age) {
               // 实例成员
               this.name = name; // 每个对象都有自己独立的 name 属性
               this.age = age;   // 每个对象都有自己独立的 age 属性
             }
        
             // 实例方法
             sayHello() {
               console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
             }
           }
        
           const student1 = new Student("nini", 18);
           const student2 = new Student("zheng", 30);
        
           student1.sayHello(); // 输出:Hello, my name is nini and I'm 18 years old.
           student2.sayHello(); // 输出:Hello, my name is zheng and I'm 30 years old.
      • 静态成员:静态成员是属于类本身的属性或方法,而不是类的实例。静态成员不依赖于类的实例对象,它们可以直接通过类名来访问。静态成员对于所有实例是共享的,它们在内存中只有一份。

        • 静态成员不属于类的实例,而是属于类本身。

        • 静态成员通过类名直接访问。

        • 静态成员不能通过 this 来访问,它只能通过类名访问。

          js 复制代码
           class Car {
             constructor(make, model) {
               this.make = make;
               this.model = model;
             }
          
             // 实例方法
             displayInfo() {
               console.log(`${this.make} ${this.model}`);
             }
          
             // 静态方法
             static compareModels(car1, car2) {
               return car1.model === car2.model;
             }
           }
          
           const car1 = new Car("Tesla", "Model S");
           const car2 = new Car("Tesla", "Model X");
          
           console.log(Car.compareModels(car1, car2)); // 输出:false
        • 在上面的代码中,compareModels 是 Car 类的静态方法。不能通过实例 car1.compareModels()来调用它,而是必须通过类名来调用Car.compareModels(car1, car2)

      • 总结: 实例成员用于存储对象的特有数据,静态成员则用于存储与类本身相关的功能或常量。

  • 构造函数存在的问题:让每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费,浪费内存。

2. 什么是原型

  • 原型这个概念的诞生主要是为了解决构造函数存在一些问题。
  • 原型是什么:原型是一个对象,我们也称prototype为原型对象。
  • 原型的作用:共享方法。
  • 原型关系:
    • 每个class都有显示原型prototype

    • 每个实例都有隐式原型__proto__

    • 实例的__proto__指向对应class的prototype

      js 复制代码
       // class实际上是函数,可见是语法糖
       typeof Student // 'function'
       typeof People // 'function'
      
       // 隐式原型和显示原型
       console.log(nini.__proto__);
       console.log(Student.prototype);
       console.log(nini.__proto__ === Student.prototype); // true

3. 显式原型

  • 显示原型即构造函数中的prototype属性。
  • 每一个类的构造函数都有一个prototype属性。这个属性包含一个对象:prototype原型对象,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
  • 实例对象一旦创建,将自动引用prototype对象的属性和方法。只要修改了prototype对象,就会同时影响到多个实例对象。

4. 隐式原型

  • 隐式原型即实例中的__proto__属性。
  • 每一个实例都会有一个属性__proto__指向构造函数的prototype原型对象。
  • 之所以我们在实例中可以使用构造函数prototype原型对象的属性和方法,就是因为实例有__proto__原型的存在。__proto__对象原型和构造函数的原型对象prototype是等价的。
  • _proto__对象原型的意义就在于为对象的查找机制提供一个方向,实际开发中不可以使用这个属性,它只是内部指向原型对象prototype

5. 原型中的constructor属性

  • 隐式原型(proto)和显式原型(prototype)里面都有一个属性constructor属性,它指回构造函数本身。
  • constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
  • 注意:写法Student.prototype.doHomework=function(){} 等相当于在原型中添加方法,所以自动带有constructor。而写法Student.prototype={}是相当于修改了原型对象,覆盖了之前的所有,所以要自己手动添加constructor构造函数,否则是没有构造函数的。

6. 基于原型的执行规则 (JS的成员查找机制)

  • 当访问一个实例的属性(包括方法)时,首先查找这个对象自身有没有该属性(例如获取nini.name或者nini.sayHello()时)
  • 如果找不到,则自动去该实例(nini)的__proto__隐式原型中查找(也就是__proto__隐式原型指向的prototype显式原型)
  • 如果还没有找到,就查找这个显示原型的原型(Object原型对象)
  • 以此类推,一直找到Object为止(null)

总结:__proto__隐式原型的意义就在于为实例成员查找机制提供一个方向,或者说一条路线。

7. 原型链

  • 只要是实例,就有__proto__隐式原型,指向其类的构造函数的显示原型
  • 构造函数的显式原型prototype里面的__proto__隐式原型指向的是Object.prototype
  • Object.prototype显式原型里面的__proto__原型,指向为null

备注:instanceof:原理就是是否能找到某某的原型(即xxxxx.prototype),如果能找到就是true,找不到就是false

8. 扩展内置对象

  • 通过显式原型,对原来的内置对象进行扩展自定义的方法。
  • 比如给数组增加自定义求偶数和的功能:
    • 注意:数组和字符串内置对象不能给显示原型覆盖操作Array.prototype={},只能是Array.prototype.xxx=function(){}的方式。第一种方式会覆盖原先的内置方法。
相关推荐
Go_going_13 分钟前
【解决 el-table 树形数据更新后视图不刷新的问题】
前端·javascript·vue.js
wfsm25 分钟前
react使用01
前端·javascript·react.js
前端Hardy1 小时前
第4课:函数基础——JS的“魔法咒语”
前端·javascript
飞舞花下1 小时前
el-popover实现下拉滚动刷新
前端·javascript·vue.js
就是我1 小时前
使用React Developer Tools做性能分析
前端·javascript·react.js
海底火旺2 小时前
JavaScript 中 '+' 的隐式转换:你需要知道的 9 种魔法行为
前端·javascript·面试
什码情况2 小时前
JavaScript ?? 运算符详解
开发语言·前端·javascript
Mintopia2 小时前
向量基础学习:从概念到 JavaScript 实现
javascript·计算机视觉·计算机图形学
_NIXIAKF2 小时前
vue项目中axios统一或单独控制接口请求时间
前端·javascript·vue.js
前端Hardy2 小时前
第3课:运算符与流程控制——JS的“决策者”
javascript·面试