魔幻代码之舞:探秘JavaScript原型的奇妙世界

1.前言

我们要探索 JavaScript 中的一个超酷的技术------原型。原型是编程中的一种强大工具,它能让你的代码更加高效和精巧。

想象一下,原型就像是编程的蓝图,可以帮助我们构建出更强大的对象。通过了解原型,我们能够更深入地理解 JavaScript 中的对象结构,让我们的代码变得更为优雅和可维护。

在这个学习之旅中,我们将深入了解原型的概念,探索如何利用原型链创建更灵活的代码结构。这并不是什么神秘的技巧,而是实实在在的编程智慧,能够让你的代码更加强大和高效。

2.原型的概念

2.1 函数的原型(显式原型、原型对象)

在 JavaScript 中,每个函数都有一个特殊的属性,称为 prototype。这个 prototype 是一个对象,它包含了一个指向原型对象的引用。

原型是函数天生就具有的属性。它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以隐式继承到原型上的属性和方法。

js 复制代码
function myFunction() {
  // 函数体
}

console.log(myFunction.prototype); // 输出: {}

这里,myFunction.prototype 就是 myFunction 函数的显示原型。

显示原型的作用

函数的原型对象是一个普通的对象,但它对于实现继承和共享属性和方法至关重要。让我们看看它的作用:

1.继承

当你创建一个对象实例时,它会继承其构造函数的原型。这样,通过原型链,实例可以访问原型对象中定义的属性和方法。

js 复制代码
function Person(name) {
  this.name = name
}

Person.prototype.sayHello = function() {
  console.log(`Hello, I'm ${this.name}`)
}

let person1 = new Person('dante')
person1.sayHello(); // 输出:Hello, I'm dante

2 共享属性和方法

所有通过相同构造函数创建的实例都共享同一个原型对象。这意味着,如果你修改了原型对象,所有实例都会受到影响。

js 复制代码
Person.prototype.age = 18;

console.log(person1.age); // 输出: 18

let person2 = new Person('dante');
console.log(person2.age); // 输出: 18

prototype 与 proto

要注意 prototype 是函数特有的属性,而 __proto__ 则是实例对象特有的属性。__proto__ 指向其构造函数的原型对象。

js 复制代码
console.log(person1.__proto__ === Person.prototype); // 输出: true

虽然 __proto__ 是一种访问原型链的方式,但并不推荐使用,因为它不是标准的 JavaScript API。推荐使用 Object.getPrototypeOf() 方法来获取对象的原型。

js 复制代码
console.log(Object.getPrototypeOf(person1) === Person.prototype); // 输出: true

构造函数的 prototype

构造函数本身也有一个 prototype 属性,它与实例的 __proto__ 指向同一个对象。这个构造函数的 prototype 用于定义实例对象的原型。

js 复制代码
console.log(Person.prototype === myFunction.prototype); // 输出: true

函数原型在 JavaScript 中扮演着重要的角色,它通过原型链实现了继承和共享属性和方法的机制。深入理解函数原型有助于更好地利用 JavaScript 中的面向对象编程特性。

2.2对象的原型(隐式原型)

在 JavaScript 中,每个对象都有一个原型。原型可以看作是对象的父对象,它包含了对象共享的属性和方法。当我们访问一个对象的属性或方法时,JavaScript 引擎会首先在对象本身查找,如果找不到,就会去原型中查找。

现在我们通过具体的代码来了解什么是对象原型,使用构造函数是一种创建对象的常见方式。构造函数可以看作是一种特殊的函数,通过 new 关键字调用时,它会创建一个新的对象,并将该对象的原型指向构造函数的原型。

js 复制代码
Person.prototype.say = function (){
  return this.name + '今年' + this.age + '岁了'
}
function Person(){
  this.name = 'dante'
  this.age = 18
}
const p = new Person()
console.log(p) // Person {name: 'dante', age: 18}
console.log(p.say()) //dante今年18岁了

从上面的代码,我们可以看到,Person构造函数中并没有say()这样一个方法,但是为什么实例p可以访问say这个方法呢?这就是在创建实例p的时候,p继承了构造函数Person的显式原型中的方法,在js引擎查找这个say()方法时,首先在实例p中查找say,没有就会在p的原型上查找,刚好,实例p的原型继承了构造函数Person中的属性和方法。我总结了以下两点:

  1. 当访问对象属性时,先找对象显式具有的属性,没找到再去找对象的隐式原型。

  2. 实例对象的隐式原型 === 构造函数的显式原型

2.3原型链

从上面我们了解到了函数的显式原型和对象的隐式原型吗,明白了这两个概念,原型链就很好解决了,那什么是原型链呢?

当一个对象中的方法被调用执行时,引擎查找的时候首先会查找对象的显式具有的属性,没有,就会在对象原型中去查找,若还没有找到,就会继续向构造该对象的构造函数的显式原型中查找,还未找到,继续向上一层查找,一直到null。

顺着对象的隐式原型不断地向上查找上一级的隐式原型,直到找到目标或者一直到null,这种查找关系叫做原型链

3.所有的对象都有隐式原型吗?

了解了对象原型,那我们来思考这个问题,所有的对象都有隐式原型吗?文章读到这里,好像这句话说的非常的正确。 但是有一个特例,通过Object.create(null)创建的对象是没有隐式原型的。

js 复制代码
 //  Object.create()
  let obj = {
    a:1
  }
  let obj2 = Object.create(null)

  console.log(obj)
  console.log(obj2)

上面是在浏览器上打印obj的结果,是有Prototype的,而下方是打印obj2的结果,没有Prototype

Object.create(null) 创建的对象之所以为空(即没有原型链上的属性和方法),是因为它的原型被显式地设置为 null

在 JavaScript 中,Object.create() 方法接受一个参数,用于指定新创建对象的原型。当你传入 null 作为参数时,创建的对象将没有原型链,也就是说它不继承任何属性或方法。

示例:

js 复制代码
const emptyObject = Object.create(null);

console.log(emptyObject.toString); // 输出: undefined
console.log(emptyObject instanceof Object); // 输出: false

在这个例子中,emptyObject 被创建为一个空对象,它不具备任何继承的属性或方法。toString 属性为 undefined,而且它不是 Object 的实例,因为它没有原型链。

通常,这种操作被用于创建一个"纯净"的、不继承任何属性或方法的对象,以防止不必要的属性干扰。这样的对象可以用于一些特定的用途,比如作为映射(Map)的初始值,因为它不会受到原型链上其他属性的影响。

4. 总结

函数原型和对象原型共同构成了 JavaScript 中强大的原型链系统。它们通过原型链的连接关系,实现了继承、属性共享,为 JavaScript 提供了灵活且强大的面向对象编程能力。深入理解这两个概念,可以帮助你更好地设计和组织代码,使其更具可维护性和可扩展性。

相关推荐
阿伟来咯~5 分钟前
记录学习react的一些内容
javascript·学习·react.js
吕彬-前端10 分钟前
使用vite+react+ts+Ant Design开发后台管理项目(五)
前端·javascript·react.js
学前端的小朱13 分钟前
Redux的简介及其在React中的应用
前端·javascript·react.js·redux·store
guai_guai_guai22 分钟前
uniapp
前端·javascript·vue.js·uni-app
也无晴也无风雨23 分钟前
在JS中, 0 == [0] 吗
开发语言·javascript
bysking1 小时前
【前端-组件】定义行分组的表格表单实现-bysking
前端·react.js
王哲晓2 小时前
第三十章 章节练习商品列表组件封装
前端·javascript·vue.js
fg_4112 小时前
无网络安装ionic和运行
前端·npm
理想不理想v2 小时前
‌Vue 3相比Vue 2的主要改进‌?
前端·javascript·vue.js·面试
酷酷的阿云2 小时前
不用ECharts!从0到1徒手撸一个Vue3柱状图
前端·javascript·vue.js