There are many ways to lock an object according to your needs. The Object
object (despite the redundancy), has some useful functions that will allow you to lock objects.
Object.freeze
Object.seal
Object.preventExtensions
For all the examples in this post, we'll use the following object :
var myBankAccount = {
user: {
fullname : "Bruce wayne",
age: 26,
occupation: {
day: "Philanthropist billionaire",
night: "I'm Batman"
}
},
multipleAccounts: true,
accounts : [
{
money: (9999999999999999),
currency : "EUR"
},
{
money: (9999999999999999),
currency : "USD"
}
]
};
Object.freeze
Freeze method freezes an object (thanks captain obvious).
This method prevents new properties from being added to it, prevent existing properties from being removed and prevents existing properties (or their enumerability, configurability, or writability) from being changed. In essence the object is made immutable. The method returns the frozen object.
// Add a property before being frozen
myBankAccount.bankName = "Gotham Merchant Bank";
// Shows the value in the object as the property
// was created before the object has been frozen
console.log(myBankAccount.bankName);
// Freeze the object
Object.freeze(myBankAccount);
/**
* Now the object cannot be modified, deleted written
*/
myBankAccount.flushMethod = function(){
SendAllMoneyToJokerAccount();
};
// Will be neither deleted !
delete myBankAccount.bankName;
// Throws error, method doesn't exist.
myBankAccount.flushMethod();
Note that you freeze only the object as first parameter. If a value of the frozen object is an object it can still be modified, unless you freeze them too. If you try to modify myBankAccount.user
, you'll be able to add properties inside of that object.
// Freeze object
Object.freeze(myBankAccount);
// The user property is an object, and you didn't freeze it Too
// to solve use Object.freeze(myBankAccount.user)
myBankAccount.user.flushMethod = function(){
SendAllMoneyToJokerAccount();
};
// Money succesfully transfered :(
// You disappoint Batman
myBankAccount.user.flushMethod();
Object.preventExtensions
The preventExtensions method prevents new properties from ever being added to an object (i.e. prevents future extensions to the object).
// Add property before being nonExtensible
myBankAccount.newValue = 12;
// Disallow new properties to the bank account
Object.preventExtensions(myBankAccount);
// Silently ignored or TypeError
myBankAccount.flushAccount = function(){
sendMoneyToJokerAccount();
};
console.log(myBankAccount.newValue);// Output :12
// Method doesn't exist
myBankAccount.flushAccount();
Object.seal
Seal method seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable.
// Seal object
Object.seal(myBankAccount);
// Changing property values on a sealed object still works.
myBankAccount.multipleAccounts = false;
// But you can't convert data properties to accessors, or vice versa.
Object.defineProperty(myBankAccount, 'foo', { get: function() { return 'hey'; } }); // throws a TypeError
delete myBankAccount.user; // throws a TypeError
myBankAccount.newPropertyToAdd = 'qwe'; // throws a TypeError
Quick comparison and notes
Function | Object is made non-extensible | configurable is set to false for each property |
---|---|---|
Object.preventExtensions | Yes | No |
Object.seal | Yes | Yes |
Object.freeze | Yes | Yes |
- The subobjects of a frozen object are modifiables unless you freeze them.
- The prototype chain using
Object.seal
remains untouched. However, the__proto__
property is sealed as well. - Properties can still be added to the object prototype. However, calling
preventExtensions
on an object will also prevent extensions on its__proto__
property.
The Object variable has useful method to check if any of the previous functions has been used on an object :
Object.isFrozen(myObj)
.Object.isSealed(myObj)
.Object.isExtensible(myObj)
.
Unless you're working with strict mode in your code ('use strict';
) no errors will be thrown in the console as everything will be silently ignored. However in strict mode, you'll get Type Errors
if you try to accomplish task as add a property in a non extensible object etc.
Prevent a variable from being accesible in the console
If you're scared that someone could check out your code and modify things in the console, just wrap your code inside an anonymous function. That will prevent from appearing in the console, so other developer wouldn't be able to access the code that way.
Analize the following code :
<input type="button" id="transfer" value="TransferToAccount" />
<input type="text" id="account" />
<input type="text" id="ammount" />
<script>
var allow_transaction = false;
var MySuperBankObject = {
person: "Bruce",
account: 123123,
money: (9999.99),
sendMoneyToAccount : function(idAccount,amount){
if(amount <= this.money){
allow_transaction = true;
TransferToAccount(this.account,idAccount,amount);
}else{
throw new Error("Too much money. You don't have all that money :(.");
}
}
};
function TransferToAccount(source_account,target_account,amount){
if(!allow_transaction){
throw new Error("The transaction needs to be verified");
}
console.log(amount + " Dollars succesfully transfered to " + target_account + " account from "+ source_account);
}
// Onclick, do transaction
document.getElementById("transfer").addEventListener("click",function(){
// get required info
var amount = document.getElementById("amount").value;
var accountTarget = document.getElementById("account").value;
// Do transaction
MySuperBankObject.sendMoneyToAccount(parseInt(accountTarget),parseFloat(amount));
},false);
</script>
If you include this code inside your document, and someone decides to read the code of that files, they could find and execute the following in the console because MySuperBankObject object is exposed globally :
And nobody wants that, do you? To prevent this, (although the code can be visible in the browser, it can't be modified) wrap the previous code in an anonymous function:
(function(){
/**
* All the code that needs to be unexposed in the console here.
*/
})(); // Send parameters inside the function if you need to
Now wrap the previous inside an anonymous function :
<input type="button" id="transfer" value="TransferToAccount" />
<input type="text" id="account" />
<input type="text" id="ammount" />
<script>
(function(){
var allow_transaction = false;
var MySuperBankObject = {
person: "Bruce",
account: 123123,
....
....
})();
</script>
Useful isn't? If a developer try to get mySuperBankObject in the console, he'll face that :
The code will work as expected, but the variables are not exposed in the console anymore. Note too that the code still being readable by a developer, although can't be modified easily it stills being modified if your code has weak points (getters and setter misconfigured i.e a stupid global function as getMySuperBankObject
...) and with the enough knowledge. Minify your code to decrease the readability.
Finally, please don't handle a bank account with some code like the posted in this post, thanks !.
Have fun