[英]Returning immutable array/object from function - JavaScript
可能存在這樣的問題,但我只是想問一下。 也許對某人會有幫助。
我有以下代碼:
window.WML.namespace('Cards', {}, (function (wml) {
'use strict';
var layout = {
'4': [
[
{x: X_POS_3, y: Y_POS_1}, {x: X_POS_4, y: Y_POS_1},
{x: X_POS_5, y: Y_POS_2}, {x: X_POS_6, y: Y_POS_2}
],
[
{x: X_POS_1, y: Y_POS_1}, {x: X_POS_2, y: Y_POS_1},
{x: X_POS_4, y: Y_POS_2}, {x: X_POS_5, y: Y_POS_2}
],
[
{x: X_POS_2, y: Y_POS_1}, {x: X_POS_5, y: Y_POS_1},
{x: X_POS_4, y: Y_POS_2}, {x: X_POS_5, y: Y_POS_2}
]
],
'5': [
// similar code
]
};
return {
cardLayout: function () {
return layout;
}
};
}(window.WML)));
我可以在Firebug中輕松地做到這一點:
var myLayout = WML.Cards.cardLayout();
myLayout['4'] = 34;
console.log(WML.Cards.cardLayout()); // prints {'4': 34, '5': []}
注意:
namespace(ObjectName, inheritObject, newObjectProperties);
在WML內部創建一個稱為ObjectName的子對象,該子對象繼承自InheritObject的屬性以及newObjectProperties的屬性/方法。
如果我知道有Array.prototype.slice()方法創建調用方數組的淺表副本,那么如何使cardLayout()返回具有不可變子數組的對象?
您可以使用setters / getters防止意外寫入應為不可變的對象:
var o = (function() {
var internal_o = {x:3};
var internal_y = 5;
Object.defineProperty(o, "y", {
get: function(){ return internal_y },
set: function(){ /*do nothing*/ },
}
return internal_o;
})();
o.y = 3; // Does nothing
console.log(o.y) // 5
我們將數據存儲在一個閉包中,因此不可能直接訪問它。 但是,您必須(遞歸地)對每個想要不可變的屬性執行此操作-您可能希望對代碼進行泛化,以便可以調用defineImmutableProperty(obj, "propertyName", value)
類的函數。 在您的示例中,如果將'4'
屬性設置為不可變,則仍然可以更改數組的元素或這些點的x
和y
屬性。
如果要使數組不可變,則可以執行以下操作:
var o = (function() {
var internal_o = {x:3};
var internal_array = [1, 2, 3];
Object.defineProperty(o, "numbers", {
get: function(){ return internal_array.slice() },
set: function(){ /*do nothing*/ },
}
return internal_o;
})();
o.numbers; // [1, 2, 3], copied from the internal array
o.numbers[1] = "changed"; // Sets a value of the internal array
console.log(o.numbers[1]); // still 2
var numbers = o.numbers;
numbers[1] = "changed";
console.log(numbers[1]); // Since we are still working with the copy, this *will* have mutated
所有這些都帶來了性能成本以及許多其他代碼。 所以,你應該問問自己,它確實是多么重要的數據是准不變! (如果有人願意,運行firebug或類似工具的人肯定可以覆蓋這些技術,因為它可以完全訪問瀏覽器的所有功能。)
此遞歸函數解決了該問題,但移動API不支持它。 因此,如果有人計划制作其應用程序的移動版本,則Object.defineProperty()可在所有平台上運行。
function deepFreeze(o) {
var prop, propKey;
Object.freeze(o); // First freeze the object.
for (propKey in o) {
prop = o[propKey];
if (!o.hasOwnProperty(propKey) || !(typeof prop === 'object') || Object.isFrozen(prop)) {
// If the object is on the prototype, not an object, or is already frozen,
// skip it. Note that this might leave an unfrozen reference somewhere in the
// object if there is an already frozen object containing an unfrozen object.
continue;
}
deepFreeze(prop); // Recursively call deepFreeze.
}
}
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.