You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript原型继承重写prototype后已有实例的原型问题

问题复现代码
//debugger;
function User(email,name) {
    this.email = email;
    this.name = name;
    this.online = false;
}

User.prototype.login = function() {
    this.online = true;
    console.log('this.name is now online');
}

function Admin(...args) {
    User.apply(this, args);
    this.title = 'admin';
}

const admin1 = new Admin('admin@admin.com', 'josh');

Admin.prototype.deleteUser = function() {
    console.log('deleted user');
}

Admin.prototype = Object.create(User.prototype);

const admin2 = new Admin('admin2@admin.com', 'barry');

console.log(admin1); // 可访问deleteUser,无法访问login方法
console.log(admin2); // 可访问login方法,无法访问deleteUser
核心成因

这个现象本质是混淆了修改原型对象内容和重写构造函数prototype指向两种操作的区别,结合JS原型绑定的基础规则就能完全解释:

  • 最核心的基础规则:用new 构造函数()创建实例时,实例内部的隐式原型[[Prototype]](俗称__proto__)会在创建瞬间,直接指向当下构造函数prototype属性对应的那个对象。这个绑定是固定的引用指向,后续如果构造函数的prototype被改成指向另一个全新对象,已经创建好的实例的隐式原型不会跟着更新,还是会指向最初绑定的旧对象。
  • 给Admin.prototype新增deleteUser方法时,没有改变Admin.prototype的引用指向,只是在它原本指向的旧原型对象上新增了一个属性。此时admin1已经创建完成,它的隐式原型本来就指向这个旧原型对象,因为二者指向同一块内存地址,旧对象上新增的方法admin1自然可以直接访问到。
  • 执行Admin.prototype = Object.create(User.prototype)时,相当于直接给Admin的prototype属性赋值了一个刚创建的全新对象,这个新对象的原型链关联到User.prototype,但本身根本没有之前添加的deleteUser方法:
    • admin1是这行代码执行前创建的实例,隐式原型仍然指向最开始的旧原型对象,旧对象上保留了之前添加的deleteUser方法,但这个旧对象从来没有和User.prototype建立过原型链关联,自然找不到User原型上的login方法。
    • admin2是这行代码执行后才创建的实例,隐式原型指向刚替换的新原型对象,顺着原型链能访问到User.prototype上的login方法,但这个新对象上从未定义过deleteUser方法,自然访问不到。

正确的原型继承写法要注意顺序:必须先通过Object.create重写构造函数的prototype完成原型链关联,再往新的prototype上添加构造函数自身的方法,顺序写反就会出现示例里的异常。

内容的提问来源于stack exchange,提问作者caveman418

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 05:24:28