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

对象、函数、原型之间的关系

在 JavaScript 中,对象函数原型 是三者紧密联系的核心概念。它们共同构成了 JavaScript 中面向对象编程的基石,并通过原型链实现了继承与代码复用。本文将从对象、函数、原型的基础概念到它们之间的关系进行详细的讲解,帮助你理解 JavaScript 的底层机制。

1. 什么是对象?

在 JavaScript 中,一切皆对象。对象是包含属性和方法的容器。属性可以是基本数据类型,如字符串、数字等;方法则是一个可以执行的函数。

var person = {
    name: "浮游",
    age: 20,
    greet: function() {
        console.log("Hello, I am " + this.name);
    }
};

console.log(person.name);  // 浮游
person.greet();  // Hello, I am 浮游

上面的 person 是一个对象,它包含了两个属性 nameage,以及一个方法 greet

2. 什么是函数?

JavaScript 中的函数实际上也是对象。与其他对象不同的是,函数对象可以被调用。此外,每个函数在创建时都会自动拥有两个属性:prototype__proto__

function Foo() {}
console.log(typeof Foo); // function
console.log(Foo instanceof Object); // true

可以看出,函数本质上是对象,具有对象的一些特性。同时,它们也有特殊的属性,方便实现继承与原型链机制。

函数的两大属性:
  • prototype:每个函数都有的属性,指向函数的原型对象,用于继承。
  • __proto__:指向创建该对象的构造函数的原型。

3. 什么是原型?

原型是实现继承的核心概念。每个 JavaScript 对象都有一个隐藏的属性 [[Prototype]],可以通过 __proto__ 来访问。原型是一个对象,它用于实现对象之间的属性和方法的共享。

3.1 原型对象 (prototype)

每个函数对象在创建时都会有一个 prototype 属性,该属性指向原型对象,而这个原型对象中包含了通过该函数创建的实例所共享的属性和方法。

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

// 向原型对象中添加方法
Person.prototype.greet = function() {
    console.log("Hello, I am " + this.name);
};

var person1 = new Person("浮游", 20);
var person2 = new Person("熠星", 24);

person1.greet();  // Hello, I am 浮游
person2.greet();  // Hello, I am 熠星

在上面的例子中,Person 函数有一个 prototype 属性,所有通过 Person 创建的对象 (person1person2) 都共享 prototype 中的 greet 方法。

3.2 隐式原型 (__proto__)

每个 JavaScript 对象都有一个 __proto__ 属性,指向其构造函数的原型。通过这个属性,对象可以继承构造函数原型上的属性和方法。__proto__ 是对象与原型之间的链接,形成了原型链。

console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // null, 原型链的顶端

person1 通过 __proto__ 链接到 Person.prototypePerson.prototype 又通过 __proto__ 链接到 Object.prototype,这就是 JavaScript 原型链的基础。

4. 对象、函数与原型的关系

JavaScript 是基于原型的语言,这意味着每个对象都从一个“原型”对象继承属性和方法。

  • 函数是对象:函数本身是一个对象,有 __proto__ 属性,它指向 Function.prototype
  • 对象有原型:每个对象都有一个 __proto__ 属性,它指向它的构造函数的 prototype
  • 原型链:通过 __proto__ 属性,对象可以访问其原型对象上的属性和方法。如果在自身对象中找不到某个属性,它会沿着原型链向上查找。
4.1 构造函数与实例对象的关系
function Car(model) {
    this.model = model;
}

Car.prototype.drive = function() {
    console.log(this.model + " is driving");
};

var car1 = new Car("Toyota");
var car2 = new Car("Honda");

car1.drive();  // Toyota is driving
car2.drive();  // Honda is driving

console.log(car1.__proto__ === Car.prototype);  // true
console.log(Car.prototype.constructor === Car);  // true
  • car1car2 是由构造函数 Car 创建的实例对象。
  • 它们的 __proto__ 属性都指向 Car.prototype
  • Car.prototype.constructor 指向 Car 构造函数本身。
4.2 原型链的查找机制

当你访问一个对象的属性时,JavaScript 引擎首先会在对象本身的属性中查找。如果找不到,它会沿着原型链在其原型对象上查找。这个过程会持续到原型链的顶端——Object.prototype

console.log(car1.toString()); // [object Object]

car1 并没有 toString 方法,但是它沿着原型链找到了 Object.prototype.toString,因此可以调用它。

5. 原型链

原型链是指对象通过 __proto__ 一直向上查找,直到找到 Object.prototype 为止。如果在整个原型链中没有找到该属性,则返回 undefined

console.log(car1.__proto__); // Car.prototype
console.log(car1.__proto__.__proto__); // Object.prototype
console.log(car1.__proto__.__proto__.__proto__); // null, 原型链的顶端

6. 总结

  • 对象:JavaScript 中的任何实体都是对象,它们可以有属性和方法。
  • 函数:JavaScript 中的函数也是对象,它们有额外的 prototype 属性,用于支持原型链和继承。
  • 原型:原型是对象的共享属性和方法的容器,通过原型链实现继承。每个对象都有一个 __proto__ 属性,指向它的构造函数的 prototype
对象、函数与原型的关系:
对象 --通过 __proto__ --> 构造函数的 prototype --通过 constructor--> 构造函数

通过这个关系,JavaScript 实现了灵活的继承机制,使得我们能够通过原型链实现对象的扩展和代码的复用。

7. 关键要点

  • 原型链是 JavaScript 继承机制的核心,通过它可以实现属性和方法的查找。
  • 每个函数都有一个 prototype 属性,指向它的原型对象,原型对象上的属性和方法可以被该构造函数的实例对象共享。
  • 每个对象都有一个 __proto__ 属性,指向它的构造函数的原型对象。
  • 原型链的终点是 Object.prototype,它是所有对象的最终原型。

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

相关文章:

  • 12.25周三F34-Day36打卡
  • VMware虚拟机中CentOS系统/dev/mapper/centos-home分区扩容指南
  • Django 模型中使用选择(choices):全面指南
  • 国标GB28181视频监控平台与Liveweb视频监控汇聚平台对接方案
  • Linux服务器端自动挂载存储设备(U盘、移动硬盘)
  • springboot/ssm私房菜定制上门服务系统Java代码编写web厨师上门做菜
  • 安装origin2025试用版(学生)
  • XlDynamicFilterCriteria 枚举 (Excel)
  • R语言数据分析案例46-不同区域教育情况回归分析和探索
  • Electron -- 预加载脚本preload.js(三)
  • 物联网系统中MQTT的概念建模方法
  • 打造高效租赁小程序让交易更便捷
  • 几个常见的Jmeter压测问题
  • lxml提取某个外层标签里的所有文本
  • Linux的mmap
  • 什么是领域驱动设计
  • [Unity] ShaderGraph动态修改Keyword Enum,实现不同效果一键切换
  • PaddlePaddle飞桨Linux系统Docker版安装
  • js的eval
  • Chromium GN 目标指南 - view_examples 自定义Button示例 (六)
  • 【es6复习笔记】let 和 const 命令(1)
  • Django models中的增删改查与MySQL SQL的对应关系
  • leetcode hot100 环形链表2
  • 深度学习环境安装
  • 内网穿透玩法之京东云亚瑟路由器刷神卓互联教程
  • 树莓集团:以产教融合助力人才培养