原型与原型链、原型属性学习笔记

张开发
2026/4/7 19:21:25 15 分钟阅读

分享文章

原型与原型链、原型属性学习笔记
一、核心概念在JavaScript中原型Prototype是实现继承的核心机制所有对象除null外都有一个内置的原型对象用于共享属性和方法避免重复创建提升代码复用性。原型链则是原型层层关联形成的链条解决了“对象如何查找属性/方法”的问题。关键前提函数也是对象函数除了自身的属性和方法还自带一个特殊的原型属性而普通对象由函数创建的原型指向其构造函数的原型对象。二、原型Prototype详解2.1 什么是原型原型是一个对象每个函数构造函数都有一个prototype属性原型属性这个属性指向的就是该函数的“原型对象”。当用这个构造函数创建实例时实例会自动关联到这个原型对象实例可以访问原型对象上的所有属性和方法。简单理解原型对象是“模板”实例是“模板复制出来的产物”模板上的内容所有产物都能共用。2.2 原型的分类易混点区分函数的原型属性prototype仅函数拥有指向“原型对象”作用是为其创建的实例提供共享属性/方法。 示例function Person() {}Person.prototype就是Person函数的原型属性指向Person的原型对象。实例的原型__proto__所有对象除null都拥有是一个内置属性非标准属性规范中用Object.getPrototypeOf()获取指向其构造函数的原型对象。 示例let p new Person()p.__proto__ Person.prototype结果为true。原型对象的构造器constructor每个原型对象都有一个constructor属性指向其对应的构造函数。 示例Person.prototype.constructor Person结果为true实例可以通过p.constructor间接访问到构造函数。2.3 原型的核心作用属性/方法共享将所有实例共有的属性如物种、通用方法放在原型对象上所有实例无需单独拥有节省内存。 示例给Person原型添加sayHi方法所有Person实例都能调用且只创建一次。实现继承子构造函数的原型指向父构造函数的实例让子实例能访问父构造函数的原型属性/方法后续原型链会详细说明。三、原型链Prototype Chain详解3.1 什么是原型链当访问一个对象的属性/方法时JavaScript会先在对象自身查找如果找不到就会去它的原型对象__proto__指向的对象中查找如果原型对象中也找不到就去原型对象的原型中查找以此类推直到找到属性/方法或找到原型链的终点null这个层层查找的链条就是原型链。核心逻辑实例.__proto__ → 构造函数.prototype → 构造函数.prototype.__proto__ → ... → null3.2 原型链的终点所有原型链的最终终点都是null因为Object.prototype.__proto__ nullObject是JavaScript中所有对象的顶层构造函数。示例Person实例p的原型链 p → Person.prototype → Object.prototype → null所以p可以访问Object.prototype上的方法如toString()、hasOwnProperty()这就是原型链的作用——实现跨构造函数的属性/方法继承。3.3 原型链的常见场景实例// 1. 定义构造函数 function Person(name) { this.name name; // 实例自身属性 } // 2. 给Person原型添加共享方法 Person.prototype.sayHi function() { console.log(Hi, ${this.name}); }; // 3. 创建实例 let p1 new Person(张三); let p2 new Person(李四); // 访问实例自身属性name直接找到 console.log(p1.name); // 张三 // 访问共享方法sayHi自身没有去Person.prototype查找 p1.sayHi(); // Hi, 张三 // 访问Object原型上的方法toStringPerson.prototype没有去Object.prototype查找 console.log(p1.toString()); // [object Object] // 查找不存在的属性遍历原型链到null返回undefined console.log(p1.age); // undefined四、原型属性相关问题易混、易错点4.1 易混点1prototype vs __proto__区别维度prototype__proto__拥有者仅函数构造函数拥有所有对象除null都拥有作用为其创建的实例提供共享属性/方法指向自身的原型对象构成原型链关系实例.__proto__ 构造函数.prototype原型对象.__proto__ 指向更高层原型4.2 易错点1修改原型属性 vs 给实例添加属性当给实例添加一个与原型对象同名的属性时不会修改原型对象的属性只会在实例自身添加该属性优先访问实例自身的属性原型链查找的优先级。// 延续上面的Person构造函数 Person.prototype.age 18; // 原型上的age属性 let p1 new Person(张三); console.log(p1.age); // 18自身没有访问原型 // 给实例添加同名属性 p1.age 20; console.log(p1.age); // 20访问自身属性 console.log(Person.prototype.age); // 18原型属性未被修改 // 删除实例自身的age属性会重新访问原型的age delete p1.age; console.log(p1.age); // 184.3 易错点2直接修改原型对象 vs 替换原型对象直接修改原型对象在原有原型对象上添加/修改属性不影响原型链已创建的实例和后续创建的实例都能访问到。 示例Person.prototype.gender 男p1已创建也能访问p1.gender。替换原型对象用一个新对象替换原有的prototype会断裂原型链已创建的实例仍指向原来的原型对象只有后续创建的实例指向新原型。// 替换原型对象 Person.prototype { gender: 男, sayHello: function() { console.log(Hello); } }; let p3 new Person(王五); let p1 new Person(张三); // 之前创建的实例 console.log(p3.gender); // 男新原型的属性 console.log(p1.gender); // undefined原原型没有gender新原型与p1无关 console.log(p1.sayHi()); // 正常执行原原型的方法 console.log(p3.sayHi()); // 报错新原型没有sayHi方法4.4 易错点3null的原型null没有原型null.__proto__会报错它是原型链的终点也是唯一没有原型的对象。注意Object.create(null)创建的对象其原型也是null无法访问Object.prototype上的任何方法如toString。

更多文章