百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

不会js中原型、原型链与constructor到底是什么?

myzbx 2025-07-23 16:44 5 浏览

关注我:知码前端,获取更多前端知识~~~

前言

哇呀呀~我说寒山说哭 我带你出 我敬滴酒带你出 我欲成冰再也无退路 怎舍寒冰冰冻我心哭~~~

Hello,广大的前端小伙伴们,又到了写文章的时候,我们说一下在javascript中一个比较重要的知识点,也是一个比较难理解的知识点,可以这么说如果学javascript这门语言不学会这个知识,那只能说学的没点意思~~那我们来说一下到底要讲什么知识呢----原型

要讲原型我们得分几个点讲解一下:

  • 为什么要有原型
  • 原型是什么
  • 原型链是什么
  • __propo__、prototype、contstructor这三个属性是什么

该篇文章可能会比较长,也可能会比较难懂,希望小伙伴们耐心,多看几次,好好理解~相信大家一定会学会这个知识点。

为什么要有原型

我们知道js中对象是通过构造函数来创建是,有的小伙伴可能要开始怼了,我创建对象的时候就没有用构造函数:

// 我直接通过字面量的方法来创建一个对象,而没有构造函数
const person = {}
// 其实上面代码也可以写成下面的
const person = new Object()
// 这两个写法是等价的

那么我们通过构造函数来创建一个对象,就可以把对象的一些属性和方法直接写到函数里面:

function Person(name, age) {
  this.name = name
  this.age = age
}
const person = new Person('知码', 20)
console.log(person.name) // '知码'
console.log(person.age) // '知码'

这样写是没有问题的,但是会有一个缺点:用一个构造函数来创建的实例之间,无法共享属性。从而导致系统的资源浪费。我们对每个实例添加一个方法:sayHello

function Person(name, age) {
  this.name = name
  this.age = age
  this.sayHello = function () {
    console.log('hello,' + this.name)
  }
}
const person1 = new Person('知码', 20)
const person2 = new Person('前端', 30)
console.log(person1.sayHello === person2.sayHello) // false

上面代码创建的两个实例都有相同的属性:name、age、sayHello。对于name和age来说是可以的,各自一份。但对于sayHello这个方法,有会浪费系统资源,因为没有必要两个实例都有这个方法。换句话说,每个实例之间应该共享这个方法。

为了解决这个问题,js就提供了原型对象(prototype)这个对象。

原型是什么

原型就是一个对象,然后用prototype这个变量来引用。每个function函数在被创建的时候都会有这个属性。(这里注意一下,只有用function声明的函数才会有这个属性,而用箭头函数是没有的。)当函数被普通调用的时候,这个对象是没有什么作用的。但当函数被当成构造函数使用的时候,这个属性就是每个实例的原型对象。在这个对象上创建的属性和方法都可以在每个实例之间共享。如:

function Person(name, age) {
  this.name = name
  this.age = age
}
Person.prototype.address = '北京'
const person1 = new Person('知码', 20)
const person2 = new Person('前端', 30)
person1.address // '北京'
person2.address // '北京'
// 可以看出`address`这个属性可以被两个实例共享

// 如果改变了这个`address`值,那么每个对象也会改变
Person.prototype.address = '上海'
person1.address // '上海'
person2.address // '上海'

可能有的小伙伴会问了,没有在函数中定义address这个属性呀,为什么实例对象会访问到呢?

如果实例对象身上有某个属性或者方法,那么会优先调用自身的,如果在自身上没有找到,就会到原型对象上去找。

对于address我们确定是没有在函数内定义,但是在Person函数的原型上定义了,所以实例对象就会按上述规则去找,最终找到address这个属性了。

原型链是什么

上面说道原型就是一个对象,在javascript中每个对象都可以充当一个原型对象,而每个对象都有自己的原型对象。就这样:

对象---->原型对象---->原型对象上的原型对象----> ...---->Object.prototype---->null

最终会到Object上的原型对象。这就是原型链。原型链的尽头就是null

当某个对象要访问某个属性或者方法的时候,就会按这个链去找,如果自身或者从某个原型上找到了属性,就不会再继续往下查找,直接返回。如果都没有所有的原型对象都没有找到这个属性,就返回undefined。举个例子说一下:

function Person(name, age){
  this.name = name
  this.age = age
}
Person.prototype.address = '北京'
const person = new Person('知码', 20)
person.name // '知码'
person.address // '北京'
person.toString() // [object Object]
person.height // undefined
  • 对于name属性来说,每个实例都有这个属性,所以会访问到,不会去原型或者原型链上查找。
  • 对于address属性来说,自身是没有这个属性,就会去函数的原型对象上去找,结果找到了,就直接返回
  • 对于toString方法来说,自身上没有这个方法,构造函数的原型对象上也没有,直到查找到Object.protptype的原型对象上,结果找到了,就会执行这个方法。
  • 对于height这个属性来说找了所有的原型对象也没有找到,就返回undefined
  • 或许又有小伙伴要问了,对于实例对象来说,它怎么知道去原型对象上去查找自身没有的属性或者方法呢?或者说他是通过什么样的机制去查找呢?这就用到下面要说的__proro__、prototype、constructor这三者的关系了。

    __propo__、prototype、contstructor这三个属性是什么

    如果你能看这到里说明你对原型和原型链有一个比较客观的认识。接下来的内容可能比较难懂,再坚持一下

    __proto__

    __proto__是前后两个下划线_ _,不是一个整体的下划线。

    当我们在创建一个对象的时候,系统都会给这个对象创建一个额外的属性__proto__,这个属性就是指向的构造函数中的原型对象。它是实例对象独有的。所以通过它就能访问到了函数原型对象。

    function Person(name, age){
      this.name = name
      this.age = age
    }
    const person = new Person('知码', 20)
    person.__proto__ === Person.prototype // true
    //两者都是指向同一个对象

    prototype

    前面也提过这个属性,它是function函数独有的。指向一个对象。

    constructor

    这个属性是prototype对象的一个属性,也就是说每个函数原型对象默认都会有这个属性,它指向了构造函数本身。

    用一个句话描述一下这三个对象之间的关系:

    每个实例对象都有__proto__属性,指向着构造函数的原型对象prototype,prototype对象里面有一个属性constructor属性,指向着构造函数本身。

    好了,今天先介绍这么多,下节我们细说下这三个属性。

    关注我:知码前端,获取更多前端知识~~~

    相关推荐

    下一代EUV光刻机,万事俱备?(下一代光刻技术)

    光刻机在半导体领域一向是个热门话题,这个能一次又一次突破工艺极限的设备仿佛一个时光机器,连接着芯片的现在和未来。从ASML宣布将推出下一代光刻机开始,人们的目光就从当前最新一代的0.33NA光刻系...

    鸿蒙NEXT-状态管理V1和状态管理V2的差别

    1.在V2中没有了@Link,来进行父组件和子组件的双向绑定。所以我们需要在子组件中通过@Event,调用父组件的事件,来实现装饰回调(白话来讲就是:子组件调用@Event装饰的函数,传入参数,修改父...

    15个Excel工作表技巧,效率必备,办公必备

    在数据的统计分析中,最常用的办公软件就是Office中的Excel,如果你对Excel的应用技巧掌握较少,可以从学习本文开始。一、Excel工作表技巧:锁定标题行方法:将光标定位到标题行下面的任意单...

    苹果这个新的稳定平台适合用户/开发者测试

    苹果好低调地就发布了这个平台,还好我们没有错过。从今天起你将有一种新的、更简便的方式去了解,Safari和其他使用Webkit的应用中将有什么特性和完善。SafariTechnologyPr...

    教程|PPT绘制箭头最全攻略,收藏一下

    微信公众号:有宝物的柜子编辑:落水无波2020-05-02原创由于没有较好的方向,公众号的更新一直暂停,根据昨天的留言,今天更新一篇关于绘制各类箭头的PPT教程,希望帮到需要的同学。那么,我们从最简...

    老板让我制作动态图表,我不会,同事说用vlookup函数3步就搞定了

    大家好,动态图表你会制作吗?是不是觉得动态图表制作起来应该非常的麻烦?其实并不是,大家熟悉的vlookup函数就可以用来制作动态图表,操作也非常的简单,下面就让我们来一起操作下吧COLUMN函数在这里...

    ES6(ECMAScript 2015)主要特性一览

    下面按“语法糖”“新数据类型/API”“异步&迭代”三大类,总结ES6的核心要点。---##一、语法糖-块级作用域:`let`、`const`-`let`:声明块级变量,不可...

    Excel工作表中F1—F12应用技巧解读,再不会就Out了

    键盘中,有一组非常显眼的功能键,就是F1—F12,其功能非常的强大,在Excel工作表中也有特别重要的作用,通过本文的学习,相信你一定有所了解。一、Excel工作表功能键:F1。功能:打开帮助对话框...

    es6的模块和核心语法(es6模块化的语法)

    目标:通过本教案,将掌握ES6的核心语法和模块化概念,理解解构表达式的用法,并初步了解Node.js的使用,为学习Vue3打下坚实的基础。学习内容:ES6核心语法模块化解构表达式Nod...

    ECMAScript标准制定过程展示及ES7新特性披露

    2015年6正式发布的ES6是ECMAScript的最新版本,它的发布具有里程碑意义,不仅带来了众多的新特性,而且自此将改变ECMAScript的发布策略。本文将会介绍ECMAScript标准的最新...

    冲激函数的理解(冲激函数的性质有哪些问题)

    一、冲激函数是什么?1.通俗理解想象一根理想化的针:长度无限小(宽度为0)高度无限大(强度无限)但总面积(能量)=1这就是冲激函数δ(t)!类比:用针尖瞬间触碰水面→产生一个无限高但宽度为...

    前端常见面试 - 请求篇(前端面试经典问题)

    对于前端来说,请求是前端日常工作必备的,通过请求才能与后端进行数据交互,尤其在现在前后端分离的开发模式下,请求显得就更加重要。因此,对于前端开发者来说,掌握请求就很重要。下面将从http请求和常见...

    不会js中原型、原型链与constructor到底是什么?

    关注我:知码前端,获取更多前端知识~~~前言哇呀呀~我说寒山说哭我带你出我敬滴酒带你出我欲成冰再也无退路怎舍寒冰冰冻我心哭~~~Hello,广大的前端小伙伴们,又到了写文章的时候,我们说一下在...

    你真的懂js的执行上下文吗?(详细说明js的执行过程)

    JavaScript执行上下文目录JavaScript执行上下文前言概念执行上下文的特点JS如何管理多个执行上下文执行栈执行上下文的生命周期创建阶段ThisBinding词法环境变量环境执行阶段销...

    停止滥用箭头函数:这5个场景请务必使用 function

    自ES6问世以来,箭头函数(ArrowFunctions)以其简洁的语法和对this的词法绑定,迅速成为了JavaScript开发者的“新宠”。我们似乎倾向于在任何可以使用函数的地方都换...