JavaScript原型链是对象属性查找与继承的核心机制,通过[[Prototype]]内部属性逐级向上查找直至null;构造函数的prototype属性用于设置实例原型,ES6 class底层仍基于此机制,但需注意引用类型共享等局限。
JavaScript中的原型链是对象之间实现属性和方法共享与查找的机制,它构成了JS继承的核心基础。每个对象都有一个内部属性 [[Prototype]](可通过 __proto__ 访问,或用 Object.getPrototypeOf() 获取),指向它的原型对象;而这个原型对象本身也可能有原型,层层向上,直到为 null —— 这条链就是原型链。
当访问一个对象的属性时,JS引擎会按以下顺序查找:
[[Prototype]] 链向上,在原型对象中继续查找;null(即 Object.prototype 的原型)为止;undefined。例如:arr = [1, 2],调用 arr.push(3) 时,arr 自身没有 push 方法,但它的原型是 Array.prototype,而该对象上有 push,因此调用成功。
函数对象(包括自定义构造函数)有一个显式的 prototype 属性,它是一个普通对象,默认包含一个 constructor 指回该函数。当用 new Fn() 创建实例时,实例的 [[Prototype]] 会自动指向该函数的 prototype 对象。
这是手动构建原型链的关键入口。比如:
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { console.log(this.name + ' makes a sound'); };
const dog = new Animal('Dog');
dog.speak(); // 正常执行:'Dog makes a sound'
此时 dog.__proto__ === Animal.prototype,而 Animal.prototype.__proto__ === Object.prototype,最终 Object.prototype.__proto__ === null。
传统“类式继承”在ES6前主要靠原型链模拟,常见做法包括:
prototype 指向父类实例(如 Child.prototype = new Parent()),但会带来引用类型共享问题;Object.create(Parent.prototype) 设置子类原型(避免父类构造函数重复执行);class B extends A 会自动设置 B.prototype.__proto__ === A.prototype,并确保 super() 正确初始化 this。原型链不是万能的,使用中需注意:
[[Prototype]]);instanceof 或 Object.prototype.isPrototypeOf(),而非直接比较 __proto__(非标准且已不推荐)。现代开发中,配合 Object.create()、Object.setPrototypeOf() 和 class 语法,可以更安全、清晰地控制原型链结构。