在 JavaScript (ES5+) 中,我试图实现以下场景:
- 一个对象(其中将有许多单独的实例)每个都具有只读属性
.size
可以通过直接属性读取从外部读取,但不能从外部设置. .size
属性必须通过原型(prototype)上的某些方法进行维护/更新(并且应该保留在原型(prototype)上)。- 我的 API 已经由规范定义,所以我不能修改它(我正在为一个已经定义的 ES6 对象开发一个 polyfill)。
- 我主要是想防止人们不小心开枪打自己的脚,而且真的不需要防弹只读(尽管越防弹越好),所以我愿意只要直接设置
obj.size = 3;
是不允许的,就可以妥协一些侧门访问属性。
我知道我可以使用在构造函数中声明的私有(private)变量并设置一个 getter 来读取它,但是我必须将需要维护该变量的方法从原型(prototype)中移出并在构造函数中声明它们也(因此他们可以访问包含变量的闭包)。对于这种特殊情况,我不想将我的方法从原型(prototype)中移除,所以我正在寻找其他可能的选择。
还有什么其他的想法(即使有一些妥协)?
最佳答案
好的,所以对于一个解决方案,您需要两个部分:
- 一个
size
不可分配的属性,即writable:true
或者没有setter
属性 - 一种改变
size
的值的方法反射(reflect),这不是.size = …
它是公共(public)的,以便原型(prototype)方法可以调用它。
@plalx 已经提出了第二个“半私有(private)”的明显方式 _size
由 size
的 setter/getter 反射(reflect)的属性.这可能是最简单、最直接的解决方案:
// declare
Object.defineProperty(MyObj.prototype, "size", {
get: function() { return this._size; }
});
// assign
instance._size = …;
另一种方法是制作 size
属性不可写,但可配置,因此您必须使用 Object.defineProperty
的“长路” (尽管恕我直言,对于辅助函数来说甚至太短了)在其中设置一个值:
function MyObj() { // Constructor
// declare
Object.defineProperty(this, "size", {
writable: false, enumerable: true, configurable: true
});
}
// assign
Object.defineProperty(instance, "size", {value:…});
这两种方法绝对足以防止“搬起石头砸自己的脚”size = …
作业。对于更复杂的方法,我们可能会构建一个公共(public)的、特定于实例的(闭包)setter 方法,该方法只能从原型(prototype)模块范围方法中调用。
(function() { // module IEFE
// with privileged access to this helper function:
var settable = false;
function setSize(o, v) {
settable = true;
o.size = v;
settable = false;
}
function MyObj() { // Constructor
// declare
var size;
Object.defineProperty(this, "size", {
enumerable: true,
get: function() { return size; },
set: function(v) {
if (!settable) throw new Error("You're not allowed.");
size = v;
}
});
…
}
// assign
setSize(instance, …);
…
}());
只要不关闭对 settable
的访问,这确实是故障安全的被泄露。还有一种类似的、流行的、更短的方法是使用对象的身份作为访问 token ,大致如下:
// module IEFE with privileged access to this token:
var token = {};
// in the declaration (similar to the setter above)
this._setSize = function(key, v) {
if (key !== token) throw new Error("You're not allowed.");
size = v;
};
// assign
instance._setSize(token, …);
但是,此模式并不安全,因为有可能窃取 token
通过将带有分配的代码应用到带有恶意 _setSize
的自定义对象方法。
关于javascript - 做一个对外只读的属性,但是我的方法还是可以设置的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23819730/