Содержание
Есть много способов заблокировать объект в соответствии с вашими потребностями. Object
Объект (несмотря на избыточность), имеет несколько полезных функций, которые позволят вам блокировать объекты.
Object.freeze
Object.seal
Object.preventExtensions
Для всех примеров в этом посте мы будем использовать следующий объект:
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 замораживает объект (спасибо капитану очевидно).
Этот метод предотвращает добавление новых свойств, предотвращает удаление существующих свойств и предотвращает изменение существующих свойств (или их перечислимость, конфигурируемость или возможность записи). По сути, объект сделан неизменным. Метод возвращает замороженный объект.
// 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();
Обратите внимание, что вы замораживаете только объект в качестве первого параметра. Если значение замороженного объекта является объектом, оно все еще может быть изменено, если вы не замораживаете их тоже. Если вы попытаетесь изменить myBankAccount.user
, вы сможете добавить свойства внутри этого объекта.
// 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
Метод protectExtensions предотвращает добавление новых свойств к объекту (то есть предотвращает будущие расширения объекта).
// 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 запечатывает объект, предотвращая добавление к нему новых свойств и помечая все существующие свойства как неконфигурируемые. Значения существующих свойств могут все еще быть изменены, пока они доступны для записи.
// 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
Быстрое сравнение и заметки
Object.preventExtensions | да | нет |
Object.seal | да | да |
Object.freeze | да | да |
- Субобъекты замороженного объекта являются изменяемыми, если вы их не заморозите.
- Прототип цепи с использованием
Object.seal
остается нетронутым Тем не менее__proto__
собственность также опечатана. - Свойства все еще могут быть добавлены к прототипу объекта. Тем не менее, призывая
preventExtensions
на объекте также будет предотвращать расширения на его__proto__
имущество.
Переменная Object имеет полезный метод, чтобы проверить, использовалась ли какая-либо из предыдущих функций для объекта:
Object.isFrozen(myObj)
,Object.isSealed(myObj)
,Object.isExtensible(myObj)
,
Если вы не работаете со строгим режимом в вашем коде ('use strict';
) в консоли не будет выдано никаких ошибок, так как все будет игнорироваться. Однако в строгом режиме вы получите Type Errors
если вы попытаетесь выполнить задачу, добавив свойство в нерасширяемый объект и т. д.
Запретить доступ к переменной в консоли
Если вы боитесь, что кто-то может проверить ваш код и изменить что-то в консоли, просто поместите ваш код в анонимную функцию. Это предотвратит появление в консоли, поэтому другие разработчики не смогут получить доступ к коду таким образом.
Проанализируйте следующий код:
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);
Если вы включите этот код в свой документ, и кто-то решит прочитать код этих файлов, он может найти и выполнить следующее в консоли, потому что объект MySuperBankObject представлен глобально:
А никто этого не хочет? Чтобы предотвратить это (хотя код может быть виден в браузере, его нельзя изменить), оберните предыдущий код в анонимную функцию:
(function(){
/**
* All the code that needs to be unexposed in the console here.
*/
})(); // Send parameters inside the function if you need to
Теперь оберните предыдущий внутри анонимной функции:
(function(){
var allow_transaction = false;
var MySuperBankObject = {
person: "Bruce",
account: 123123,
....
....
})();
Полезно не? Если разработчик попытается получить mySuperBankObject в консоли, он столкнется с этим:
Код будет работать как положено, но переменные больше не отображаются в консоли. Обратите внимание, что код все еще читается разработчиком, хотя не может быть легко изменено он все еще изменяется, если у вашего кода есть слабые места (геттеры и сеттеры неправильно настроены, т.е. глупая глобальная функция как getMySuperBankObject
...) и с достаточными знаниями. Сократите код, чтобы уменьшить читабельность.
Наконец, пожалуйста, не обрабатывайте банковский счет с каким-либо кодом, подобным указанному в этом сообщении, спасибо!.
Повеселись