diff --git a/public/absRes/prototype/1.webp b/public/absRes/prototype/1.webp new file mode 100644 index 0000000..b6a7300 Binary files /dev/null and b/public/absRes/prototype/1.webp differ diff --git a/src/views/demo/constructor/constructor.md b/src/views/demo/constructor/constructor.md new file mode 100644 index 0000000..4bffd5c --- /dev/null +++ b/src/views/demo/constructor/constructor.md @@ -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... │ │ │ +└─────────┘ └─────────────────┘ └─────────────────┘ +``` \ No newline at end of file diff --git a/src/views/demo/constructor/index.vue b/src/views/demo/constructor/index.vue new file mode 100644 index 0000000..99d9191 --- /dev/null +++ b/src/views/demo/constructor/index.vue @@ -0,0 +1,18 @@ + + + diff --git a/src/views/demo/prototype/prototype.md b/src/views/demo/prototype/prototype.md index ac4e321..990fc59 100644 --- a/src/views/demo/prototype/prototype.md +++ b/src/views/demo/prototype/prototype.md @@ -1 +1,88 @@ -## 测试 \ No newline at end of file +## 代码前置条件 +```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指向,谁调用指向谁 +``` \ No newline at end of file diff --git a/src/views/welcome/config.json b/src/views/welcome/config.json index f1a1173..f1d3b5e 100644 --- a/src/views/welcome/config.json +++ b/src/views/welcome/config.json @@ -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" } ] } \ No newline at end of file