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

原型链(Prototype Chain)入门

原型链(Prototype Chain)概述

在 JavaScript 中,原型链是用于实现对象继承的机制。每个对象都有一个内部属性 [[Prototype]],它指向该对象的原型(在大多数现代 JavaScript 引擎中,通常通过 __proto__ 来访问)。原型链是由多个对象通过它们的原型链接在一起的链式结构,最终链的尽头指向 null

关键概念

  1. __proto__prototype 的区别

    • __proto__ 是指向当前对象的原型对象的内部属性。
    • prototype 是构造函数对象的属性,指向新实例的原型对象。
  2. 原型链的结构

    • 每个对象都有一个原型对象,原型对象本身也是一个对象,这个原型对象可能会有它自己的原型,这样就形成了一个链条,直到原型链的末端(通常是 Object.prototype)。
    • 通过原型链,JavaScript 对象可以继承其他对象的属性和方法。

详细解析

  1. 对象的 [[Prototype]] 属性(原型)
    每个 JavaScript 对象都有一个隐式的内部属性 [[Prototype]],它指向该对象的原型对象。你可以通过 __proto__ 来访问该属性。比如:

    const obj = {};
    console.log(obj.__proto__); // 输出 Object.prototype
    

    上述代码中的 obj 对象的原型是 Object.prototype,它是所有普通对象的根原型。

  2. prototype 属性
    prototype 是函数对象的一个特殊属性,它指向函数的原型对象。当你通过一个构造函数创建实例时,实例对象的 [[Prototype]] 会指向该构造函数的 prototype 属性。例如:

    function Person(name) {
        this.name = name;
    }
    
    const john = new Person('John');
    console.log(john.__proto__ === Person.prototype); // 输出 true
    

    在这个例子中,john 对象的 [[Prototype]] 指向 Person.prototype,即 Person 构造函数的 prototype 属性。

  3. 如何通过原型链访问属性和方法
    当你访问一个对象的属性时,JavaScript 会首先检查该对象自身是否有这个属性。如果没有,它会沿着原型链向上查找,直到找到该属性,或者到达原型链的末端(即 null)。

    例如:

    const person = {
        name: 'Alice',
        greet() {
            console.log('Hello, ' + this.name);
        }
    };
    
    const employee = Object.create(person);
    employee.job = 'Developer';
    
    employee.greet(); // 输出 "Hello, Alice"
    console.log(employee.job); // 输出 "Developer"
    

    在这个例子中,employee 对象没有自己的 greet 方法,但它通过原型链继承了 person 对象的 greet 方法。

  4. 原型链的查找机制
    JavaScript 对象的查找机制如下:

    • 当访问一个对象的属性时,JavaScript 会首先检查该对象本身是否包含该属性。
    • 如果对象本身没有该属性,JavaScript 会检查对象的原型(即 __proto__)。
    • 如果原型对象也没有该属性,查找会继续沿着原型链向上,直到达到 null,也就是 Object.prototype,此时如果还没有找到该属性,就会返回 undefined

    例如:

    const animal = {
        species: 'Animal',
        speak() {
            console.log('Animal makes a sound');
        }
    };
    
    const dog = Object.create(animal);
    dog.breed = 'Golden Retriever';
    
    console.log(dog.species);  // 输出 'Animal' 通过原型链继承
    dog.speak();  // 输出 'Animal makes a sound' 通过原型链继承
    console.log(dog.breed);  // 输出 'Golden Retriever' dog 对象自身的属性
    

    在上面的例子中,dog 对象有一个 breed 属性,但它没有 speciesspeak 属性。因此,它会查找 animal 对象的原型,找到了 speciesspeak

原型链的终点

原型链的终点通常是 Object.prototype,这是所有对象的根原型。Object.prototype[[Prototype]]null,它是原型链的最后一个对象。

const obj = {};
console.log(obj.__proto__); // 输出 Object.prototype
console.log(obj.__proto__.__proto__); // 输出 null

在 JavaScript 中,__proto__prototype 是两个密切相关但作用不同的概念。它们都是用来描述对象之间继承关系的,但它们分别处于不同的层次和使用场景。理解它们的区别有助于更好地掌握 JavaScript 中的原型链和继承机制。

prototype__proto__ 的区别

1. prototype 是构造函数的属性
  • 作用prototype 是每个构造函数(函数对象)上的一个属性,它指向该构造函数的原型对象。这个原型对象上通常会定义一些方法或属性,所有通过该构造函数创建的实例都会继承这些方法或属性。
  • 位置prototype 只存在于构造函数上,而不是实例对象上。

例子

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

const p1 = new Person("Alice");
p1.sayHello(); // "Hello, Alice"
  • 在上面的代码中,Person.prototype 是一个包含 sayHello 方法的对象,而 p1 这个实例通过其原型链访问到了 sayHello 方法。
2. __proto__ 是实例对象的属性
  • 作用__proto__ 是每个实例对象(由构造函数创建的对象)上的一个属性,它指向该对象的构造函数的 prototype。也就是说,__proto__ 是对象的原型链的一部分,指向对象原型的“父”对象(即构造函数的 prototype)。
  • 位置__proto__ 存在于对象实例上,用于表示实例与其构造函数的原型对象之间的关系。

例子

function Person(name) {
  this.name = name;
}

const p1 = new Person("Alice");
console.log(p1.__proto__ === Person.prototype); // true
  • 在这个例子中,p1.__proto__ 指向 Person.prototype,即 p1 实例继承自 Person.prototype

关键区别总结

  1. prototype 是构造函数的属性

    • 每个构造函数(如 Person)都会有一个 prototype 属性,这个属性指向构造函数的原型对象。该原型对象上可以定义方法和属性,所有通过该构造函数创建的实例会继承这些方法和属性。
    • 例如,Person.prototype.sayHello 就是 Person 的所有实例共享的方法。
  2. __proto__ 是实例对象的属性

    • 每个通过构造函数创建的实例对象(如 p1)都会有一个 __proto__ 属性,这个属性指向实例的构造函数的 prototype。也就是说,p1.__proto__ 指向 Person.prototype
    • __proto__ 表示对象的原型链关系,它是实例对象访问其构造函数原型对象的桥梁。

更深一步:原型链

  • 当你访问一个对象的属性或方法时,JavaScript 会先检查对象本身是否有这个属性。如果没有,它会沿着对象的 __proto__ 链查找,直到找到该属性或到达 Object.prototype 为止。

  • 对象实例通过 __proto__ 链接到构造函数的 prototype,而构造函数的 prototype 又指向 Object.prototype,从而形成了一个原型链。

function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function() {
  console.log("Hello, " + this.name);
};

const p1 = new Person("Alice");
console.log(p1.__proto__ === Person.prototype);  // true
console.log(p1.__proto__.__proto__ === Object.prototype);  // true
  • 在这个例子中:
    • p1.__proto__ 指向 Person.prototype
    • Person.prototype.__proto__ 指向 Object.prototype
    • 如果在 p1 上找不到 sayHello 方法,JavaScript 会继续沿着原型链查找,直到 Object.prototype

prototype__proto__ 之间的联系

  • prototype 是构造函数上用来设置实例对象原型的属性。
  • __proto__ 是实例对象用来访问构造函数原型的属性。

prototype__proto__ 共同组成了原型链(prototype chain)。实例对象通过 __proto__ 链接到构造函数的 prototype,而构造函数的 prototype 上定义的方法和属性被实例继承。

小结

总结

  • 原型链 是 JavaScript 对象继承和属性查找的机制,允许一个对象通过其原型继承另一个对象的属性和方法。
  • __proto__ 是对象的原型对象,指向该对象的父对象。
  • prototype 是构造函数的属性,指向通过该构造函数创建的实例对象的原型。
  • 查找一个对象的属性时,JavaScript 会沿着原型链向上查找,直到找到该属性或者原型链的终点 null
  • prototype构造函数的属性,定义了所有由该构造函数创建的实例共享的属性和方法。
  • __proto__实例对象的属性,指向构造函数的 prototype,通过它可以访问和查找实例对象的原型链上的属性和方法。

原型链是 JavaScript 中非常重要的特性,它使得继承、方法共享、属性访问等成为可能。


http://www.kler.cn/a/455086.html

相关文章:

  • UGUI简单动画制作
  • 深入理解Java虚拟机(JVM)
  • Java中处理if-else的几种高级方法
  • leetcode 27. 移除元素
  • python+requests接口自动化测试框架实例详解
  • 一键图片转3D模型,AI建模,一键把图片转三维模型,二维图片转3维模型,AI建模
  • ITK-基于itkUnaryFunctorImageFilter实现图像反转
  • PDF书籍《手写调用链监控APM系统-Java版》第1章 开篇介绍
  • 前端 学习
  • Alma linux部署gitlab
  • Java 中 List 源码解析:深度剖析与实现
  • 机器学习1-简单神经网络
  • Go主协程如何等其余协程完再操作
  • 废品回收小程序:助力企业转型发展
  • Vue3 +Element-Plus el-select下拉菜单样式(局部生效)
  • vue 中 keep-alive 详解
  • C# 窗体应用程序嵌套web网页,基于谷歌浏览器内核(含源码)
  • 《机器学习》——利用OpenCV库中的KNN算法进行图像识别
  • oracle数据泵expdp/impdp导出导入
  • 【C++第十六课 - C++11】列表初始化、右值引用、移动构造、移动赋值、lambda表达式
  • 大模型笔记!以LLAMA为例,快速入门LLM的推理过程
  • Vue异步处理、异步请求
  • 无人零售 4G 工业无线路由器赋能自助贩卖机高效运营
  • 【基础】卒的遍历(DFS)
  • dockfile 配置 /etc/apt/source.list.d/debian.list 清华镜像
  • 记录一个制作Fortran的docker镜像