原型链(Prototype Chain)入门

原型链(Prototype Chain)概述

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

关键概念

  1. __proto__prototype 的区别

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

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

详细解析

  1. 对象的 [[Prototype]] 属性(原型)

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

    js 复制代码
    const obj = {};
    console.log(obj.__proto__); // 输出 Object.prototype

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

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

    js 复制代码
    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)。

    例如:

    js 复制代码
    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

    例如:

    js 复制代码
    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,它是原型链的最后一个对象。

js 复制代码
const obj = {};
console.log(obj.__proto__); // 输出 Object.prototype
console.log(obj.__proto__.__proto__); // 输出 null

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

prototype__proto__ 的区别

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

例子

js 复制代码
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__ 存在于对象实例上,用于表示实例与其构造函数的原型对象之间的关系。

例子

js 复制代码
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,从而形成了一个原型链。

js 复制代码
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 中非常重要的特性,它使得继承、方法共享、属性访问等成为可能。

相关推荐
m0_748244968 分钟前
VUE前端实现天爱滑块验证码--详细教程
前端·javascript·vue.js
NoneCoder1 小时前
CSS系列(26)-- 动画性能优化详解
前端·css·性能优化
滚雪球~1 小时前
@vue/cli启动异常:ENOENT: no such file or directory, scandir
前端·javascript·vue.js
GDAL1 小时前
vue3入门教程:ref函数
前端·vue.js·elementui
GISer_Jing1 小时前
Vue3状态管理——Pinia
前端·javascript·vue.js
萧寂1731 小时前
ios底部小横条高度适配
css
代码的乐趣1 小时前
支持selenium的chrome driver更新到131.0.6778.204
chrome·python·selenium
web150854159352 小时前
vue 集成 webrtc-streamer 播放视频流 - 解决阿里云内外网访问视频流问题
vue.js·阿里云·webrtc
路人甲ing..4 小时前
jupyter切换内核方法配置问题总结
chrome·python·jupyter
丰云4 小时前
一个简单封装的的nodejs缓存对象
缓存·node.js