跳到主要内容
JavaScript 原型和原型链完整指南 | 极客日志
JavaScript Node.js 大前端
JavaScript 原型和原型链完整指南 详细讲解了 JavaScript 的原型与原型链机制。涵盖对象创建方式、原型对象的作用、三个关键属性(prototype、__proto__、constructor)的关系及查找机制。深入剖析原型链的形成、终点及特点,并通过代码示例演示继承实现、instanceof 原理及 new 操作符模拟。此外,还包含性能优化建议、原型污染防御及高频面试问答模板,帮助开发者深入理解 JavaScript 面向对象核心概念。
第一部分:基础概念
1. 对象的三种创建方式
① 对象字面量(最常用)
const obj1 = { name : "Jack" , age : 26 }
特点 :简洁直观,适合创建单个对象。
② Object 构造函数
const obj2 = new Object ();
obj2.name = "Jack" ;
obj2.age = 26 ;
特点 :较少使用,等价于字面量方式。
③ 构造函数模式(重点)⭐
function Person (name, age ) {
this .name = name;
this .age = age;
this .say = function ( ) {
console .log ('我能说话' );
};
}
const obj3 = new Person ('Jack' , 26 );
const obj4 = new Person ('Rose' , 25 );
特点 :代码复用,批量创建对象。
2. 为什么需要原型?
问题:内存浪费
function Person ( ) {
. = ;
. = ( ) {
. ( );
};
}
p1 = ();
p2 = ();
. (p1. === p2. );
this
name
'Rose'
this
say
function
console
log
'我能说话'
const
new
Person
const
new
Person
console
log
say
say
分析 :每个实例都有独立的 say 方法副本,浪费内存!
内存示意图:
┌─────────────┐
│ p1 │
│ name: Rose │
│ say: fn1 │ ← 独立的函数
└─────────────┘
┌─────────────┐
│ p2 │
│ name: Rose │
│ say: fn2 │ ← 又一个独立的函数
└─────────────┘
解决方案:原型对象 function Person (name ) {
this .name = name;
}
Person .prototype .say = function ( ) {
console .log ('我能说话' );
};
const p1 = new Person ('Jack' );
const p2 = new Person ('Rose' );
console .log (p1.say === p2.say );
┌─────────────┐
│ p1 │
│ name: Jack │
└──────┬──────┘
│ __proto__
▼
┌─────────────┐
│ p2 │
│ name: Rose │
└──────┬──────┘
│ __proto__
▼
┌──────────────────┐
│ Person.prototype │
│ say: fn │ ← 共享同一个函数
└──────────────────┘
第二部分:核心机制
1. 三个关键属性 ┌─────────────────────────────────────────────────────────────────┐
│ 三剑客 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ① prototype (显式原型) │
│ • 只有函数对象才有 │
│ • 指向原型对象 │
│ • 用于实现方法共享 │
│ │
│ ② __proto__(隐式原型) │
│ • 所有对象都有 │
│ • 指向创建该对象的构造函数的 prototype │
│ • 形成原型链的关键 │
│ │
│ ③ constructor(构造函数) │
│ • 原型对象的属性 │
│ • 指向构造函数本身 │
│ • 用于识别对象类型 │
│ │
└─────────────────────────────────────────────────────────────────┘
2. 基础关系图 function Person (name ) {
this .name = name;
}
Person .prototype .say = function ( ) {
console .log (`Hello, ${this .name} ` );
};
const p1 = new Person ('张三' );
构造函数 ┌──────────┐
│ Person │
└────┬─────┘
│
│ prototype
▼
┌─────────────────┐
│ Person.prototype│
│ constructor │ ◀───────┤ constructor
│ say() │
└────────┬────────┘
│
│ __proto__
▼
┌─────────┐
│ p1 │
│ { │
│ name: │
│ '张三' │
│ } │
└─────────┘
3. 核心等式(必须记住)⭐⭐⭐
p1.__proto__ === Person .prototype ;
Person .prototype .constructor === Person ;
p1.constructor === Person ;
Person .__proto__ === Function .prototype ;
第三部分:原型链
1. 什么是原型链? 定义 :对象通过 __proto__ 属性连接起来的链式结构。
function Person (name ) {
this .name = name;
}
Person .prototype .say = function ( ) {
console .log (`Hello, ${this .name} ` );
};
const p = new Person ('张三' );
2. 完整原型链图 实例对象 ┌────────┐
│ p │
│ { │
│ name: │
│ '张三' │
│ } │
└───┬────┘
│ __proto__
▼
┌─────────────────┐
│ Person.prototype │ ← 第一层原型
│ { │
│ constructor │
│ say () │
│ } │
└───┬─────────────┘
│ __proto__
▼
┌─────────────────┐
│ Object .prototype │ ← 第二层原型(根原型)
│ { │
│ toString () │
│ valueOf () │
│ hasOwnProperty│
│ } │
└───┬─────────────┘
│ __proto__
▼
null ← 原型链的终点
3. 属性查找机制 function Person (name ) {
this .name = name;
}
Person .prototype .age = 18 ;
const p = new Person ('张三' );
console .log (p.name );
console .log (p.age );
console .log (p.toString ());
查找 p .name :
① 在 p 自身查找 → 找到!返回 '张三'
查找 p .age :
① 在 p 自身查找 → 没有
② 在 p .__proto__(Person.prototype )查找 → 找到!返回 18
查找 p .toString :
① 在 p 自身查找 → 没有
② 在 p .__proto__(Person.prototype )查找 → 没有
③ 在 Person.prototype .__proto__(Object .prototype )查找 → 找到!
4. 原型链的特点 ✅ 1. 链式查找
• 从对象自身开始,沿着 __proto__ 向上查找
• 找到即停止,找不到继续向上
• 直到 null 为止
✅ 2. 就近原则
• 实例属性优先于原型属性
• 可以"屏蔽" 原型上的同名属性
✅ 3. 动态性
• 可以随时给原型添加属性和方法
• 已创建的实例也能访问新添加的成员
✅ 4. 终点是 null
• Object .prototype .__proto__ === null
• 这是原型链的最顶端
第四部分:进阶知识
1. 普通对象 vs 函数对象
function f1 ( ) {}
const f2 = function ( ) {};
const f3 = new Function ('x' , 'return x' );
console .log (typeof f1);
console .log (typeof f2);
console .log (typeof f3);
const obj1 = {};
const obj2 = new Object ();
const obj3 = new f1 ();
console .log (typeof obj1);
console .log (typeof obj2);
console .log (typeof obj3);
┌─────────────────────────────────────────────────────────────────┐
│ 函数对象 vs 普通对象 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ 函数对象 │
│ ✅ 有 prototype 属性 │
│ ✅ 可以作为构造函数使用(new ) │
│ ✅ __proto__ 指向 Function .prototype │
│ │
│ 普通对象 │
│ ❌ 没有 prototype 属性 │
│ ❌ 不能作为构造函数 │
│ ✅ __proto__ 指向创建它的构造函数的 prototype │
│ │
└─────────────────────────────────────────────────────────────────┘
2. Function 的特殊性 function Person ( ) {}
console .log (Person .__proto__ === Function .prototype );
console .log (Object .__proto__ === Function .prototype );
console .log (Array .__proto__ === Function .prototype );
console .log (Function .__proto__ === Function .prototype );
console .log (Function .prototype .__proto__ === Object .prototype );
Function → Function .prototype → Object .prototype → null
3. 完整原型链关系图 ┌─────────────────────────────────────────────────────────────────┐
│ 完整原型链 │
└─────────────────────────────────────────────────────────────────┘
实例对象 ┌────────┐
│ p │
└───┬────┘
│ __proto__
▼
┌─────────────────┐
│ Person .prototype │
└───┬─────────────┘
│ __proto__
▼
┌─────────────────┐
│ Object .prototype │
└───┬─────────────┘
│ __proto__
▼
null
构造函数 ┌────────┐
│ Person │
└───┬────┘
│ __proto__
▼
┌──────────────────┐
│ Function .prototype │
└───┬──────────────┘
│ __proto__
▼
┌─────────────────┐
│ Object .prototype │
└───┬─────────────┘
│ __proto__
▼
null
Function 自己 ┌──────────┐
│ Function │
└───┬──────┘
│ __proto__
▼
┌──────────────────┐
│ Function .prototype │ ← 指向自己的 prototype
└───┬──────────────┘
│ __proto__
▼
┌─────────────────┐
│ Object .prototype │
└───┬─────────────┘
│ __proto__
▼
null
4. 原型链查找实例 function Person ( ) {}
Object .prototype .price = 2000 ;
Function .prototype .price = 300 ;
console .log (Person .price );
查找 Person .price :
① Person 自身有 price 吗? → 没有
② Person .__proto__ (Function .prototype )有吗? → 有!返回 300
如果 Function .prototype 没有:
③ Function .prototype .__proto__ (Object .prototype )有吗? → 有!返回 2000
关键点 :__proto__ 决定查找路径,而不是 prototype。
第五部分:实战应用
1. 实现继承
原型链继承 function Animal (name ) {
this .name = name;
}
Animal .prototype .eat = function ( ) {
console .log (`${this .name} is eating` );
};
function Dog (name, breed ) {
Animal .call (this , name);
this .breed = breed;
}
Dog .prototype = Object .create (Animal .prototype );
Dog .prototype .constructor = Dog ;
Dog .prototype .bark = function ( ) {
console .log (`${this .name} is barking` );
};
const dog = new Dog ('旺财' , '哈士奇' );
dog.eat ();
dog.bark ();
2. 手动实现 instanceof function myInstanceof (obj, constructor ) {
let proto = Object .getPrototypeOf (obj);
const prototype = constructor.prototype ;
while (proto) {
if (proto === prototype) {
return true ;
}
proto = Object .getPrototypeOf (proto);
}
return false ;
}
function Person ( ) {}
const p = new Person ();
console .log (myInstanceof (p, Person ));
console .log (myInstanceof (p, Object ));
console .log (myInstanceof (p, Array ));
3. 手动实现 new 操作符 function myNew (constructor, ...args ) {
const obj = Object .create (constructor.prototype );
const result = constructor.apply (obj, args);
return result instanceof Object ? result : obj;
}
function Person (name, age ) {
this .name = name;
this .age = age;
}
Person .prototype .sayHello = function ( ) {
console .log (`Hello, I'm ${this .name} ` );
};
const p = myNew (Person , '张三' , 25 );
console .log (p.name );
p.sayHello ();
4. 判断属性来源 function Person (name ) {
this .name = name;
}
Person .prototype .age = 18 ;
const p = new Person ('张三' );
console .log (p.hasOwnProperty ('name' ));
console .log (p.hasOwnProperty ('age' ));
console .log ('name' in p);
console .log ('age' in p);
function hasPrototypeProperty (obj, prop ) {
return !obj.hasOwnProperty (prop) && (prop in obj);
}
console .log (hasPrototypeProperty (p, 'name' ));
console .log (hasPrototypeProperty (p, 'age' ));
5. 性能优化建议
function Person (name ) {
this .name = name;
this .sayHello = function ( ) {
console .log (`Hello, ${this .name} ` );
};
}
const p1 = new Person ('张三' );
const p2 = new Person ('李四' );
console .log (p1.sayHello === p2.sayHello );
function Person (name ) {
this .name = name;
}
Person .prototype .sayHello = function ( ) {
console .log (`Hello, ${this .name} ` );
};
const p3 = new Person ('张三' );
const p4 = new Person ('李四' );
console .log (p3.sayHello === p4.sayHello );
6. 原型污染防御
const obj = {};
obj.__proto__ .isAdmin = true ;
const user = {};
console .log (user.isAdmin );
const safeObj = Object .create (null );
safeObj.__proto__ = { isAdmin : true };
console .log (safeObj.isAdmin );
Object .freeze (Object .prototype );
function isSafeProperty (obj, prop ) {
return Object .prototype .hasOwnProperty .call (obj, prop);
}
const safeMap = new Map ();
safeMap.set ('key' , 'value' );
第六部分:面试攻略 🎯
一、核心考点总结 ┌─────────────────────────────────────────────────────────────────┐
│ 必考知识点 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ⭐⭐⭐⭐⭐ 原型和原型链的概念 │
│ ⭐⭐⭐⭐⭐ prototype 和 __proto__ 的区别 │
│ ⭐⭐⭐⭐⭐ 原型链的查找机制 │
│ ⭐⭐⭐⭐⭐ 原型链的终点 │
│ ⭐⭐⭐⭐ constructor 的作用 │
│ ⭐⭐⭐⭐ 如何实现继承 │
│ ⭐⭐⭐ instanceof 的原理 │
│ ⭐⭐⭐ new 操作符的原理 │
│ ⭐⭐⭐ Function 的特殊性 │
│ ⭐⭐ 原型污染问题 │
│ │
└─────────────────────────────────────────────────────────────────┘
二、完美回答模板
问题 1:说说 JavaScript 的原型和原型链?
"JavaScript 的原型和原型链是实现继承和属性共享的核心机制。我从三个方面来说明:原型是什么、原型链是什么、它们有什么特点 。"
"原型 是一个对象,每个函数都有一个 prototype 属性,指向这个原型对象。原型对象用于实现属性和方法的共享。
举个例子:
好处 :节省内存,提高性能。如果把方法定义在构造函数内部,每个实例都会创建一个新的函数副本,造成内存浪费。"
"原型链 是对象通过 __proto__ 属性连接起来的链式结构。
每个对象都有一个 __proto__ 属性,指向创建它的构造函数的 prototype。当访问对象的属性时,如果对象自身没有,就会沿着 __proto__ 向上查找,直到找到或到达 null。
完整的原型链是这样的:
举个例子:
查找机制 :访问 p.toString() 时,先在 p 自身查找,没有就到 Person.prototype 查找,还没有就到 Object.prototype 查找,最终找到并执行。"
"原型和原型链有几个重要特点:
1. 属性共享 :原型上的属性和方法被所有实例共享,节省内存。
2. 动态性 :可以随时给原型添加属性和方法,已创建的实例也能访问。
3. 就近原则 :实例属性优先于原型属性,可以"屏蔽"原型上的同名属性。
4. 链式查找 :沿着 __proto__ 向上查找,直到 null。
5. 终点是 null :Object.prototype.__proto__ === null,这是原型链的顶端。"
"在实际开发中,原型主要用于:实现继承 :通过原型链实现对象之间的继承关系方法共享 :把公共方法放在原型上,避免重复创建扩展内置对象 :可以给 Array.prototype 等添加自定义方法
现在 ES6 的 class 语法本质上也是基于原型实现的,只是语法糖而已。"
三、高频追问及回答
Q1: prototype 和 proto 有什么区别? "三个关键区别:
1. 存在对象不同
• prototype:只有函数对象才有
• __proto__ :所有对象都有
2. 指向不同
• prototype:指向原型对象
• __proto__ :指向创建该对象的构造函数的 prototype
3. 作用不同
• prototype:用于实现属性和方法的共享
• __proto__ :用于形成原型链,实现属性查找
举例说明:
function Person() {}
const p = new Person();
Person.prototype // 原型对象
p.__proto__ // 指向 Person.prototype
p.__proto__ === Person.prototype // true
注意:__proto__ 已被废弃,推荐使用 Object.getPrototypeOf()"
Q2: 原型链的终点是什么? "原型链的终点是 null。
完整链条:
实例对象 → 构造函数.prototype → Object .prototype → null
验证:
const obj = {}
console.log (obj.__proto__); // Object .prototype
console.log (Object .prototype .__proto__); // null
为什么是 null?
因为 Object .prototype 是所有对象的根原型,如果它还有原型,
就会形成无限循环。所以 JavaScript 设计时让它指向 null,
作为原型链的终点。"
Q3: constructor 有什么用? "constructor 有三个主要作用:
1. 识别对象类型
const p = new Person()
console.log(p.constructor.name)
2. 创建相同类型的新对象
const p2 = new p.constructor('李四' )
3. 判断实例关系
console.log(p.constructor === Person)
注意事项:
重写原型对象后要修复 constructor:
Person.prototype = { sayHello: function() {} }
// 此时 constructor 丢失了
// 需要手动修复
Person.prototype.constructor = Person"
Q4: 如何判断属性是在对象自身还是原型上? "三种方法:
1 . hasOwnProperty(推荐)
判断属性是否在对象自身:
p .hasOwnProperty ('name')
2 . in 操作符
判断属性是否存在(包括原型链):
'name' in p
3 . 组合使用
判断属性是否在原型上:
function hasPrototypeProperty (obj, prop) {
return !obj.hasOwnProperty (prop) && (prop in obj)
}
实例:
function Person (name) {
this.name = name;
}
Person.prototype .age = 18 ;
const p = new Person ('张三');
p .hasOwnProperty ('name');
p .hasOwnProperty ('age');
'age' in p ;
Q5: new 操作符做了什么? "new 操作符执行了四个步骤:
1. 创建一个新对象
const obj = {}
2. 将新对象的 __proto__ 指向构造函数的 prototype
obj.__proto__ = Constructor.prototype
3. 执行构造函数,将 this 绑定到新对象
const result = Constructor.apply(obj, args)
4. 返回对象
如果构造函数返回对象,则返回该对象
否则返回新创建的对象
手动实现:
function myNew(Constructor, ...args) {
const obj = Object.create(Constructor.prototype)
const result = Constructor.apply(obj, args)
return result instanceof Object ? result : obj
}""
Q6: Function 有什么特殊性? "Function 有三个特殊之处:
1. Function 是所有函数的构造函数
所有函数的 __proto__ 都指向 Function.prototype:
Person.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
Array.__proto__ === Function.prototype // true
2. Function 自己也是函数
Function.__proto__ === Function.prototype // true
这是唯一一个 __proto__ 指向自己 prototype 的对象
3. Function.prototype 是对象
Function.prototype.__proto__ === Object.prototype // true
完整原型链:
Function → Function.prototype → Object.prototype → null"
Q7: 原型有什么性能问题吗? "主要有两个问题:
1. 引用类型共享问题
原型上的引用类型属性会被所有实例共享:
Person.prototype.hobbies = ['reading' ]
const p1 = new Person()
const p2 = new Person()
p1.hobbies.push('gaming')
console.log(p2.hobbies)
解决方案:在构造函数中初始化引用类型属性
2. 原型链过长导致查找慢
原型链越长,属性查找越慢
优化方案:
• 减少继承层级
• 常用属性放在实例自身"
Q8: 如何实现继承? "JavaScript 中实现继承有多种方式,我说几个主要的:
1. 原型链继承
function Animal(name) {
this.name = name
}
function Dog(name, breed) {
Animal.call(this, name)
this.breed = breed
}
Dog.prototype = Object.create(Animal.prototype)
Dog.prototype.constructor = Dog
优点:简单易懂
缺点:需要手动修复 constructor
2. ES6 Class 继承(推荐)
class Animal {
constructor(name) {
this.name = name
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name)
this.breed = breed
}
}
优点:语法清晰,自动处理原型关系
本质:还是基于原型实现的语法糖
3. 组合继承
结合构造函数继承和原型链继承
既继承属性又继承方法"
Q9: ES6 Class 和原型有什么关系? "ES6 Class 本质上是原型的语法糖,底层还是基于原型实现的。
验证:
class Person {
constructor(name) {
this.name = name
}
sayHello() {
console.log(`Hello, ${this.name}`)
}
}
// 等价于
function Person(name) {
this.name = name
}
Person.prototype.sayHello = function() {
console.log(`Hello, ${this.name}`)
}
// 验证
console.log(typeof Person)
console.log(Person.prototype.sayHello)
区别:
1. Class 必须用 new 调用
2. Class 内部方法不可枚举
3. Class 有更严格的语法检查
4. Class 支持 extends 关键字
但原型关系完全一致:
const p = new Person('张三' )
p.__proto__ === Person.prototype // true "
Q10: 为什么要有原型链? "原型链解决了三个核心问题:
1. 代码复用
• 公共方法放在原型上,所有实例共享
• 避免每个实例都创建方法副本
• 节省内存空间
2. 实现继承
• 通过原型链实现对象之间的继承关系
• 子类可以访问父类的属性和方法
• 形成层级关系
3. 属性查找机制
• 提供统一的属性查找规则
• 从对象自身到原型链逐级查找
• 实现属性的动态扩展
如果没有原型链:
• 每个对象都要包含所有方法(内存浪费)
• 无法实现继承(代码重复)
• 无法扩展内置对象(功能受限)"
Q11: 原型链查找会影响性能吗? "会有一定影响,但通常可以忽略。
性能影响:
1. 原型链越长,查找越慢
obj → Constructor.prototype → Parent.prototype → Object.prototype
2. 频繁访问不存在的属性会遍历整个原型链
优化建议:
1. 减少继承层级
• 避免过深的继承链
• 一般不超过 3-4 层
2. 常用属性放在实例自身
function Person(name) {
this.name = name
}
Person.prototype.sayHello = function() {}
3. 使用 hasOwnProperty 避免原型链查找
if (obj.hasOwnProperty('prop')) {
// 只查找自身属性
}
4. 缓存原型方法
const sayHello = Person.prototype.sayHello
sayHello.call(obj)
实际影响:
现代 JavaScript 引擎对原型链查找做了大量优化,
正常使用不会有明显性能问题。"
Q12: 能修改内置对象的原型吗? "技术上可以,但强烈不推荐!
可以这样做:
Array.prototype .myMethod = function () {
console.log ('自定义方法');
};
const arr = [1, 2, 3] ;
arr.myMethod ();
为什么不推荐:
1 . 污染全局环境
• 影响所有数组实例
• 可能与其他库冲突
2 . 可能被覆盖
• 未来 JavaScript 版本可能添加同名方法
• 导致代码失效
3 . 性能问题
• 修改内置原型会影响引擎优化
4 . 难以调试
• 其他开发者不知道有自定义方法
• 增加维护成本
正确做法:
1 . 使用工具函数
function myArrayMethod (arr) { }
2 . 使用类继承
class MyArray extends Array {
myMethod () { }
}
3 . 使用组合模式
const arrayUtils = {
myMethod (arr) { }
}"
五、面试回答完整模板
🎯 问题:详细说说 JavaScript 的原型和原型链?
"JavaScript 的原型和原型链是实现继承和属性共享的核心机制。我从四个方面来详细说明:原型是什么、原型链是什么、它们的特点、实际应用 。"
"原型(prototype) 是一个对象,每个函数都有一个 prototype 属性指向这个原型对象。
核心作用 :实现属性和方法的共享。
举个例子:
为什么需要原型?
如果把方法定义在构造函数内部,每个实例都会创建一个新的函数副本,造成内存浪费。而放在原型上,所有实例共享同一个方法,节省内存。
三个关键属性 :
prototype(显式原型)- 只有函数有,指向原型对象
__proto__(隐式原型)- 所有对象都有,指向创建它的构造函数的 prototype
constructor - 原型对象的属性,指向构造函数本身"
"原型链 是对象通过 __proto__ 连接起来的链式结构。
形成过程 :
完整链条 :
查找机制 :
当访问对象的属性时:先在对象自身查找找不到就沿着 __proto__ 向上查找直到找到或到达 null
举例:
终点是 null :Object.prototype.__proto__ === null,这是原型链的顶端。"
"原型和原型链有五个重要特点:
1. 属性共享
• 原型上的属性和方法被所有实例共享
• 节省内存,提高性能
2. 动态性
• 可以随时给原型添加属性和方法
• 已创建的实例也能访问新添加的成员
3. 就近原则
• 实例属性优先于原型属性
• 可以"屏蔽"原型上的同名属性
4. 链式查找
• 沿着 __proto__ 向上查找
• 找到即停止,找不到返回 undefined
5. 引用类型共享问题
• 原型上的引用类型属性会被所有实例共享
• 一个实例修改会影响其他实例
• 解决方案:在构造函数中初始化引用类型属性"
"在实际开发中,原型主要用于:
1. 实现继承
2. 方法共享
• 把公共方法放在原型上
• 避免重复创建
3. 扩展内置对象
• 可以给 Array.prototype 等添加方法
• 但不推荐,容易污染全局
4. 实现多态
• 通过原型链实现方法重写
• 子类可以覆盖父类方法
现代开发 :
ES6 的 class 语法本质上也是基于原型实现的,只是语法糖。但它提供了更清晰的语法和更好的可读性,是目前推荐的写法。"
六、面试加分项
1. 主动提及的高级话题 ✅ "我还了解原型污染的安全问题..."
✅ "在性能优化方面,原型链查找..."
✅ "ES6 Class 虽然是语法糖,但它..."
✅ "Function 比较特殊,它的 __proto__ 指向自己的 prototype..."
✅ "实际项目中,我们用原型实现了..."
2. 展示深度理解
Function .__proto__ === Function .prototype
Person .__proto__ === Function .prototype
Object .__proto__ === Function .prototype
obj → Constructor .prototype → Object .prototype → null
Dog .prototype = Object .create (Animal .prototype );
Dog .prototype .constructor = Dog ;
Object .getPrototypeOf (obj);
Object .setPrototypeOf (obj, proto);
3. 结合实际项目 "在我们的项目中,我用原型实现了一个插件系统:基类定义了核心方法,放在原型上供所有插件共享。每个插件继承基类,可以重写特定方法。通过原型链实现了插件的热插拔和动态扩展。这样既保证了代码复用,又实现了灵活的扩展性。"
七、面试回答要点总结 ┌─────────────────────────────────────────────────────────────────┐
│ 面试回答黄金法则 │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ✅ 结构清晰 │
│ • 分点阐述,层次分明 │
│ • 先说概念,再说特点,最后说应用 │
│ │
│ ✅ 举例说明 │
│ • 每个概念都配合代码示例 │
│ • 用图解辅助理解 │
│ │
│ ✅ 深度适中 │
│ • 基础概念必须准确 │
│ • 适当展示进阶知识 │
│ • 不要过度炫技 │
│ │
│ ✅ 联系实际 │
│ • 说明实际应用场景 │
│ • 提及项目经验 │
│ • 展示问题解决能力 │
│ │
│ ✅ 关键术语 │
│ • prototype(显式原型) │
│ • __proto__(隐式原型) │
│ • constructor(构造函数) │
│ • 原型链(prototype chain) │
│ • 属性查找(property lookup) │
│ │
│ ⭐ 加分项 │
│ • 提到 Function 的特殊性 │
│ • 说明 ES6 Class 与原型的关系 │
│ • 讨论性能和安全问题 │
│ • 展示手写实现能力 │
│ │
└─────────────────────────────────────────────────────────────────┘
八、一句话精华总结
"JavaScript 通过原型(prototype)实现方法共享,通过原型链(proto)实现继承和属性查找。每个对象都有 proto 指向创建它的构造函数的 prototype,多个原型通过 proto 连接形成原型链,终点是 Object.prototype.proto = null。这是 JavaScript 面向对象编程的基础。"
总结 ✅ 基础概念 - 对象创建、原型对象、隐式原型
✅ 核心机制 - prototype、proto 、constructor
✅ 原型链 - 形成过程、查找机制、终点
✅ 进阶知识 - Function 特殊性、完整关系图
✅ 实战应用 - 继承实现、常用方法、性能优化
✅ 面试攻略 - 完美回答模板、高频追问、加分项
掌握这些内容,无论是项目开发还是面试,都能游刃有余!🎉
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online