javascript – 创建一个对外界只读的属性,但我的方法仍然可以设置

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

>一个对象(其中将有许多单独的实例),每个对象都有一个只读属性.size,可以通过直接属性读取从外部读取,但不能从外部设置.
> .size属性必须从原型上的某些方法维护/更新(并且应保留在原型上).
>我的API已经由规范定义,因此我无法对其进行修改(我正在为已定义的ES6对象处理polyfill).
>我主要是试图阻止人们不小心在脚下射击,并且不必真的有防弹只读(尽管防弹越多越好),所以我愿意妥协只要直接设置obj.size = 3,就可以在侧门上访问该物业;是不允许的.

我知道我可以使用在构造函数中声明的私有变量并设置一个getter来读取它,但是我必须移动需要从原型中维护该变量的方法并在构造函数中声明它们(所以他们可以访问包含变量的闭包.对于这种特殊情况,我宁愿不从原型中取出我的方法,所以我正在寻找其他选项可能是什么.

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

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

>一个不可赋值的size属性,即具有writable:true或无setter属性
>一种更改大小反映的值的方法,它不是.size = …而且是公共的,以便原型方法可以调用它.

@plalx已经提出了第二种“semiprivate”_size属性的明显方法,该属性由大小的getter反映出来.这可能是最简单,最直接的解决方案:

// declare
Object.defineProperty(MyObj.prototype, "size", {
    get: function() { return this._size; }
});
// assign
instance._size = …;

另一种方法是使size属性不可写,但是可配置,这样你就必须使用Object.defineProperty的“漫长道路”(虽然imho甚至对辅助函数来说太短)来设置一个值:

function MyObj() { // Constructor
    // declare
    Object.defineProperty(this, "size", {
        writable: false, enumerable: true, configurable: true
    });
}
// assign
Object.defineProperty(instance, "size", {value:…});

这两种方法绝对足以防止“射中脚”大小= ……任务.对于更复杂的方法,我们可以构建一个公共的,特定于实例的(闭包)setter方法,该方法只能从原型模块范围方法中调用.

(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的关闭访问,这确实是故障安全的.还有一种类似的,流行的,更短的方法是使用对象的身份作为访问令牌,其方式如下:

// 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, …);

但是,此模式不安全,因为可以通过将具有分配的代码应用于具有恶意_setSize方法的自定义对象来窃取令牌.

转载注明原文:javascript – 创建一个对外界只读的属性,但我的方法仍然可以设置 - 代码日志