JavaScript中继承构造函数原型的正确实现方式
原型继承正确写法结论
Option 1(Admin.prototype = Object.create(User.prototype))是正确实现,Option 2是存在严重缺陷的错误写法。
两种写法的本质区别
- Option 2(
Admin.prototype = User.prototype)的问题:
该写法直接让Admin的原型和User的原型指向同一个内存地址的对象,没有做任何隔离。后续如果给Admin原型挂载管理员专属方法(比如删除用户、删除内容的方法),会直接修改User原型对象,导致所有普通User实例也能访问到这些仅管理员应该拥有的方法,造成原型污染,完全违背继承的隔离设计。 - Option 1(
Admin.prototype = Object.create(User.prototype))的正确性:Object.create(User.prototype)会创建一个全新的空对象,同时将这个空对象的隐式原型(__proto__)指向User.prototype。这时候:- Admin实例顺着原型链可以正常访问到User原型上挂载的
login等公共方法,满足继承需求 - 后续给Admin原型添加专属方法时,只会修改这个独立的新原型对象,不会污染User的原型,普通User实例不会拿到Admin的专属方法,符合原型继承的设计预期。
- Admin实例顺着原型链可以正常访问到User原型上挂载的
补全最佳实践
使用Option1实现继承后,需要手动将Admin原型的constructor指回Admin本身,避免原型链上的构造函数指向错乱:
Admin.prototype = Object.create(User.prototype); // 修正constructor指向 Admin.prototype.constructor = Admin;
效果验证代码
function User(email, name) { this.email = email; this.name = name; this.online = false; } User.prototype.login = function() { this.online = true; console.log(this.email, 'has logged in'); } function Admin(...args) { User.apply(this, args); this.role = 'super admin'; } // 正确继承实现 Admin.prototype = Object.create(User.prototype); Admin.prototype.constructor = Admin; // 挂载Admin专属方法 Admin.prototype.deleteUser = function(targetId) { console.log(`admin deleted user ${targetId}`); } // 测试 const adminInstance = new Admin('admin@test.com', 'siteAdmin'); adminInstance.login(); // 正常输出 admin@test.com has logged in,继承成功 const normalUser = new User('user@test.com', 'commonUser'); console.log(normalUser.deleteUser); // 输出undefined,普通用户不会拿到管理员方法,无原型污染
内容的提问来源于stack exchange,提问作者caveman418
相关产品推荐
相关产品推荐

