超类构造方法继承疑问:子类为何继承超类新增原型方法?
问题解答
你的理解完全正确
- 创建
User构造函数,并在其原型上添加info()方法 - 通过
User.call(this, name)实现构造函数继承,让UserAdmin实例拥有User的实例属性 - 使用
Object.create(User.prototype, {...})让UserAdmin.prototype继承User.prototype的方法,同时修正constructor指向以保持一致性
为什么someFunc会被UserAdmin实例继承?
因为Object.create(User.prototype)创建的新对象,其内部原型(__proto__)直接指向原User.prototype对象,而非复制一份快照。这意味着当后续给User.prototype新增someFunc时,UserAdmin的实例依然能通过原型链找到这个方法——毕竟它的原型链最终还是连着User.prototype本身。
如何避免继承超类原型后续新增的函数?
核心思路是复制User.prototype的当前属性到独立对象,切断和原User.prototype的原型链关联,这样后续User.prototype的修改就不会影响UserAdmin的原型。
方法1:用Object.assign快速复制
function User(name) { this.name = name; } User.prototype.info = function () { return this.name; }; function UserAdmin(name, privileges) { User.call(this, name); this.privileges = privileges; } // 复制User.prototype当前的所有属性到新对象,同时设置constructor UserAdmin.prototype = Object.assign({}, User.prototype, { constructor: { value: UserAdmin, enumerable: false, configurable: true, writable: true, } }); // 后续给User原型新增方法 User.prototype.someFunc = function() { console.log("I am created in User prototype") } let meAdmin = new UserAdmin("meAdmin", "edit"); meAdmin.someFunc() // 报错:meAdmin.someFunc is not a function
方法2:手动遍历复制(兼容旧环境)
如果环境不支持Object.assign,可以手动遍历User.prototype的可枚举属性:
function User(name) { this.name = name; } User.prototype.info = function () { return this.name; }; function UserAdmin(name, privileges) { User.call(this, name); this.privileges = privileges; } // 创建一个空原型的对象,避免继承Object.prototype的冗余属性 UserAdmin.prototype = Object.create(null); // 复制User.prototype的可枚举属性 for (let key in User.prototype) { if (User.prototype.hasOwnProperty(key)) { UserAdmin.prototype[key] = User.prototype[key]; } } // 修正constructor属性 Object.defineProperty(UserAdmin.prototype, 'constructor', { value: UserAdmin, enumerable: false, configurable: true, writable: true, }); User.prototype.someFunc = function() { console.log("I am created in User prototype") } let meAdmin = new UserAdmin("meAdmin", "edit"); meAdmin.someFunc() // 报错:meAdmin.someFunc is not a function
注意点
- 这种方式是静态复制,如果后续
User.prototype上的原有方法被修改,UserAdmin.prototype里的对应方法不会同步更新——因为是独立的副本。 - 如果你需要保持原原型方法的同步更新,那还是得用原型链继承;但如果要彻底隔离后续新增方法,复制属性的方式就是最优解。
内容的提问来源于stack exchange,提问作者Boris Borais
相关产品推荐
相关产品推荐

