Defining read-only properties in JavaScript

前端 未结 5 805
广开言路
广开言路 2020-11-28 06:23

Given an object obj, I would like to define a read-only property \'prop\' and set its value to val. Is this the proper way to do that?

相关标签:
5条回答
  • 2020-11-28 06:51

    You could instead use the writable property of the property descriptor, which prevents the need for a get accessor:

    var obj = {};
    Object.defineProperty(obj, "prop", {
        value: "test",
        writable: false
    });
    

    As mentioned in the comments, the writable option defaults to false so you can omit it in this case:

    Object.defineProperty(obj, "prop", {
        value: "test"
    });
    

    This is ECMAScript 5 so won't work in older browsers.

    0 讨论(0)
  • 2020-11-28 06:57

    In my case I needed an object where we can set its properties only once.
    So I made it throw an error when somebody tries to change already set value.

    class SetOnlyOnce {
        #innerObj = {}; // private field, not accessible from outside
    
        getCurrentPropertyName(){
            const stack = new Error().stack; // probably not really performant method
            const name = stack.match(/\[as (\w+)\]/)[1];
            return name;
        }
    
        getValue(){
            const key = this.getCurrentPropertyName();
    
            if(this.#innerObj[key] === undefined){
                throw new Error('No global param value set for property: ' + key);
            }
    
            return this.#innerObj[key];
        }
    
        setValue(value){
            const key = this.getCurrentPropertyName();
    
            if(this.#innerObj[key] !== undefined){
                throw new Error('Changing global parameters is prohibited, as it easily leads to errors: ' + key)
            }
    
            this.#innerObj[key] = value;
        }
    }
    
    
    class GlobalParams extends SetOnlyOnce {
        get couchbaseBucket() { return this.getValue()}
        set couchbaseBucket(value){ this.setValue(value)}
    
        get elasticIndex() { return this.getValue()}
        set elasticIndex(value){ this.setValue(value)}   
    }
    
    const _globalParams = new GlobalParams();
    
    _globalParams.couchbaseBucket = 'some-bucket';
    _globalParams.elasticIndex = 'some-index';
    
    console.log(_globalParams.couchbaseBucket)
    console.log(_globalParams.elasticIndex)
    
    _globalParams.elasticIndex = 'another-index'; // ERROR is thrown here
    console.log(_globalParams.elasticIndex)

    0 讨论(0)
  • 2020-11-28 06:59

    Because of the old browsers (backwards compatibility) I had to come up with accessor functions for properties. I made it part of bob.js:

    var obj = { };
    //declare read-only property.
    bob.prop.namedProp(obj, 'name', 'Bob', true);
    //declare read-write property.
    bob.prop.namedProp(obj, 'age', 1);
    
    //get values of properties.
    console.log(bob.string.formatString('{0} is {1} years old.', obj.get_name(), obj.get_age()));
    //set value of read-write property.
    obj.set_age(2);
    console.log(bob.string.formatString('Now {0} is {1} years old.', obj.get_name(), obj.get_age()));
    
    //cannot set read-only property of obj. Next line would throw an error.
    // obj.set_name('Rob');
    
    //Output:
    //========
    // Bob is 1 years old.
    // Now Bob is 2 years old.
    

    I hope it helps.

    0 讨论(0)
  • 2020-11-28 07:02

    In new browsers or node.js it is possible to use Proxy to create read-only object.

    var obj = {
        prop: 'test'
    }
    
    obj = new Proxy(obj ,{
        setProperty: function(target, key, value){
            if(target.hasOwnProperty(key))
                return target[key];
            return target[key] = value;
        },
        get: function(target, key){
            return target[key];
        },
        set: function(target, key, value){
            return this.setProperty(target, key, value);
        },
        defineProperty: function (target, key, desc) {
            return this.setProperty(target, key, desc.value);
        },
        deleteProperty: function(target, key) {
            return false;
        }
    });
    

    You can still assign new properties to that object, and they would be read-only as well.

    Example

    obj.prop
    // > 'test'
    
    obj.prop = 'changed';
    obj.prop
    // > 'test'
    
    // New value
    obj.myValue = 'foo';
    obj.myValue = 'bar';
    
    obj.myValue
    // > 'foo'
    
    0 讨论(0)
  • 2020-11-28 07:15

    I tried and it Works ...

    element.readOnly = "readOnly"  (then .readonly-> true)
    element.readOnly = ""  (then .readonly-> false)
    
    0 讨论(0)
提交回复
热议问题