本文概述
有多种方法可以根据你的需要锁定对象。对象对象(尽管有冗余), 具有一些有用的功能, 可让你锁定对象。
- 对象冻结
- 物体密封
- 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"
}
]
};
对象冻结
冻结方法冻结对象(感谢队长)。
此方法可防止向其添加新属性, 防止删除现有属性, 并防止更改现有属性(或其可枚举性, 可配置性或可写性)。本质上, 对象是不可变的。该方法返回冻结的对象。
// 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
preventExtensions方法可防止将新属性添加到对象(即防止将来对该对象进行扩展)。
// 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();
物体密封
密封方法可密封对象, 从而防止向其添加新属性并将所有现有属性标记为不可配置。只要可写, 当前属性的值仍可以更改。
// 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
快速比较和注释
函数 | 使对象不可扩展 | 每个属性的可配置设置为false |
---|---|---|
Object.preventExtensions | 是 | No |
物体密封 | 是 | 是 |
对象冻结 | 是 | 是 |
- 除非冻结对象, 否则冻结对象的子对象是可修改的。
- 使用Object.seal的原型链保持不变。但是, __proto__属性也是密封的。
- 属性仍然可以添加到对象原型。但是, 在对象上调用preventExtensions也将阻止对其__proto__属性的扩展。
Object变量具有一种有用的方法来检查对象是否使用了任何先前的功能:
- Object.isFrozen(myObj)。
- Object.isSealed(myObj)。
- Object.isExtensible(myObj)。
除非你在代码中使用严格模式(” use strict”;), 否则不会在控制台中引发任何错误, 因为所有内容都将被静默忽略。但是, 在严格模式下, 如果尝试在不可扩展的对象中添加属性等来完成任务, 则会出现类型错误。
防止在控制台中访问变量
如果你担心有人可以签出你的代码并在控制台中进行修改, 则只需将你的代码包装在一个匿名函数中即可。这将阻止其出现在控制台中, 因此其他开发人员将无法以这种方式访问代码。
分析以下代码:
<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>
如果你在文档中包含此代码, 并且某人决定读取该文件的代码, 则由于MySuperBankObject对象是全局公开的, 因此他们可以在控制台中查找并执行以下代码:
没有人想要吗, 对吗?为了防止这种情况(尽管该代码在浏览器中可见, 但是无法修改), 将先前的代码包装在一个匿名函数中:
(function(){
/**
* All the code that needs to be unexposed in the console here.
*/
})(); // Send parameters inside the function if you need to
现在将前一个包裹在一个匿名函数中:
<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>
有用吗?如果开发人员尝试在控制台中获取mySuperBankObject, 他将面临以下问题:
该代码将按预期工作, 但是变量不再在控制台中公开。还要注意, 即使你的代码有弱点(getter和setter的配置错误, 即愚蠢的全局函数如getMySuperBankObject …)并且具有足够的知识, 但是仍不能被轻易修改, 尽管开发人员仍可以轻松地对其进行修改。 。精简代码以降低可读性。
最后, 请不要处理带有此帖子中所发布代码的银行帐户, 谢谢!
玩得开心
评论前必须登录!
注册