JavaScript原型链查找先在对象自身属性中查找,未找到则沿[[Prototype]]向上遍历直至null;构造函数通过prototype和new隐式赋值连接原型;class是语法糖,本质仍是原型继承;需注意共享属性污染、static方法位置及super调用时机等陷阱。
JavaScript 原型链本质是对象内部的 [[Prototype]] 隐式引用(可通过 Object.getPrototypeOf(obj) 读取,或非标准但广泛支持的 __proto__ 访问)。当访问一个对象的属性时,引擎按以下顺序查找:
hasOwnProperty 为 true 的属性)[[Prototype]] 指向的对象继续查找null)这个过程是动态的:修改某个中间原型上的属性,会影响所有继承自它的实例——因为它们共享同一原型对象。
function 构造函数模拟类时原型怎么连传统构造函数方式下,原型链连接靠两个关键点:prototype 属性和 new 操作符的隐式赋值。例如:
function Person(name) {
this.name = name;
}
Person.prototype.say = function() { return 'Hi'; };
const p = new Person('Alice');
console.log(p.say()); // 'Hi'
console.log(p.__proto__ === Person.prototype); // true
console.log(Person.prototype.__proto__ === Object.prototype); // true
注意:Person.prototype 是给实例用的原型;而 Person.__proto__ 指向 Function.prototype(因为函数本身也是对象),这是常被混淆的一层。
class 语法糖背后仍是原型链class 并没有引入新继承模型,只是对原型机制的封装。下面两段代码行为一致:
// class 写法
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} makes a noise.`; }
}
class Dog extends Animal {
speak() { return `${this.name} barks.`; }
}
// 等价的传统写法(忽略细节差异如不可枚举、不可重写等)
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { return `${this.name} makes a noise.`; };
function Dog(name) { Animal.call(this, name); }
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function() { return `${this.name} barks.`; };
区别在于:class 自动设置 [[Prototype]] 链(Dog.__proto__ === Animal),且方法默认不可枚举、不可配置;而手动写容易漏掉 Object.setPrototypeOf(Dog.prototype, Animal.prototype) 或忘记修复 constructor,导致 instanceof 失效或序列化异常。
super 调用时机原型链只负责「方法共享」和「动态属性查找」,但不处理实例属性初始化逻辑。常见问题包括:
prototype 上定义对象/数组属性(如 items: []),会被所有实例共享,造成数据污染static 方法不进原型链,而是直接挂在构造函数上,所以 Dog.staticMethod() 可用,但 dogInstance.staticMethod() 报错super() 必须在子类 constructor 中 this 使用前调用,否则报 ReferenceError: Must call super constructor
this 和 arguments,也不绑定 super,因此不能用于覆盖父类方法并调用 super.xxx()
真正复杂的不是链本身,而是开发者误以为它像 Java/C++ 那样“编译期确定继承结构”——而 JavaScript 中,原型可以随时被修改、替换甚至切断,Object.setPrototypeOf() 和 __proto__ 都可能让运行时行为变得难以追踪。