深入理解 JavaScript 中的原型与对象

深入理解 JavaScript 中的原型与对象

在 JavaScript 中,原型是一项强大的概念,贯穿于对象创建、继承、和属性访问的方方面面。本文将深入讨论原型及相关概念,从显式原型、隐式原型到原型链,为你揭示 JavaScript 中这个核心特性的奥秘。

javascript 复制代码
function Person() {
    this.name = '小明'
    this.age = 18
}
Person.eat = function() {
    console.log('想吃面条')
}

let p = new Person()
let p2 = new Person()
console.log(p === p2)//false

以上代码中,构造函数 Preson,当我们new了两个Person,得到两个对象。在之前的学习中,我们知道了函数是引用类型,存在于堆中,当我们拿到它,其实是拿到了它在堆中的地址。按理说第11行语句的结果是true才对,说明,每new一次得到的对象都是新的对象。

第5行代码我们可以看到,我们往Person挂了一个eat属性(函数也是对象),执行Person.eat()是可以调用的,但当我们去查看new出来的Person对象时发现它并不在里面,也就是说,p.eat()是会报错的。(我的浏览器没有识别出 '小明' -.-')我们如何去解决这个问题呢?往下看

1. 显式原型

1.1 定义

在 JavaScript 中,每个函数都有一个特殊的属性,称为 prototype。这个属性定义了由该函数创建的对象的公共祖先。通过该构造函数创建的对象,可以隐式地继承这个原型上的属性和方法。

1.2 意义

显式原型允许我们将共享的属性和方法定义在一个地方,从而简化代码。所有由同一构造函数创建的对象,都共享一个原型,节省内存并使代码更加可维护。

1.3 原型上的属性修改

需要注意的是,原型上的属性修改只能由原型自己操作,实例对象无权修改。这一点对于理解 JavaScript 的继承机制至关重要。

2. 隐式原型

2.1 定义

对象原型,通常称为隐式原型,是实例对象的 __proto__ 属性,指向构造函数的显式原型。

2.2 关系

实例对象的隐式原型与构造函数的显式原型相互关联。通过这种关系,实例对象可以访问构造函数原型上的属性和方法。

ini 复制代码
<script>
    //Car.prototype.name = 'BMW'
    //Car.prototype.lang = 4900
    //Car.prototype.height = 1400
    Car.prototype = {
        name: 'BMW',
        lang: 4900,
        height: 1400
    }

    function Car(owner, color) {
        // this.name = 'BMW'
        // this.lang = 4900
        // this.height = 1400
        this.owner = owner
        this.color = color
    }

    let car = new Car('小帅', 'red')
    let car2 = new Car('小美', 'pink')

    console.log(car);
</script>

以上代码我们可以看到,Car.prototype这就是往这个构造函数的显示原型里添加属性。所以当我们new 一个Car时,它会隐式继承该原型的属性和方法。所以当我们要修改原型属性,也要通过该种方法

也就是说car.__proto__===Car.prototype

3. new 操作符

3.1 创建过程

使用 new 操作符创建对象的过程包含以下步骤:

  1. 创建一个空对象。
  2. 执行构造函数中的逻辑,将 this 绑定到新创建的对象上。
  3. 将新对象的隐式原型指向构造函数的显式原型。
  4. 返回新创建的对象。

new 操作符的机制保证了新对象与构造函数原型之间的正确关联。

4. 原型链

4.1 定义

原型链是由对象的隐式原型一级一级连接起来的链条。在属性访问时,JavaScript 引擎会沿着原型链向上查找,直到找到目标属性或者到达原型链的末端(null)。

4.2 每个对象都有一个隐式原型:

在 JavaScript 中,每个对象都有一个 __proto__ 属性,它指向该对象的原型。这个原型对象也是一个对象,并且它也有自己的 __proto__,形成了一条由对象连接而成的链,即原型链。

4.3. 原型链的顺序查找:

当你访问一个对象的属性时,如果对象本身没有这个属性,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或者到达原型链的末端(null)。

4.4. 原型链的形成:

原型链是通过对象的隐式原型一级一级连接起来的。一个对象的隐式原型指向构造函数的显式原型,而构造函数的显式原型也是一个对象,它的隐式原型又指向另一个构造函数的显式原型,依此类推,形成了原型链。

4.5. 构造函数和原型链:

每个构造函数都有一个显式原型对象,通过 prototype 属性访问。新创建的对象通过 new 操作符与构造函数关联,其隐式原型指向构造函数的显式原型。

下面是一个简单的例子来演示原型链:

javascript 复制代码
// 构造函数
function Animal(name) {
    this.name = name;
}

// 在构造函数的原型上添加方法
Animal.prototype.sayName = function() {
    console.log("My name is " + this.name);
};

// 创建实例对象
const myAnimal = new Animal("Leo");

// 访问实例对象的方法
myAnimal.sayName(); // 输出: My name is Leo

// 实例对象的隐式原型指向构造函数的显式原型
console.log(myAnimal.__proto__ === Animal.prototype); // 输出: true

// 构造函数的显式原型的隐式原型指向 Object 构造函数的显式原型
console.log(Animal.prototype.__proto__ === Object.prototype); // 输出: true

// Object 构造函数的显式原型的隐式原型是 null
console.log(Object.prototype.__proto__ === null); // 输出: true

在这个例子中,myAnimal 实例对象通过原型链可以访问到 sayName 方法,而原型链的末端是 null,表示查找到此处为止。

5. 网易面试题解析

5.1 所有对象都有隐式原型吗?

在 JavaScript 中,几乎所有的对象都有隐式原型,但有一种特殊情况例外。通过 Object.create(null) 创建的对象是没有隐式原型的。

javascript 复制代码
const obj = Object.create(null);

console.log(obj.__proto__); // 输出: undefined

在这个例子中,通过 Object.create(null) 创建的对象 obj 不继承任何属性和方法,它的隐式原型是 undefined,而不是指向标准的对象原型(Object.prototype)。

这种情况通常用于创建一个纯净的、不继承任何属性和方法的对象,可以完全按照你的需求定义其属性和方法。然而,这也意味着这个对象失去了一些 JavaScript 常规对象的特性,比如无法使用一些内置的方法和属性。因此,使用 Object.create(null) 需要慎重考虑,确保你真的需要一个没有原型链的对象。

结语

深刻理解原型、隐式原型、new 操作符和原型链是成为 JavaScript 高效开发者的关键。这些概念贯穿了 JavaScript 的对象模型,对于正确理解和利用这门语言至关重要。希望通过本文的讲解,读者能够更清晰地理解 JavaScript 中原型的精髓。

相关推荐
程序员猫哥_几秒前
HTML 生成网页工具推荐:从手写代码到 AI 自动生成网页的进化路径
前端·人工智能·html
龙飞051 分钟前
Systemd -systemctl - journalctl 速查表:服务管理 + 日志排障
linux·运维·前端·chrome·systemctl·journalctl
我爱加班、、6 分钟前
Websocket能携带token过去后端吗
前端·后端·websocket
AAA阿giao6 分钟前
从零拆解一个 React + TypeScript 的 TodoList:模块化、数据流与工程实践
前端·react.js·ui·typescript·前端框架
杨超越luckly12 分钟前
HTML应用指南:利用GET请求获取中国500强企业名单,揭秘企业增长、分化与转型的新常态
前端·数据库·html·可视化·中国500强
hedley(●'◡'●)42 分钟前
基于cesium和vue的大疆司空模仿程序
前端·javascript·vue.js·python·typescript·无人机
qq5_81151751544 分钟前
web城乡居民基本医疗信息管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
前端·vue.js·spring boot
百思可瑞教育1 小时前
构建自己的Vue UI组件库:从设计到发布
前端·javascript·vue.js·ui·百思可瑞教育·北京百思教育
百锦再1 小时前
Vue高阶知识:利用 defineModel 特性开发搜索组件组合
前端·vue.js·学习·flutter·typescript·前端框架
CappuccinoRose1 小时前
JavaScript 学习文档(二)
前端·javascript·学习·数据类型·运算符·箭头函数·变量声明