feat: 原型和原型链理解

master
LCJ-MinYa 5 days ago
parent 9385c44cc9
commit a27184c9bb

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@ -0,0 +1,143 @@
## constructor 属性的详细解释
### 基本概念
**constructor** 是原型对象上的一个属性,它指向创建当前实例对象的构造函数。
### 各层级的 constructor 指向
```
Person.prototype.constructor → Person
Function.prototype.constructor → Function
Object.prototype.constructor → Object
```
### 实际示例
```javascript
function Person(name) {
this.name = name;
}
const p1 = new Person("张三");
// 验证 constructor 指向
console.log(p1.constructor === Person); // true
console.log(Person.prototype.constructor === Person); // true
console.log(Function.prototype.constructor === Function); // true
console.log(Object.prototype.constructor === Object); // true
```
### 完整的 constructor 链式关系
```
p1.constructor → Person.prototype.constructor → Person
Person.constructor → Function.prototype.constructor → Function
Function.constructor → Function.prototype.constructor → Function
(Function 的构造函数是它自身)
Object.constructor → Function.prototype.constructor → Function
(Object 的构造函数是 Function)
```
### constructor 属性的工作原理
1. **原型继承机制**
```javascript
// 当访问 p1.constructor 时:
// 1. p1 对象本身没有 constructor 属性
// 2. 沿着原型链查找p1.__proto__ → Person.prototype
// 3. 在 Person.prototype 上找到 constructor 属性
// 4. 该 constructor 指向 Person 函数
```
2. **constructor 的重写**
```javascript
function Person() {}
// 默认情况下
console.log(Person.prototype.constructor === Person); // true
// 如果重写 prototype
Person.prototype = {
// 必须手动指定 constructor否则会丢失
constructor: Person,
sayHello: function() {}
};
// 如果不手动指定 constructor
Person.prototype = {
sayHello: function() {}
};
console.log(Person.prototype.constructor === Person); // false
console.log(Person.prototype.constructor === Object); // true
```
### 实际应用场景
1. **类型判断**
```javascript
const arr = [];
console.log(arr.constructor === Array); // true
const obj = {};
console.log(obj.constructor === Object); // true
const num = 123;
console.log(num.constructor === Number); // true
```
2. **实例创建**
```javascript
function Person(name) {
this.name = name;
}
const p1 = new Person("张三");
// 通过 constructor 创建新实例
const p2 = new p1.constructor("李四");
console.log(p2.name); // "李四"
console.log(p2 instanceof Person); // true
```
3. **原型链中的 constructor**
```javascript
function Animal() {}
function Dog() {}
// 设置继承关系
Dog.prototype = Object.create(Animal.prototype);
// 修复 constructor 指向
Dog.prototype.constructor = Dog;
const dog = new Dog();
console.log(dog.constructor === Dog); // true
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
```
### 总结要点
1. **constructor 的位置**:在原型对象上,不在实例对象上
2. **默认指向**:指向创建该原型对象的构造函数
3. **可修改性**constructor 属性可以被修改或覆盖
4. **查找路径**:实例对象访问 constructor 时会沿着原型链查找
5. **特殊案例**
- `Function.prototype.constructor` 指向 `Function`
- `Object.prototype.constructor` 指向 `Object`
- 函数对象的构造函数是 `Function`
- 对象实例的构造函数是创建它的函数
### 内存示意图
```
p1 (实例) Person.prototype Function.prototype
┌─────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ __proto__ → │ constructor │ → Person │
│ ├──────────────→ │ │ │ constructor │ → Function
│ │ │ other props... │ │ │
└─────────┘ └─────────────────┘ └─────────────────┘
```

@ -0,0 +1,18 @@
<template>
<div
class="markdown-body"
v-html="htmlStr"
/>
</template>
<script setup>
import { ref } from 'vue';
import { marked } from 'marked';
import { getMarkdownContent } from '@/utils/tools';
const htmlStr = ref('');
getMarkdownContent('./md/constructor.md').then((res) => {
htmlStr.value = marked(res);
});
</script>

@ -1 +1,88 @@
## 测试
## 代码前置条件
```javascript
function Person(name) {
this.name = name;
}
const p1 = new Person('p1');
```
## constructor的详细理解
[constructor的详细理解](/#/demo/constructor)
## 原型链流转图
```javascript
/**
* __proto__:原型引用
* prototype原型对象
* 每个实例对象都有__proto__它指向构造函数的prototype
*/
// p1的完整原型链
p1.__proto__ === Person.prototype
Person.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
// Person的完整原型链
Person.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
// Function的完整原型链注意Function.__proto__与Function.prototype循环相等这里是循环引用差异点
Function.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
/**
* Object的完整原型链
* Object.__proto__之所以等于Function.prototype是因为Object本身是一个构造函数所有的构造函数最终都指向Function.prototype
* 那为什么Function.prototype.__proto__指向Object.prototype因为Function.prototype是对象所有的对象最终都指向Obnect.prototype
* 如果这里用Function.__proto__,那它指向的就是Function.prototyp因为Function是构造函数所以符合上面所说的所有的构造函数最终都指向Function.prototype这里就形成了循环引用
*/
Object.__proto__ === Function.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
//Object.prototype的完整原型链
Object.prototype.__proto__ === null
```
## 原型与原型链md关系图
```markdown
p1
├── __proto__ → Person.prototype
└── __proto__ → Object.prototype
└── __proto__ → null
Person
├── __proto__ → Function.prototype
└── __proto__ → Object.prototype
└── __proto__ → null
Function
├── __proto__ → Function.prototype
└── __proto__ → Object.prototype
└── __proto__ → null
Object
├── __proto__ → Function.prototype
└── __proto__ → Object.prototype
└── __proto__ → null
Object.prototype
└── __proto__ → null
```
## 原型图示例
![操作示例](/absRes/prototype/1.webp)
## 原理解释
```javascript
// Person这里是一个构造函数所有的构造函数都指向Function.prototype
Person.__proto__ === Function.prototype
// Person.prototype这里是对象所有的对象最终都指向Objec.prototype
Person.prototype.__proto__ === Object.prototype
// 结论这里可以把Person或者Person.prototype看成一个this指向谁调用指向谁
```

@ -1,12 +1,12 @@
{
"totalNotes": 88,
"totalNotes": 92,
"categories": 5,
"lastUpdated": "2026-01-29T03:29:36.051Z",
"weeklyAdded": 2,
"lastUpdated": "2026-02-03T02:46:03.140Z",
"weeklyAdded": 7,
"categoryChartData": [
{
"name": "demo",
"value": 77
"value": 81
},
{
"name": "python",
@ -27,34 +27,34 @@
],
"recentNotes": [
{
"path": "demo/formItemWithRangeFields.vue",
"title": "表单一个formItem中校验多个字段",
"path": "demo/canvasExample.vue",
"title": "canvas示例",
"category": "demo",
"date": "2026-01-29"
"date": "2026-02-03"
},
{
"path": "demo/eventListenner/index.vue",
"title": "事件监听器的一些总结",
"path": "demo/lodashExamples.vue",
"title": "Lodash 经典用法",
"category": "demo",
"date": "2026-01-29"
"date": "2026-02-02"
},
{
"path": "demo/elementPlusMessageBoxUse.vue",
"title": "element plus中使用messageBox技巧",
"path": "demo/code.vue",
"title": "面试手写题",
"category": "demo",
"date": "2026-01-13"
"date": "2026-02-02"
},
{
"path": "demo/scrollSnapType.vue",
"title": "滚动吸附效果",
"path": "demo/formItemWithRangeFields.vue",
"title": "表单一个formItem中校验多个字段",
"category": "demo",
"date": "2025-12-31"
"date": "2026-02-02"
},
{
"path": "demo/catchError/index.vue",
"title": "明明程序报错,但是控制台不打印错误的几种情况(别怀疑,一定是代码问题,而不是程序运行太久)",
"path": "demo/formChangeTrack.vue",
"title": "表单敏感字段变更追踪标记",
"category": "demo",
"date": "2025-12-18"
"date": "2026-02-02"
}
]
}
Loading…
Cancel
Save