簡體   English   中英

是否可以用JavaScript對象文字表示法創建只讀成員?

[英]Is it possible to create read only members in JavaScript Object Literal Notation?

我有以下JavaScript對象文字表示法對象

var Parameters= {
    modal_window:{
        backdrop:true,
        keyboard:true,
        show:true,
        remote:false,
        type:{
            normal:function(){
                this.footer.button.accept.type='btn btn-primary';
                this.header.type='modal-header';
            },
            success:function(){
                this.footer.button.accept.type='btn btn-success';
                this.header.type='modal-header alert alert-success';
            },
            info:function(){
                this.footer.button.accept.type='btn btn-info';
                this.header.type='modal-header alert alert-info';
            },
            error:function(){
                this.footer.button.accept.type='btn btn-danger';
                this.header.type='modal-header alert alert-error';
            },
            warning:function(){
                this.footer.button.accept.type='btn btn-warning';
                this.header.type='modal-header alert';
            }
        }
    },
    header:{
        title:undefined,
        type:this.window.type.normal.header
    },
    footer:{
        button:
        {
            accept:{
                title:'Accept',
                click:undefined,
                type:undefined
            },
            cancel:{
                title:'Cancel',
                click:undefined
            }
        }
    }
};

是否可以使header.type和footer.button.accept.type只讀只能通過window.type.normal,window.type.success等進行更改的變量?

澄清:我想在這里做一些澄清。 我的Parameters.header.type應該是只讀的,並且應該具有默認值。 並且當用戶選擇例如Parameters.modal_window.type.normal Parameters.header.type時,必須進行更改。

不管大家怎么說,您都可以在支持Object.defineProperty現代瀏覽器中創建只讀屬性。

var obj = {};

Object.defineProperty(obj, 'someProp', {
    configurable: false,
    writable: false,
    value: 'initial value'
});

obj.someProp = 'some other value';

console.log(obj.someProp); //initial value

編輯:

再次閱讀您的問題后,我了解到您的意思是真正的私有成員或私有變量。 這可以通過使用閉包和自定義getter / setter來實現。

注意:為便於說明,我簡化了對象的結構。

var Parameters = (function () {
    var headerType = 'some value'; //private variable

    return {
        modal_window: {
            type: {
                normal: function () {
                    //custom logic
                    headerType = 'some new value'; //set private variable
                }
            }
        },
        header: {
            get type() { return headerType; } //define a getter only

            //for older browsers, you could just define a normal function
            //which you would have to access like Parameters.header.type()
            //type: function () { return headerType; }
        }
    };

})();

var header = Parameters.header;

console.log(header.type); //some value
header.type = 'some other val';
console.log(header.type); //some value
Parameters.modal_window.type.normal();
console.log(header.type); //some new value

既然我們知道可以實施真正的隱私,但我不確定這是否值得。 實施真正的隱私會使設計復雜化,並降低可測試性(取決於情況)。 一種很流行的方法是使用諸如_myPrivateVar的命名約定簡單地標識私有成員。 這清楚地表明了這種意圖,並告訴程序員他們應該像對待私人成員那樣對待該成員。

您可以使它們起作用,如下所示:

header:{
        title:undefined,
        type: function(){
           return Parameters.modal_window.type.normal.header;
        }
    }

如果需要支持IE 8或更早版本,則可以創建一個訪問器方法來檢索該值,然后使用私有變量存儲實際數據。 如果您適當地定義方法,則可以從它們中設置私有變量,但外界不能設置。 在IE8中,無法定義只讀屬性,因此您必須改為使用訪問器。

有關如何設置訪問者可以用作接口的私有數據的詳細信息,請參見Crockford關於私有成員數據的論述: http : //javascript.crockford.com/private.html

如果您願意使用IE9或更高版本,則可以通過Object.defineProperty()將getter與閉包中的私有變量結合使用。 如果沒有設置器,則無法從外部設置它,但是閉包中定義的方法(在克羅克福德的文章中進行了描述)仍然可以設置私有變量的值。 您將擁有一個只讀屬性,該屬性也可以由您自己的一些方法設置。

您可以創建一個屬性並將其設置為不可寫。 您的構造函數必須用屬性替換值。 如果屬性返回的變量是在閉包中捕獲的,並且沒有暴露給其他對象,則該變量將與只讀變量一樣好。 如果未更改,則甚至不需要關閉,只需使用value配置選項即可。

編輯:根據您的要求,

var Properties = function(obj) {
    var makePropRecursive = function(prop) {
        var old_prop = obj[prop];
        delete obj[prop];
        var prop_obj = {};
        for (var attr in old_prop) {
            if (old_prop.hasOwnProperty(attr)) {
                Object.defineProperty(prop_obj, attr, {
                    value: old_prop[attr],
                    writable: false,
                    enumerable: true
                });
            }
        }
        Object.defineProperty(obj, prop, {
            value: prop_obj,
            writable: false,
            enumerable: true
        });
    };
    makePropRecursive('header');
    makePropRecursive('footer');
    return obj;
};

var props = new Properties({
    modal_window:{
        backdrop:true,
        keyboard:true,
        show:true,
        remote:false,
        type:{
            normal:function(){
                this.footer.button.accept.type='btn btn-primary';
                this.header.type='modal-header';
            },
            success:function(){
                this.footer.button.accept.type='btn btn-success';
                this.header.type='modal-header alert alert-success';
            },
            info:function(){
                this.footer.button.accept.type='btn btn-info';
                this.header.type='modal-header alert alert-info';
            },
            error:function(){
                this.footer.button.accept.type='btn btn-danger';
                this.header.type='modal-header alert alert-error';
            },
            warning:function(){
                this.footer.button.accept.type='btn btn-warning';
                this.header.type='modal-header alert';
            }
        }
    },
    header:{
        title:"Whatever",
        type:"Type"
    },
    footer:{
        button:
        {
            accept:{
                title:'Accept',
                click:undefined,
                type:undefined
            },
            cancel:{
                title:'Cancel',
                click:undefined
            }
        }
    }
});

console.log(props.header);
props.header = 17;
props.header.type = 18;
props.header.title = 19;
console.log(props.header);

props.header不變:輸出顯示

Object {title: "Whatever", type: "Type"}
Object {title: "Whatever", type: "Type"} 

現在是凌晨3點,而遞歸函數不是,所以您只能“修復”一個對象的一個​​級別。 同樣,最好將值復制this值而不是返回obj 但對其進行拋光應該並不難。

如果需要更改值,則可以在構造函數中設置整個對象的私有副本,然后進行吸氣( get: function(name) { return stuff.from.the.original.object } )。

在較新版本的JavaScript中,您可以定義屬性訪問的工作方式:

var yourObj = function() {
  var readOnly = "cannot be changed";
  return {
    get readOnly() { return readOnly; },
    set readOnly(v) { return; },

    specialSetter: function(something) {
      if (something == "magic number") {
        readOnly = "oops maybe it can";
      }
    }
  };
}();

現在代碼可以得到如下值:

var theValue = yourObj.readOnly;

無需進行函數調用。 但是,如果嘗試更改該值:

yourObj.readOnly = "hello world";

那什么也不會發生

設置器或任何其他函數都可以在需要時仍更新訪問“ readOnly”屬性時將返回的值。 但是,任何直接設置屬性的嘗試都不會做任何事情(除非setter函數決定它喜歡該值)。

編輯您可能希望將“ specialSetter”設置為只讀,盡管沒有任何東西可以“破解”閉包。 另外,您可能想使用Object.defineProperty來使“ readOnly”不可寫,但是我不知道這樣是否可以正常工作。

怎么樣: Object.freeze()

您可以在此處找到更多信息: MDN Object.freeze

所以:

Object.freeze(Parameters.modal_window.header);
...

然后,在您希望能夠對其進行設置的功能中,對它們進行解凍,更改並重新凍結。

您絕對不能更改凍結的對象,這是錯誤地在程序中的其他任何地方。

這適用於IE9 + Chrome,Firefox和Safari。

您可以使用下面的顯示模塊模式來隱藏變量並防止其被更改,但這不會阻止任何人更改可訪問的“類型”功能。

在代碼下面,標頭屬性更改為_header並成為一個函數。 屬性類型已更改為_type,並通過用對象表示法包裝返回來將“ type”作為函數而不是屬性返回來隱藏。 有人可以通過重寫將類型函數更改為所需的任何內容,但不能更改_type的值。

var Parameters = function () {
var _modal_window = function modal_window() {
    var backdrop = true,
    keyboard = true,
    show = true,
    remote = false;
    return {
        type: {
            normal: function () {
                this.footer.button.accept.type = 'btn btn-primary';
                this.header.type = 'modal-header';
            },
            success: function () {
                this.footer.button.accept.type = 'btn btn-success';
                this.header.type = 'modal-header alert alert-success';
            },
            info: function () {
                this.footer.button.accept.type = 'btn btn-info';
                this.header.type = 'modal-header alert alert-info';
            },
            error: function () {
                this.footer.button.accept.type = 'btn btn-danger';
                this.header.type = 'modal-header alert alert-error';
            },
            warning: function () {
                this.footer.button.accept.type = 'btn btn-warning';
                this.header.type = 'modal-header alert';
            }
        }
    };
}();
var _header = function header() {
    var _type = 'This causes error';//this.window.type.normal.header;
    return {
        title: undefined, type: function () { return _type; }
    };
}();
var _footer = function footer() {
    return {
        button:
    {
        accept: {
            title: 'Accept',
            click: undefined,
            type: undefined
        },
        cancel: {
            title: 'Cancel',
            click: undefined
        }
    }
    };
}();
return {
    modal_window: _modal_window,
    header: _header,
    footer: _footer
};
}();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM