创建一个对外界只读的属性,但我的方法仍然可以设置 [英] Make a property that is read-only to the outside world, but my methods can still set

查看:101
本文介绍了创建一个对外界只读的属性,但我的方法仍然可以设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In JavaScript (ES5+), I'm trying to achieve the following scenario:


  1. 一个对象(其中会有很多)每个都有一个只读属性 .size ,可以通过直接属性读取从外部读取,但不能从外部设置。

  2. 必须从原型上的某些方法维护/更新 .size 属性(并且应保留在原型上)。

  3. 我的API已经由规范定义,因此我无法对其进行修改(我正在为已定义的ES6对象进行polyfill工作)。

  4. I我大多试图阻止人们不小心在脚下射击,并且不必真的必须使用防弹只读(尽管防弹越多越好),所以我愿意妥协一些只要直接设置 obj.size = 3; ,就可以进入酒店。

  1. An object (of which there will be many separate instances) each with a read-only property .size that can be read from the outside via direct property read, but cannot be set from the outside.
  2. The .size property must be maintained/updated from some methods which are on the prototype (and should stay on the prototype).
  3. My API is already defined by a specification so I can't modify that (I'm working on a polyfill for an already-defined ES6 object).
  4. I'm mostly trying to prevent people from shooting themselves in the foot accidentally and don't really have to have bulletproof read-only-ness (though the more bullet-proof it is, the better), so I am willing to compromise some on side door access to the property as long as directly setting obj.size = 3; isn't allowed.

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

I'm aware that I could use a private variable declared in the constructor and set up a getter to read it, but I would have to move the methods that need to maintain that variable off the prototype and declare them inside the constructor also (so they have access to the closure containing the variable). For this particular circumstance, I'd rather not take my methods off the prototype so I'm searching for what the other options might be.

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

What other ideas might there be (even if there are some compromises to it)?

推荐答案

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

OK, so for a solution you need two parts:


  • a size 属性,不可分配,即可写: true 或没有 setter attributes

  • 一种更改大小的值的方法反映,这不是 .size = ... ,这是公共的,因此原型方法可以调用它。

  • a size property which is not assignable, i.e. with writable:true or no setter attributes
  • a way to change the value that size reflects, which is not .size = … and that is public so that the prototype methods can invoke it.

@plalx已经提出了一个明显的方法,第二个semiprivate _size 属性,由getter反映对于大小。这可能是最简单,最直接的解决方案:

@plalx has already presented the obvious way with a second "semiprivate" _size property that is reflected by a getter for size. This is probably the easiest and most straightforward solution:

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

另一种方法是使大小属性不可写,但可配置,所以你必须使用长途与 Object.defineProperty (虽然imho甚至太短的辅助函数)来设置其中的值:

Another way would be to make the size property non-writable, but configurable, so that you have to use "the long way" with Object.defineProperty (though imho even too short for a helper function) to set a value in it:

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

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

These two methods are definitely enough to prevent "shoot in the foot" size = … assignments. For a more sophisticated approach, we might build a public, instance-specific (closure) setter method that can only be invoked from prototype module-scope methods.

(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的访问权限,这确实是自动防故障的/ code>被泄露。还有一种类似的,流行的,更短的方法是使用对象的身份作为访问令牌,行如下:

This is indeed fail-safe as long as no closured access to settable is leaked. There is also a similar, popular, little shorter approach is to use an object's identity as an access token, along the lines of:

// 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 方法的自定义对象。

However, this pattern is not secure as it is possible to steal the token by applying code with the assignment to a custom object with a malicious _setSize method.

这篇关于创建一个对外界只读的属性,但我的方法仍然可以设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆