跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaScriptNode.js大前端

JavaScript 原型和原型链完整指南

综述由AI生成详细讲解了 JavaScript 的原型与原型链机制。涵盖对象创建方式、原型对象的作用、三个关键属性(prototype、__proto__、constructor)的关系及查找机制。深入剖析原型链的形成、终点及特点,并通过代码示例演示继承实现、instanceof 原理及 new 操作符模拟。此外,还包含性能优化建议、原型污染防御及高频面试问答模板,帮助开发者深入理解 JavaScript 面向对象核心概念。

BackendPro发布于 2026/3/28更新于 2026/5/2926 浏览

第一部分:基础概念

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() {
  this.name = 'Rose';
  this.say = function() {
    console.log('我能说话');
  };
}
const p1 = new Person();
const p2 = new Person();
console.log(p1.say === p2.say); // false ❌

分析:每个实例都有独立的 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); // true ✅

优化后的内存示意图:

┌─────────────┐
│ 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; // true

// ② 原型对象的 constructor 指向构造函数
Person.prototype.constructor === Person; // true

// ③ 实例的 constructor 指向构造函数(通过原型链)
p1.constructor === Person; // true

// ④ 构造函数的隐式原型指向 Function.prototype
Person.__proto__ === Function.prototype; // true

第三部分:原型链

1. 什么是原型链?

定义:对象通过 __proto__ 属性连接起来的链式结构。

function Person(name) {
  this.name = name;
}
Person.prototype.say = function() {
  console.log(`Hello, ${this.name}`);
};
const p = new Person('张三');
// 原型链:
// p → Person.prototype → Object.prototype → null
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);  // 18
console.log(p.toString()); // '[object Object]'

查找过程:

查找 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); // 'function'
console.log(typeof f2); // 'function'
console.log(typeof f3); // 'function'

// ==================== 普通对象 ====================
const obj1 = {};
const obj2 = new Object();
const obj3 = new f1();
console.log(typeof obj1); // 'object'
console.log(typeof obj2); // 'object'
console.log(typeof obj3); // 'object'

关键区别:

┌─────────────────────────────────────────────────────────────────┐
│ 函数对象 vs 普通对象                                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│ 函数对象                                                        │
│ ✅ 有 prototype 属性                                              │
│ ✅ 可以作为构造函数使用(new)                                    │
│ ✅ __proto__ 指向 Function.prototype                              │
│                                                                 │
│ 普通对象                                                        │
│ ❌ 没有 prototype 属性                                            │
│ ❌ 不能作为构造函数                                             │
│ ✅ __proto__ 指向创建它的构造函数的 prototype                     │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
2. Function 的特殊性
function Person() {}
// ① 所有函数的 __proto__ 都指向 Function.prototype
console.log(Person.__proto__ === Function.prototype); // true
console.log(Object.__proto__ === Function.prototype); // true
console.log(Array.__proto__ === Function.prototype);  // true

// ② Function 自己也是函数
console.log(Function.__proto__ === Function.prototype); // true

// ③ Function.prototype 是对象
console.log(Function.prototype.__proto__ === Object.prototype); // true

Function 的原型链:

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); // 300

查找过程:

查找 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(); // 旺财 is eating
dog.bark(); // 旺财 is barking
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)); // true
console.log(myInstanceof(p, Object)); // true
console.log(myInstanceof(p, Array));  // false
3. 手动实现 new 操作符
function myNew(constructor, ...args) {
  // 1. 创建新对象,原型指向构造函数的 prototype
  const obj = Object.create(constructor.prototype);
  // 2. 执行构造函数,绑定 this
  const result = constructor.apply(obj, args);
  // 3. 如果构造函数返回对象,则返回该对象;否则返回新对象
  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();        // Hello, I'm 张三
4. 判断属性来源
function Person(name) {
  this.name = name;
}
Person.prototype.age = 18;
const p = new Person('张三');

// ① hasOwnProperty - 判断是否在对象自身
console.log(p.hasOwnProperty('name')); // true
console.log(p.hasOwnProperty('age'));  // false

// ② in 操作符 - 判断是否存在(包括原型链)
console.log('name' in p); // true
console.log('age' in p);  // true

// ③ 判断是否在原型上
function hasPrototypeProperty(obj, prop) {
  return !obj.hasOwnProperty(prop) && (prop in obj);
}
console.log(hasPrototypeProperty(p, 'name')); // false
console.log(hasPrototypeProperty(p, 'age'));  // true
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); // false

// ==================== ✅ 好的做法 ====================
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); // true
6. 原型污染防御
// ==================== 原型污染示例 ====================
const obj = {};
// 恶意代码
obj.__proto__.isAdmin = true;
// 影响所有对象
const user = {};
console.log(user.isAdmin); // true ← 被污染了!

// ==================== 防御措施 ====================
// 1. 使用 Object.create(null) 创建无原型对象
const safeObj = Object.create(null);
safeObj.__proto__ = { isAdmin: true };
console.log(safeObj.isAdmin); // undefined ← 安全

// 2. 冻结原型对象
Object.freeze(Object.prototype);

// 3. 使用 hasOwnProperty 检查
function isSafeProperty(obj, prop) {
  return Object.prototype.hasOwnProperty.call(obj, prop);
}

// 4. 使用 Map 代替普通对象
const safeMap = new Map();
safeMap.set('key', 'value');

第六部分:面试攻略 🎯

一、核心考点总结
┌─────────────────────────────────────────────────────────────────┐
│ 必考知识点                                                      │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│ ⭐⭐⭐⭐⭐ 原型和原型链的概念                                          │
│ ⭐⭐⭐⭐⭐ prototype 和 __proto__ 的区别                               │
│ ⭐⭐⭐⭐⭐ 原型链的查找机制                                            │
│ ⭐⭐⭐⭐⭐ 原型链的终点                                                │
│ ⭐⭐⭐⭐ constructor 的作用                                           │
│ ⭐⭐⭐⭐ 如何实现继承                                                 │
│ ⭐⭐⭐ instanceof 的原理                                             │
│ ⭐⭐⭐ new 操作符的原理                                              │
│ ⭐⭐⭐ Function 的特殊性                                             │
│ ⭐⭐ 原型污染问题                                                   │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
二、完美回答模板
问题 1:说说 JavaScript 的原型和原型链?

🎯 完美回答(3 分钟版本)


开场:点明核心

"JavaScript 的原型和原型链是实现继承和属性共享的核心机制。我从三个方面来说明:原型是什么、原型链是什么、它们有什么特点。"


第一部分:原型(prototype)

"原型是一个对象,每个函数都有一个 prototype 属性,指向这个原型对象。原型对象用于实现属性和方法的共享。

举个例子:

好处:节省内存,提高性能。如果把方法定义在构造函数内部,每个实例都会创建一个新的函数副本,造成内存浪费。"


第二部分:原型链(proto)

"原型链是对象通过 __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); // 'Person'
2. 创建相同类型的新对象
   const p2 = new p.constructor('李四')
3. 判断实例关系
   console.log(p.constructor === Person); // true
注意事项:
重写原型对象后要修复 constructor:
Person.prototype = { sayHello: function() {} }
// 此时 constructor 丢失了
// 需要手动修复
Person.prototype.constructor = Person"
Q4: 如何判断属性是在对象自身还是原型上?
"三种方法:
1. hasOwnProperty(推荐)
   判断属性是否在对象自身:
   p.hasOwnProperty('name') // true/false
2. in 操作符
   判断属性是否存在(包括原型链):
   'name' in p // true/false
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'); // true(自身)
p.hasOwnProperty('age');  // false(原型)
'age' in p;               // true(存在)"
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); // ['reading', 'gaming'] ← 被影响了
   解决方案:在构造函数中初始化引用类型属性
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); // 'function'
console.log(Person.prototype.sayHello); // [Function: 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 的原型和原型链?

完美回答(5 分钟完整版)


第一部分:概念介绍(1 分钟)

"JavaScript 的原型和原型链是实现继承和属性共享的核心机制。我从四个方面来详细说明:原型是什么、原型链是什么、它们的特点、实际应用。"


第二部分:原型(1.5 分钟)

"原型(prototype) 是一个对象,每个函数都有一个 prototype 属性指向这个原型对象。

核心作用:实现属性和方法的共享。

举个例子:

为什么需要原型? 如果把方法定义在构造函数内部,每个实例都会创建一个新的函数副本,造成内存浪费。而放在原型上,所有实例共享同一个方法,节省内存。

三个关键属性: prototype(显式原型)- 只有函数有,指向原型对象 __proto__(隐式原型)- 所有对象都有,指向创建它的构造函数的 prototype constructor - 原型对象的属性,指向构造函数本身"


第三部分:原型链(1.5 分钟)

"原型链是对象通过 __proto__ 连接起来的链式结构。

形成过程:

完整链条:

查找机制: 当访问对象的属性时:先在对象自身查找找不到就沿着 __proto__ 向上查找直到找到或到达 null

举例:

终点是 null:Object.prototype.__proto__ === null,这是原型链的顶端。"


第四部分:核心特点(1 分钟)

"原型和原型链有五个重要特点:

1. 属性共享 • 原型上的属性和方法被所有实例共享 • 节省内存,提高性能

2. 动态性 • 可以随时给原型添加属性和方法 • 已创建的实例也能访问新添加的成员

3. 就近原则 • 实例属性优先于原型属性 • 可以"屏蔽"原型上的同名属性

4. 链式查找 • 沿着 __proto__ 向上查找 • 找到即停止,找不到返回 undefined

5. 引用类型共享问题 • 原型上的引用类型属性会被所有实例共享 • 一个实例修改会影响其他实例 • 解决方案:在构造函数中初始化引用类型属性"


第五部分:实际应用(1 分钟)

"在实际开发中,原型主要用于:

1. 实现继承

2. 方法共享 • 把公共方法放在原型上 • 避免重复创建

3. 扩展内置对象 • 可以给 Array.prototype 等添加方法 • 但不推荐,容易污染全局

4. 实现多态 • 通过原型链实现方法重写 • 子类可以覆盖父类方法

现代开发: ES6 的 class 语法本质上也是基于原型实现的,只是语法糖。但它提供了更清晰的语法和更好的可读性,是目前推荐的写法。"


六、面试加分项
1. 主动提及的高级话题
✅ "我还了解原型污染的安全问题..."
✅ "在性能优化方面,原型链查找..."
✅ "ES6 Class 虽然是语法糖,但它..."
✅ "Function 比较特殊,它的 __proto__ 指向自己的 prototype..."
✅ "实际项目中,我们用原型实现了..."
2. 展示深度理解
// 能说出这些细节会加分
// 1. Function 的特殊性
Function.__proto__ === Function.prototype // true

// 2. 所有函数都是 Function 的实例
Person.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true

// 3. 原型链的完整路径
obj → Constructor.prototype → Object.prototype → null

// 4. constructor 的修复
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 必须修复

// 5. 使用现代 API
Object.getPrototypeOf(obj); // 代替 obj.__proto__
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 特殊性、完整关系图 ✅ 实战应用 - 继承实现、常用方法、性能优化 ✅ 面试攻略 - 完美回答模板、高频追问、加分项

掌握这些内容,无论是项目开发还是面试,都能游刃有余!🎉

目录

  1. 第一部分:基础概念
  2. 1. 对象的三种创建方式
  3. ① 对象字面量(最常用)
  4. ② Object 构造函数
  5. ③ 构造函数模式(重点)⭐
  6. 2. 为什么需要原型?
  7. 问题:内存浪费
  8. 解决方案:原型对象
  9. 第二部分:核心机制
  10. 1. 三个关键属性
  11. 2. 基础关系图
  12. 3. 核心等式(必须记住)⭐⭐⭐
  13. 第三部分:原型链
  14. 1. 什么是原型链?
  15. 2. 完整原型链图
  16. 3. 属性查找机制
  17. 4. 原型链的特点
  18. 第四部分:进阶知识
  19. 1. 普通对象 vs 函数对象
  20. 2. Function 的特殊性
  21. 3. 完整原型链关系图
  22. 4. 原型链查找实例
  23. 第五部分:实战应用
  24. 1. 实现继承
  25. 原型链继承
  26. 2. 手动实现 instanceof
  27. 3. 手动实现 new 操作符
  28. 4. 判断属性来源
  29. 5. 性能优化建议
  30. 6. 原型污染防御
  31. 第六部分:面试攻略 🎯
  32. 一、核心考点总结
  33. 二、完美回答模板
  34. 问题 1:说说 JavaScript 的原型和原型链?
  35. 三、高频追问及回答
  36. Q1: prototype 和 proto 有什么区别?
  37. Q2: 原型链的终点是什么?
  38. Q3: constructor 有什么用?
  39. Q4: 如何判断属性是在对象自身还是原型上?
  40. Q5: new 操作符做了什么?
  41. Q6: Function 有什么特殊性?
  42. Q7: 原型有什么性能问题吗?
  43. Q8: 如何实现继承?
  44. Q9: ES6 Class 和原型有什么关系?
  45. Q10: 为什么要有原型链?
  46. Q11: 原型链查找会影响性能吗?
  47. Q12: 能修改内置对象的原型吗?
  48. 五、面试回答完整模板
  49. 🎯 问题:详细说说 JavaScript 的原型和原型链?
  50. 六、面试加分项
  51. 1. 主动提及的高级话题
  52. 2. 展示深度理解
  53. 3. 结合实际项目
  54. 七、面试回答要点总结
  55. 八、一句话精华总结
  56. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • OpenClaw + Claude 搭建自动写作工作流实践
  • 通义万相 2.1 文生图技术特性与部署实践
  • RabbitMQ 发布确认模式详解:单条、批量与异步实现
  • C++ 入门实战指南:从环境搭建到面向对象编程
  • Linux 管道通信实战:匿名管道进程池与命名管道服务端模型
  • Python 爬虫实战:跨境电商数据采集与代理 IP 策略
  • 基于 Django 与 Vue 的大学生兼职管理系统设计与实现
  • 单链表实战:删除指定值、反转链表与查找中间节点
  • 语义化 AI 驱动器:提示词工程演进与未来技术架构
  • 宇树 G1 机器人强化学习训练配置与奖励函数解析
  • C 语言基础:形参与实参详解,手动实现 pow 函数
  • VirtualBox 安装 Ubuntu 后无法跨虚拟机复制内容的解决方法
  • 英伟达开源 DreamDojo:4.4 万小时数据破解机器人训练难题
  • Z-Image-Turbo 孙珍妮模型部署与提示词实战
  • C++ 构造函数与初始化列表核心解析
  • 选择排序算法详解:原理、优化与复杂度分析
  • 攻防世界 Web 题解:Lottery 与 ics-05 漏洞分析
  • Python MQTT 客户端开发实战:Paho-MQTT 库详解
  • FPGA 摄像头采集到 HDMI 显示完整链路实战
  • GitHub Copilot 辅助 Java 代码重构:上下文感知实操指南

相关免费在线工具

  • 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