在JavaScript中定义只读属性

时间:2011-10-13 16:32:34

标签: javascript

给定一个对象obj,我想定义一个只读属性'prop'并将其值设置为val。这是正确的方法吗?

Object.defineProperty( obj, 'prop', {
    get: function () {
        return val;
    }
});

结果应该是(对于val = 'test'):

obj.prop; // 'test'
obj.prop = 'changed';
obj.prop; // still 'test' since it's read-only

此方法适用于:http://jsfiddle.net/GHMjN/
我只是不确定这是否是最简单/最顺利/最合适的方式......

5 个答案:

答案 0 :(得分:87)

您可以改为使用属性描述符的writable属性,这样就无需使用get访问者:

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

正如评论中所提到的,writable选项默认为false,因此您可以在这种情况下省略它:

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

这是ECMAScript 5,因此无法在旧浏览器中使用。

答案 1 :(得分:1)

在新版浏览器或 node.js 中,可以使用 Proxy 创建只读对象。

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) {
        return this.setProperty(target, key, value);
    },
    deleteProperty: function(target, key) {
        return false;
    }
});

您仍然可以为该对象分配新属性,它们也是只读属性。

示例

obj.prop
// > 'test'

obj.prop = 'changed';
obj.prop
// > 'test'

// New value
obj.myValue = 'foo';
obj.myValue = 'bar';

obj.myValue
// > 'foo'

答案 2 :(得分:1)

我尝试过,并且有效...

element.readOnly = "readOnly"  (then .readonly-> true)
element.readOnly = ""  (then .readonly-> false)

答案 3 :(得分:0)

由于旧的浏览器(向后兼容性),我不得不为属性提供访问器功能。我把它作为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.

我希望它有所帮助。

答案 4 :(得分:0)

在我的情况下,我需要一个只能设置其属性一次的对象。
因此,当有人尝试更改已设置的值时,我就抛出了错误。

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)