javascript - 做一个对外只读的属性,但是我的方法还是可以设置的

标签 javascript getter private-members defineproperty

在 JavaScript (ES5+) 中,我试图实现以下场景:

  1. 一个对象(其中将有许多单独的实例)每个都具有只读属性 .size 可以通过直接属性读取从外部读取,但不能从外部设置.
  2. .size 属性必须通过原型(prototype)上的某些方法进行维护/更新(并且应该保留在原型(prototype)上)。
  3. 我的 API 已经由规范定义,所以我不能修改它(我正在为一个已经定义的 ES6 对象开发一个 polyfill)。
  4. 我主要是想防止人们不小心开枪打自己的脚,而且真的不需要防弹只读(尽管越防弹越好),所以我愿意只要直接设置 obj.size = 3; 是不允许的,就可以妥协一些侧门访问属性。

我知道我可以使用在构造函数中声明的私有(private)变量并设置一个 getter 来读取它,但是我必须将需要维护该变量的方法从原型(prototype)中移出并在构造函数中声明它们也(因此他们可以访问包含变量的闭包)。对于这种特殊情况,我不想将我的方法从原型(prototype)中移除,所以我正在寻找其他可能的选择。

还有什么其他的想法(即使有一些妥协)?

最佳答案

好的,所以对于一个解决方案,您需要两个部分:

  • 一个size不可分配的属性,即 writable:true或者没有 setter属性
  • 一种改变size的值的方法反射(reflect),这不是.size = …它是公共(public)的,以便原型(prototype)方法可以调用它。

@plalx 已经提出了第二个“半私有(private)”的明显方式 _sizesize 的 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/

相关文章:

Ruby:使用 self 关键字从内部调用私有(private)方法

oop - CoffeeScript 中的私有(private)成员?

javascript - 除世界之外按字母顺序排列项目

没有值的 JavaScript 对象属性不会显示

Javascript setter / getter

python - 我有一个带有 getter 和 setter 的 Python 类,我想将其转换为 MATLAB

unit-testing - 当您使用您对私有(private)方法的了解来选择测试用例时,您是否明确地对私有(private)方法进行了单元测试

javascript - javascript 无法从 jsp 获取数据

javascript - Jquery 获取没有父级的列表值

javascript - Vue 看不到我的对象从 vuex 获取的更新