当前位置:首页 > 文章列表 > 文章 > 前端 > 防止JS原型方法被覆盖的几种方式:使用Object.defineProperty设置只读属性通过设置writable:false,可以防止原型方法被重新赋值。Object.defineProperty(Function.prototype,'myMethod',{value:function(){console.log('Mymethod');},writable:false,configurab
防止JS原型方法被覆盖的几种方式:使用Object.defineProperty设置只读属性通过设置writable:false,可以防止原型方法被重新赋值。Object.defineProperty(Function.prototype,'myMethod',{value:function(){console.log('Mymethod');},writable:false,configurab
在JavaScript中,确保核心代码的稳定性和可维护性至关重要。本文深入探讨了如何有效防止JS原型方法被覆盖,重点介绍了使用 `Object.defineProperty` 方法,通过设置 `writable: false` 和 `configurable: false` 来实现原型方法的不可重写和不可配置。这种方法能有效避免因意外修改导致的bug,提升代码的稳定性和调试效率。此外,文章还讨论了其他保护原型方法的策略,如闭包、`Object.freeze()`、`Object.seal()` 和ES6私有类字段,帮助开发者根据不同场景选择最合适的方案,构建更健壮的JavaScript应用。
最直接且有效的方式是使用Object.defineProperty将原型方法的writable和configurable属性都设置为false。1. 将writable设为false可防止通过赋值操作重写方法;2. 将configurable设为false可防止删除该方法或再次修改其属性描述符,从而实现最高级别的保护。这种方式能确保核心方法在大型应用或库中保持稳定,避免意外修改导致的bug,提升代码的可维护性和调试效率。
让JavaScript原型上的方法变得不可重写,最直接且有效的方式是利用 Object.defineProperty
在定义该方法时,将其 writable
属性设置为 false
。这能确保一旦方法被定义,就无法通过简单的赋值操作来修改它。

解决方案
要让一个原型方法不可被重写,核心在于精确控制其属性描述符。Object.defineProperty
方法允许我们对对象的属性进行细粒度的控制,包括其可写性、可枚举性、可配置性等。
具体做法是:在为原型添加方法时,不是直接赋值,而是使用 Object.defineProperty
。

function MyClass() { // 构造函数内容 } // 定义一个不可重写的原型方法 Object.defineProperty(MyClass.prototype, 'doSomething', { value: function() { console.log("我是一个重要的、不该被轻易改变的方法!"); // 实际的业务逻辑 }, writable: false, // 关键:设置为false,禁止通过赋值操作修改 configurable: false, // 关键:设置为false,禁止删除或再次修改属性描述符 enumerable: true // 可选:是否可枚举,通常原型方法会设置为true或false,根据需要 }); const instance = new MyClass(); instance.doSomething(); // 输出: 我是一个重要的、不该被轻易改变的方法! // 尝试重写这个方法 try { instance.doSomething = function() { console.log("我被重写了!"); // 这行不会执行 }; } catch (e) { console.error("尝试重写失败:", e.message); // 在严格模式下会抛出TypeError } instance.doSomething(); // 仍然输出: 我是一个重要的、不该被轻易改变的方法! // 尝试删除这个方法 try { delete instance.doSomething; } catch (e) { console.error("尝试删除失败:", e.message); // 在严格模式下会抛出TypeError } instance.doSomething(); // 仍然输出: 我是一个重要的、不该被轻易改变的方法!
通过将 writable
设置为 false
,我们阻止了外部对该方法进行赋值操作来改变其指向。而将 configurable
也设置为 false
,则进一步锁定了这个属性,这意味着你不能删除它,也不能再次使用 Object.defineProperty
来修改它的任何属性描述符(包括 writable
本身),这提供了最高级别的保护。
为什么需要限制JavaScript原型方法的重写?
在日常的JavaScript开发中,我们往往会追求代码的灵活性和可扩展性。但有些时候,尤其是在构建大型应用、框架或库时,我们需要一些核心逻辑保持稳定和不可变。限制原型方法的重写,正是出于这种对稳定性和可预测性的追求。

从我的经验来看,这主要有几个原因:
保持代码的完整性和一致性:想象一下,你开发了一个核心组件,其中某个原型方法承担着至关重要的内部计算或状态管理。如果这个方法可以被随意重写,那么其他依赖它的模块可能会在不知情的情况下出现异常行为,导致难以追踪的bug。这种限制就像给关键零件打上了“请勿擅动”的标签,确保其行为始终如一。
API的稳定性:如果你在发布一个库,用户可能会基于你的API进行开发。如果库中的核心原型方法可以被轻易修改,那么用户可能会在不经意间破坏库的内部逻辑,从而导致他们的应用崩溃。通过限制重写,你实际上是在向使用者承诺,这个方法的行为是固定的,他们可以放心地依赖它。
避免意外的副作用:JavaScript的动态性是一把双刃剑。虽然它带来了极大的灵活性,但也可能导致意料之外的副作用。当多个团队成员协作时,一个不经意的原型方法重写,可能会影响到其他不相关的代码部分,从而引入新的问题。明确地将某些方法设置为不可重写,能有效减少这种“连锁反应”的风险。
提高调试效率:当一个系统出现问题时,如果知道某些核心方法是不可变的,那么在排查问题时,就可以将这些方法排除在怀疑对象之外,从而缩小问题范围,提高调试效率。我个人就遇到过因为原型方法被不小心覆盖,导致业务逻辑错乱,排查起来简直是噩梦。
说到底,这是一种防御性编程的体现,旨在构建更健壮、更可维护的代码库。它不是为了限制开发者,而是为了提供一个更坚实的基础,让上层建筑能够更稳定地运行。
Object.defineProperty的writable和configurable属性有什么作用?
Object.defineProperty
是JavaScript中一个非常强大的内建方法,它允许我们精确地定义或修改对象的属性。而 writable
和 configurable
则是其属性描述符中两个至关重要的布尔值,它们决定了属性的行为。
writable
属性:
这个属性决定了该属性的 value
是否可以通过赋值操作符 (=
) 来改变。
- 当
writable: true
(默认值) 时,你可以像平常一样给属性赋值,改变它的值。 - 当
writable: false
时,尝试通过赋值操作符去修改这个属性的值将会被阻止。在严格模式下,这会抛出一个TypeError
;在非严格模式下,操作会静默失败,属性的值保持不变。
想象一下,你有一个常量或者一个不希望被外部修改的函数引用。将 writable
设置为 false
,就相当于给这个属性的值加上了一个“只读”的标记。对于原型方法而言,这意味着一旦方法函数被指定,就不能通过 MyClass.prototype.myMethod = newFunction;
这样的方式来替换它。
configurable
属性:
这个属性是控制属性“元数据”的权限。它决定了该属性的描述符本身是否可以被修改,以及该属性是否可以从对象中删除。
- 当
configurable: true
(默认值) 时:- 你可以删除这个属性 (
delete obj.property
)。 - 你可以再次使用
Object.defineProperty
来修改这个属性的任何属性描述符(包括writable
,enumerable
,value
,get
,set
)。
- 你可以删除这个属性 (
- 当
configurable: false
时:- 这个属性不能被删除。尝试删除会失败,在严格模式下抛出
TypeError
。 - 这个属性的描述符不能被再次修改。这意味着你不能将
writable
从false
改回true
,也不能改变enumerable
状态,或者将数据属性转换为访问器属性(get
/set
)等。一旦设置为false
,这个属性的定义就基本被“冻结”了。
- 这个属性不能被删除。尝试删除会失败,在严格模式下抛出
configurable: false
是一个非常强的限制。它不仅保护了属性的值,还保护了属性的“定义”本身。对于那些你希望永远存在且其行为模式永不改变的核心原型方法,将 configurable
也设置为 false
是一个非常稳妥的选择。它确保了方法不仅不能被重写,也不能被移除,甚至其自身的“可重写性”这个特性都不能被改变。
举个例子:
如果你只设置了 writable: false
而 configurable: true
,那么你可以通过 Object.defineProperty
再次修改这个方法的 writable
属性,把它改回 true
,然后再重写它。但如果 configurable
也是 false
,那就彻底锁死了。
选择 writable
和 configurable
的值,取决于你对属性保护的需求程度。对于原型方法而言,通常会希望它们是 writable: false
来防止意外重写。至于 configurable
,如果方法是整个系统不可或缺的基石,那么 false
提供最大保障;如果未来可能需要某种程度的“高级”修改(例如,在测试环境中模拟或替换),那么保持 configurable: true
可能会更灵活一些,但这也会带来一定的风险。
除了Object.defineProperty,还有其他方式可以“保护”原型方法吗?
除了 Object.defineProperty
这种直接且强大的机制,JavaScript中还有一些其他策略或模式,可以间接地“保护”或限制对原型方法的修改。它们可能不如 defineProperty
那么直接地阻止重写,但在不同的场景下,也能达到类似的目的,或者提供更高级别的封装。
1. 利用闭包和模块作用域
这不是直接作用于原型,而是通过封装来限制访问。在现代JavaScript中,模块(ES Modules)或立即执行函数表达式(IIFE)可以创建私有作用域。如果你在模块内部定义了一个函数,并将其作为公共API的一部分导出,那么这个函数本身是模块内部的,外部无法直接访问或修改其内部实现。
// myModule.js const privateHelper = function() { console.log("这是一个内部私有方法,不希望被外部直接修改。"); }; class MyService { doSomethingImportant() { privateHelper(); // 内部调用私有方法 console.log("执行服务核心逻辑。"); } } // 导出类,而不是直接导出方法 export default MyService; // 在其他文件中 import MyService from './myModule.js'; const service = new MyService(); service.doSomethingImportant(); // 正常调用 // 尝试访问或修改 privateHelper 是不可能的 // service.privateHelper; // undefined // MyService.prototype.privateHelper; // undefined
这种方式的“保护”是设计层面的,它通过限制对内部实现的访问来达到目的。你无法重写一个你根本访问不到的函数。它更像是“不提供修改的途径”,而不是“阻止修改”。
2. 使用 Object.freeze()
或 Object.seal()
这两个方法作用于整个对象,而不是单个属性。它们可以用来冻结或密封一个原型对象。
Object.freeze(MyClass.prototype)
: 这会使MyClass.prototype
对象完全不可变。- 现有属性的值不能被改变(所有属性都变为
writable: false
)。 - 不能添加新属性。
- 不能删除现有属性。
- 不能改变现有属性的描述符(所有属性都变为
configurable: false
)。 这对于希望整个原型对象都保持不变的场景非常有用。一旦冻结,原型上的所有方法都不能被重写或删除。
function MyClass() {} MyClass.prototype.methodA = function() { console.log("A"); }; MyClass.prototype.methodB = function() { console.log("B"); }; Object.freeze(MyClass.prototype); // 冻结整个原型 const instance = new MyClass(); instance.methodA(); // A try { instance.methodA = function() { console.log("New A"); }; // 抛出TypeError } catch (e) { console.error("尝试重写冻结的方法失败:", e.message); }
- 现有属性的值不能被改变(所有属性都变为
Object.seal(MyClass.prototype)
: 这会密封MyClass.prototype
对象。- 不能添加新属性。
- 不能删除现有属性。
- 现有属性的值仍然可以改变,只要它们的
writable
属性是true
。 - 现有属性的描述符不能被改变(所有属性都变为
configurable: false
)。 如果你的目标只是防止添加或删除原型方法,但允许现有方法被重写,那么seal
可能会有用。但对于“不可重写”的需求,它不如freeze
或defineProperty
那么直接。
这两种方法虽然能“保护”原型方法,但它们的作用范围是整个对象,而非单个方法。如果你的需求是只保护某个特定的原型方法,而允许其他方法保持可变,那么 Object.defineProperty
依然是更精准的选择。
3. 使用ES6+的私有类字段(#
语法)
对于类内部的方法,ES6引入了私有类字段的提案(目前已是Stage 3,在现代浏览器和Node.js中广泛支持)。通过在方法名前加上 #
,可以将其定义为真正的私有方法,外部无法访问,自然也无法重写。
class MyClass { #privateMethod() { console.log("这是一个真正的私有方法,外部无法访问。"); } publicMethod() { this.#privateMethod(); // 只能在类内部调用 console.log("公共方法执行。"); } } const instance = new MyClass(); instance.publicMethod(); // 正常工作 // 尝试访问或重写私有方法会导致语法错误或运行时错误 // instance.#privateMethod(); // 语法错误 // instance.#privateMethod = function() {}; // 语法错误
这种方式提供了最强的封装性,但它仅限于类实例内部,而不是作用于原型链上的方法。它更侧重于实现细节的隐藏,而非原型方法的“不可重写性”。
总结来说,Object.defineProperty
是最直接且精细地控制单个原型方法不可重写的方式。其他方法,如模块封装、Object.freeze()
或私有类字段,则提供了不同粒度和侧重点的“保护”策略,通常是作为更宏观的设计选择来使用的。选择哪种方式,取决于你的具体需求和代码结构。
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~

- 上一篇
- Java解析XML的几种实用方法

- 下一篇
- JavaScript文件分片上传实现方法详解
-
- 文章 · 前端 | 3分钟前 | JavaScript 时间复杂度 并查集 路径压缩 按秩合并
- JS实现并查集及优化技巧
- 118浏览 收藏
-
- 文章 · 前端 | 3分钟前 |
- HTML扑克游戏制作与发牌动画实现方法
- 416浏览 收藏
-
- 文章 · 前端 | 4分钟前 |
- JS中extends的作用与适用场景
- 278浏览 收藏
-
- 文章 · 前端 | 5分钟前 |
- async函数执行顺序解析
- 216浏览 收藏
-
- 文章 · 前端 | 6分钟前 |
- HTML表格边框控制方法详解
- 230浏览 收藏
-
- 文章 · 前端 | 6分钟前 |
- ReactNative邮箱验证实时提示实现方法
- 314浏览 收藏
-
- 文章 · 前端 | 12分钟前 |
- Flask与React热更新集成教程
- 457浏览 收藏
-
- 文章 · 前端 | 18分钟前 |
- 不用id获取表单值的技巧
- 105浏览 收藏
-
- 文章 · 前端 | 19分钟前 |
- JavaScript添加事件监听方法
- 336浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 511次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 498次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 484次学习
-
- 千音漫语
- 千音漫语,北京熠声科技倾力打造的智能声音创作助手,提供AI配音、音视频翻译、语音识别、声音克隆等强大功能,助力有声书制作、视频创作、教育培训等领域,官网:https://qianyin123.com
- 154次使用
-
- MiniWork
- MiniWork是一款智能高效的AI工具平台,专为提升工作与学习效率而设计。整合文本处理、图像生成、营销策划及运营管理等多元AI工具,提供精准智能解决方案,让复杂工作简单高效。
- 147次使用
-
- NoCode
- NoCode (nocode.cn)是领先的无代码开发平台,通过拖放、AI对话等简单操作,助您快速创建各类应用、网站与管理系统。无需编程知识,轻松实现个人生活、商业经营、企业管理多场景需求,大幅降低开发门槛,高效低成本。
- 160次使用
-
- 达医智影
- 达医智影,阿里巴巴达摩院医疗AI创新力作。全球率先利用平扫CT实现“一扫多筛”,仅一次CT扫描即可高效识别多种癌症、急症及慢病,为疾病早期发现提供智能、精准的AI影像早筛解决方案。
- 155次使用
-
- 智慧芽Eureka
- 智慧芽Eureka,专为技术创新打造的AI Agent平台。深度理解专利、研发、生物医药、材料、科创等复杂场景,通过专家级AI Agent精准执行任务,智能化工作流解放70%生产力,让您专注核心创新。
- 164次使用
-
- 优化用户界面体验的秘密武器:CSS开发项目经验大揭秘
- 2023-11-03 501浏览
-
- 使用微信小程序实现图片轮播特效
- 2023-11-21 501浏览
-
- 解析sessionStorage的存储能力与限制
- 2024-01-11 501浏览
-
- 探索冒泡活动对于团队合作的推动力
- 2024-01-13 501浏览
-
- UI设计中为何选择绝对定位的智慧之道
- 2024-02-03 501浏览