JS 原型链
1. 面向对象背景
Section titled “1. 面向对象背景”在 ES6 引入 class 关键字之前,JavaScript 中并没有传统面向对象语言(如 Java/C++)中的“类”概念。JS 的面向对象是基于 构造函数 (Constructor) 和 原型链 (Prototype Chain) 实现的。
2. 对象创建与构造函数
Section titled “2. 对象创建与构造函数”除了直接字面量创建 var obj = {} 外,标准的对象生成依赖于构造函数。
(行业规范:构造函数的首字母必须大写以示区分)
var obj = new Object(); // 通过内置 objet 方案创建
function Star(name, age) { // 实例属性/方法:绑定在 this 上,每个实例对象都独有一份拷贝 this.name = name; this.age = age; this.sing = function() { console.log('sing'); }}
// 静态属性:直接挂载在构造函数对象上,实例无法访问Star.gender = 'male';
// 实例化let instance = new Star('刘德华', 18);2.1. 💡 new 关键字背后的四部曲
Section titled “2.1. 💡 new 关键字背后的四部曲”当执行 new Star() 时,JS 引擎在底层偷偷做了这四件事:
- 在内存中创建一个新的空对象
{}。 - 将构造函数内部的
this指针强行绑定到这个新对象上。 - 执行构造函数内的代码(为新对象添加属性和方法)。
- 自动返回这个新对象(所以构造函数不需要写
return)。
3. 原型链机制 (核心灵魂)
Section titled “3. 原型链机制 (核心灵魂)”如果所有方法都写在构造函数的 this 上,每次 new 对象都会在内存中重新开辟空间存放同一个函数,这会导致极大的内存浪费。原型对象 解决了这个问题。
3.1. 显式原型:prototype
Section titled “3.1. 显式原型:prototype”- 定义:每一个构造函数天生自带一个名为
prototype的对象属性。 - 作用:我们可以将公用的方法直接挂载到这个对象上。所有由该构造函数生成的实例,都会自动“共享”这个
prototype空间。 - 原型的
this指向:原型对象内的方法,其内部的this永远指向 正在调用该方法的实例对象。
3.2. 隐式原型:__proto__
Section titled “3.2. 隐式原型:__proto__”-
定义:每一个实例化的对象天生自带一个
__proto__属性。 -
作用:这个指针牢牢地指向了它的构造函数的
prototype对象。 -
验证三角关系:
console.log(Star.prototype === instance.__proto__); // 输出: true
3.3. 属性/方法查找机制 (原型链的向上攀爬)
Section titled “3.3. 属性/方法查找机制 (原型链的向上攀爬)”当访问对象的某个属性或方法(如 instance.sing())时:
- 引擎首先在
instance自身的内部查找。 - 如果找不到,就会顺着
__proto__爬到构造函数的prototype对象中去找。 - 如果还找不到,由于
prototype本身也是一个对象,它也有自己的__proto__(指向全局Object.prototype),以此类推。 - 直到攀爬到顶端
Object.prototype.__proto__(其值为null)时停止。如果仍未找到,则返回undefined。
3.4. 身份标识:constructor
Section titled “3.4. 身份标识:constructor”在每一个原型对象 prototype 中,都有一个反向的引路指针 constructor 属性,它指向了 所属的构造函数本身。
console.log(Star.prototype.constructor === Star); // 输出: trueconsole.log(Star.prototype.constructor); // Starconsole.log(Star.prototype == instance.__proto__); // true