构造函数和原型

本文详细介绍了构造函数的作用、new操作的四个步骤,探讨其内存占用问题,并对比了显式原型(prototype)与隐式原型(__proto__)。此外,讲解了如何通过原型链和hasOwnProperty/in检查属性,以及prototype与proto的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造函数

含义:

构造函数是一种特殊的函数,用来初始化对象,为对象成员变量赋初始值,与 new 一起使用。可以吧对象中的一些公共属性和方法抽取出来,然后封装到这个函数里面

new 在执行的时候做的四件事情
  1. 在内存中创建一个新的空对象
  2. 让this指向这个新的对象
  3. 执行构造函数里面的代码,给这个新对象添加属性和方法
  4. 返回这个新对象(所以构造函数里不需要return
构造函数的缺点

创建对象时,里面的方法(function是复杂数据类型)会在内存中重新开辟空间,也就是每一个实例对象都会开辟一块空间,存在浪费内存的问题。

代码示例
/*构造函数*/
function Person(sName,sPhone){
	this.name=sName
	this.phone=sPhone
	this.run=function(){
	console.log('奔跑');
}
}
			
// 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
 const p1 = new Person("张三", "15623233232");
 const p2 = new Person("李四", "17789899898");
			
console.log(p1.run===p2.run);//false,代表地址不同

通过构造函数创建的新对象实例是相互独立的,为新对象实例添加的方法只有该实例拥有这个方法,其它实例是没有这个方法的

/*构造函数*/
function Person(sName,sPhone){
	this.name=sName
	this.phone=sPhone
	this.run=function(){
	console.log('奔跑');
}
}
			
// 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
const p1 = new Person("张三", "15623233232");
const p2 = new Person("李四", "17789899898");
 // 为新对象实例添加方法
// 通过原型创建的新对象实例是相互独立的
p1.sayHello = function(){
  console.log("你好啊");
}
p1.sayHello() //你好啊
p2.sayHello() //报错
构造函数原型 prototype (显式原型)

1.函数才有prototype,prototype是一个对象,指向了当前构造函数的引用地址
2.这个原型对象 prototype 的所有属性和方法都会被构造函数所拥有。
3.我们可以把公共的方法,直接定义在 prototype 对象上, 这样所有对象的实例就可以共享这个方法了

代码示例
/*构造函数原型 prototype*/
function Person(sName,sPhone){
	this.name=sName
	this.phone=sPhone
	this.run=function(){
	console.log('奔跑');
 }
}
Person.prototype.run=function(){
 console.log('奔跑');
}
 // 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
const p1 = new Person("张三", "15623233232");
const p2 = new Person("李四", "17789899898");
console.log(p1.run===p2.run);//true,代表地址相同
对象原型 _proto_(隐式原型)

1.对象都有一个属性__proto__指向构造函数的 prototype 原型对象
2.之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有__proto__原型的存在
3.__proto__对象原型和原型对象 prototype 是等价的

代码示例
 console.log(p1.__proto__ === Person.prototype); //true
原型 constructor

原型 里有 constructor 这个属性,主要作用是告诉我们是由那个构造函数中创建出来的
如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数。
因为新添加的对象覆盖了原来构造函数的prototype对象

  function Person(sName,sPhone){
	this.name=sName
	this.phone=sPhone
	this.run=function(){
	console.log('奔跑');
}
}
Person.prototype = {
  constructor: Person,
  run: function () {
   console.log("奔跑");
},
  eat: function () {
    console.log("吃东西");
   },
};
      // 实例化创建新的原型对象,新的原型对象会共享原型的属性和方法
const p1 = new Person("张三", "15623233232");
const p2 = new Person("李四", "17789899898");
console.log(Person.prototype);
console.log(p1.__proto__);
查找规则(原型链)

首先看p1对象身上是否存在 run 方法,如果有就执行这个对象身上的 run ,如果没有,因为有__proto__的存在,就去构造函数原型对象prototype身上去查找这个 run 方法。
这样一层一层向上查找就会形成一个链式结构
在这里插入图片描述

检查对象自身是否含有某个属性的方法

1.hasOwnProperty

 let obj = {
    a: 5,
    b: 10,
  };
	
console.log("21", obj.hasOwnProperty("a"));

2 in

console.log('a' in obj)
prototype 和 proto 区别是什么?
  1. prototype是构造函数的属性
  2. __proto__是每个实例都有的属性,可以访问 [[prototype]] 属性
  3. 实例的__proto__与其构造函数的prototype指向的是同一个对象
<think>好的,我现在需要回答用户关于构造函数原型对象关系的问题。首先,我得回忆一下用户提供的引用内容,特别是引用[1]、[2]、[4],因为它们详细讨论了构造函数原型对象实例对象之间的联系。 用户的问题有两个部分:构造函数原型对象的关系,以及如何理解它们的关联。我需要确保回答覆盖这两个方面,并且结构清晰。根据引用,构造函数有一个prototype属性指向原型对象,而原型对象有一个constructor属性指回构造函数。这是一个相互引用的闭环关系。同时,实例对象通过__proto__属性连接到原型对象。 接下来,我需要用简单易懂的中文解释这些关系,避免使用过于专业的术语。可以分点说明,比如构造函数的prototype属性、原型对象的constructor属性、实例的__proto__属性,以及原型链的作用。这样用户能逐步理解每个部分的作用联系。 另外,用户提到的示例代码可能有助于说明问题。比如,引用[2]中的Person构造函数,可以举这个例子来说明原型对象如何存储方法,所有实例共享这些方法。这样可以突出原型对象在内存效率上的优势,避免每个实例重复创建方法。 还要注意引用用户提供的引用内容,在适当的地方添加引用标记,比如在提到构造函数原型对象相互指向时引用[1][4]。同时,确保回答符合系统级指令,如使用正确的LaTeX格式,虽然这个问题可能不需要数学公式,但如果有涉及变量或术语,可能需要用$符号包裹。 最后,生成相关问题时要围绕构造函数原型对象、原型链以及实际应用场景展开,帮助用户进一步学习。例如,如何访问原型对象的方法,原型链的作用,或者为什么共享方法更高效。 检查是否存在可能的错误,比如是否正确解释了constructor属性prototype属性的指向,是否混淆了__proto__prototype。根据引用[4],实例的__proto__指向构造函数的prototype,而构造函数的prototype属性指向原型对象,原型对象的constructor又指回构造函数。需要确保这些点准确无误。 总结回答的结构:先总述关系,再分点详细说明每个属性,接着用代码示例说明,最后总结关联。这样用户能够逐步理解,结构清晰。</think>### 构造函数原型对象的关系解析 #### 核心关系 构造函数通过`prototype`属性指向原型对象,原型对象通过`constructor`属性反向指向构造函数,两者形成闭环引用。实例对象通过`__proto__`属性关联到原型对象,构成原型链的基础[^1][^4]。 #### 分步说明 1. **构造函数的`prototype`属性** 每个构造函数(如`Person`)在创建时,系统会自动为其分配一个原型对象(即`Person.prototype`)。构造函数的`prototype`属性直接指向该原型对象。 例如: ```javascript function Person(name) { this.name = name; } console.log(Person.prototype); // 输出原型对象 ``` 2. **原型对象的`constructor`属性** 原型对象中有一个`constructor`属性,默认指向其关联的构造函数。这一设计使得可以通过原型反向追溯构造函数。 ```javascript console.log(Person.prototype.constructor === Person); // 输出true ``` 3. **实例对象的`__proto__`属性** 当通过`new`关键字创建实例时(如`const obj = new Person()`),实例的`__proto__`属性会自动指向构造函数原型对象。 ```javascript const obj = new Person("张三"); console.log(obj.__proto__ === Person.prototype); // 输出true ``` 4. **原型链的作用** 实例对象访问属性时,若自身不存在该属性,会通过`__proto__`逐级向上查找原型对象中的属性,形成原型链。这种机制实现了属性方法的共享[^2][^4]。 例如,若将方法定义在原型上: ```javascript Person.prototype.sayHello = function() { console.log("Hello!"); }; obj.sayHello(); // 调用原型方法 ``` #### 关联示意图 $$ \begin{aligned} &\text{构造函数} \xrightarrow{\text{prototype}} \text{原型对象} \\ &\text{原型对象} \xrightarrow{\text{constructor}} \text{构造函数} \\ &\text{实例对象} \xrightarrow{\text{__proto__}} \text{原型对象} \end{aligned} $$ #### 实际意义 - **共享方法,节省内存**:将公共方法定义在原型对象中,所有实例共享同一方法,避免重复创建[^2]。 - **实现继承**:通过原型链,子类可以访问父类原型中的属性方法[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值