js保存常量,使其只可讀,實現方式有哪些

保存常量,使其只可讀,實現方式有哪些

1 . es6語法中的常量聲明符 constjavascript

const freeze = 'strange'

freeze = 'tony' //  => Uncaught TypeError: Assignment to constant variable.

若是const聲明一個對象會如何?java

const freezeHero = {
    name: 'strange', 
    skill: 'magic'
    }

freezeHero = {
    name: 'no'
}   //  => Uncaught TypeError: Assignment to constant variable.

//  改變該對象的屬性
freezeHero.name = 'tony'
freezeHero.skill = 'equip'
console.log(freezeHero) //  => {name: 'tony', skill: 'equip'}

const聲明的對象屬性仍然能夠改變,由於僅僅只是變量指向的那個內存地址不能改動。es6

2 . Object.freeze()api

Object.freeze()一樣也是es6新增的apiapp

const freezeMan = {
    name: 'tony'
}
Object.freeze(freezeMan)
freezeMan.name = 'strange'
freezeMan.skill = 'magic'
console.log(freezeMan)  //  => {name: 'tony'}

能夠看到,對象的靜態屬性變爲只讀,不可修改,且不能夠添加新屬性,若是屬性自己也是對象會如何?ui

const freezeMen = {
    members: ['tony', 'strange'], 
    level: 2
}
Object.freeze(freezeMen)
freezeMen.level = 4
//  修改對象的members屬性
Array.prototype.push.apply(freezeMen.members, ['captain', 'hulk'])

console.log(freezeMen)  // => {members: ['tony', 'strange', 'captain', 'hulk'], level: 2}

被鎖定的對象,屬性值爲簡單類型時會被freeze,但值爲對象時仍然能夠修改,這與const聲明符的原理一致。下面經過遞歸的方式,實現對象引用的深層次鎖定,對象的任何屬性都不可重寫,也不可動態添加新屬性prototype

const freezeMen = {
    members: ['tony', 'strange'], 
    level: 2
}
const deepLock = function(obj){
    Object.freeze(obj)
    Object.keys(obj).map((k, i) => {
        if(typeof obj[k] === 'object'){
            deepLock(obj[k])
        }
    })
    return obj
}
deepLock(freezeMen).members = ['captian', 'hulk']
freezeMen.victory = true

console.log(freezeMen)  // => {members: ['tony', 'strange'], level: 2} 

//  若是再想經過defineProperty方法來增長新屬性,會直接拋出異常
Object.defineProperty(freezeMen, 'lastDefine', {
    writable: false,
    value: 'it is lastDefine',
    enumerable: true
})
//  => Uncaught TypeError: Cannot define property lastDefine, object is not extensible

3 . Object.definePropertycode

用這個方法實現的效果與freeze方法差很少,設置writable屬性值爲只讀,對於簡單值類型有效,而屬性值自己爲對象時仍然是能夠修改其值的。一樣能夠使用遞歸來實現對象

var lockProperty = function(data) {
    if(typeof data === 'object') {
        Object.keys(data).map(key => {
            defineDisWritable(data, key, data[key])
        })
    }
    return data
}
var defineDisWritable = function(obj, key, val) {
    Object.defineProperty(obj, key, {
        writable: false,
        value: val,
        enumerable: true
    })
    if(typeof val === 'object') {
        lockProperty(val)
    }
}
const freezeMen = {
    members: {
        people: {
            name: 'default'
        }
    }, 
    level: 2
}
lockProperty(freezeMen)

freezeMen.add = 'new key'
freezeMen.level = 10
freezeMen.members = {
    house: 'big'
}

freezeMen.members.people.name = 'modified'
console.log(freezeMen)  //  => {add: 'new key', members: {people: {name: 'default'}, level: 2}

// 咱們試試使用defineProperty添加新屬性
Object.defineProperty(freezeMen, 'lastkey', {
    writable: false,
    value: 'last',
    enumerable: true
})
console.log(freezeMen) // => {add: 'new key', members: {people: {name: 'default'}, level: 2, lastkey: 'last'}

上述方法也能夠實現對象深層嵌套的屬性凍結,與Object.freeze()的惟一區別是,傳遞的頂層對象仍然能夠添加新的屬性(無論是經過動態添加仍是Object.defineProperty)。遞歸

還能夠經過劫持setter來鎖定經過defineProperty方法添加的屬性。

var lockProperty = function(data) {
    if(typeof data === 'object') {
        Object.keys(data).map(key => {
            defineDisWritable(data, key, data[key])
        })
    }
    return data
}
var defineDisWritable = function(obj, key, val) {
    Object.defineProperty(obj, key, {
        set: function(newVal) {
            //  不賦新值
            // val = newVal
        },
        get: function() {
            return val
        },
        enumerable: true
    })
    if(typeof val === 'object') {
        lockProperty(val)
    }
}
const freezeMen = {
    members: {
        people: {
            name: 'default'
        }
    }, 
    level: 2
}
lockProperty(freezeMen)

freezeMen.add = 'new key'
freezeMen.level = 10
freezeMen.members = {
    house: 'big'
}

freezeMen.members.people.name = 'modified'
console.log(freezeMen)  //  => {add: 'new key', members: {people: {name: 'default'}, level: 2}

_比較Object.defineProperty()Object.freeze()兩種方法的遞歸方案,對於複雜的數據對象,能夠實現兩種狀況:

1.要存儲一個徹底不可寫的數據,使用Object.freeze();
2.要存儲一個不可修改但可拓展的數據,使用Object.defineProperty()

相關文章
相關標籤/搜索