JavaScript 动态生成 Setter 方法:利用 defineSetter 简化类属性封装
本文介绍一种在 JavaScript 中自动为类成员生成 setter 方法的技术。通过扩展 Function 原型,利用 __defineSetter__ 的思想实现 defineSetter 和 defineAllSetter,从而避免手动编写大量冗余的 setter 代码,提升代码规范性和开发效率。
本文旨在分享代码实现细节,若发现任何问题或疑问,欢迎在评论区留言指正。
JavaScript 类属性封装的挑战
在编写 JavaScript 类时,例如:
[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
为了增强代码的可读性,并清晰区分公共(public)与私有(private)变量,我通常习惯通过定义 set... 方法来赋值给类的成员变量。这些 set 方法自然属于公共接口。此外,这种做法也有助于使代码结构更加规范。
然而,这样做会带来一个显著问题:如果不对输入值进行有效性验证(或仅进行简单验证),代码量将大幅增加。试想如果一个类包含 20 个成员属性,就需要手动编写 20 个对应的 set... 方法,这显然过于冗余。因此,我们需要一种机制来解决这一问题。
仿写 __defineSetter 的实现思路
回顾 Mozilla 浏览器中提供的 __defineSetter__ 和 __defineGetter__ 方法,它们允许开发者为 DOM 对象动态添加成员,极大地方便了开发。受此启发,我们可以尝试在 JavaScript 中仿写一个 __defineSetter 功能。
实现思路如下:
利用 JavaScript 的动态特性,为对象动态添加方法或属性。
这样,类中原本需要手动添加的 set... 方法就不再必要了。
同时,对于非字母区间(非 [a-z] 区间)的属性,也不再需要添加对应的 set... 方法。
核心代码实现与原型扩展
以下是具体的实现代码:
var _defineSetter = function (self, p, hdle) { //如果属性为空或js中认为是false的值,则返回 if (!p || !self || "function"!=typeof self) return null; //强制转型,并将self置为该Function(即class)的引用,当然你也可以添加类中属性set方法,而非prototype属性的set方法 p = String(p); self = self.prototype; //如果该成员不是一个方法(function),则添加set..方法 if ("function"!=typeof self[p]) { var n = (function _n (n) { n = String(n); for (var i=0; i<n.length; i++) { var letter = n.substring(0,1).toUpperCase(); n = n.substr(1); if (/[a-z]/i.test(letter)) return 'set'+letter+n; }; return null; }) (p); //得到set...这个成员,下面为该成员动态添加方法,如果没有自定义方法,则添加function(v){this[p]=v}的方法; if (n && hdle && "function"==typeof hdle) self[n] = new Function("v", "this." +p+ "=" +hdle+ ".apply(this,[v]);"); else self[n] = new Function("v", "this." +p+ "=v;"); return self[n]; } return self; }; [Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
上述代码基本实现了 _defineSetter 的功能。但如果我们需要为每个属性单独调用 defineSetter,仍然显得繁琐。既然原型已经实现,我们可以将其动态绑定到 Function 对象上,只需一行代码即可解决所有 set... 方法的生成问题。
Function.prototype.defineAllSetter = function (hdle) {
for (var i in this.prototype)
_defineSetter.apply(this, [this,i,hdle]);
return this;
};
接下来,我们再绑定一个 defineSetter 给 Function 对象。
Function.prototype.defineSetter = function (p, hdle) {
return _defineSetter.apply(this,
[this].concat(Array.prototype.slice.call(arguments,0)));
};
至此,基本功能已实现。大家可以尝试运行测试。
[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]
本例的 DEMO 及完整代码地址:
http://www.never-online.net/code/js/defineSetter/
当然,我们可以在其中加入验证逻辑,具体代码此处不再赘述,因为核心功能已经实现。有兴趣的读者可以尝试自行扩展。
JavaScript异步发送HTTP请求时怎么优雅地处理错误
2026-11-05 17:10:44
5款主流JS在线运行工具对比:CodePen、JSFiddle与StackBlitz怎么选
2026-11-05 17:04:04
JavaScript入门书籍避坑:这些书不适合初学者
2026-11-05 16:31:15
JS使用Math.round实现保留两位小数的原理与代码
2026-11-05 15:35:55
JavaScript 原生 Date 对象怎么实现日期加减
2026-11-05 14:30:00
