从函数返回不可变 array/object - JavaScript
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 的属性加上 properties/methods newObjectProperties 的属性。
如果我知道有 Array.prototype.slice() 方法可以创建调用者数组的浅表副本,您将如何制作具有不可变子数组的 cardLayout() return 对象?
您可以使用 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
我们将数据存储在闭包中,因此无法直接访问它。你必须(递归地)为 every 属性 做这个你想要不可变的,虽然 - 你可能想要概括代码以便你可以调用像 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
可能有这样的问题,但我只是想问一下。也许这会对某人有所帮助。
我有这个代码:
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 的属性加上 properties/methods newObjectProperties 的属性。
如果我知道有 Array.prototype.slice() 方法可以创建调用者数组的浅表副本,您将如何制作具有不可变子数组的 cardLayout() return 对象?
您可以使用 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
我们将数据存储在闭包中,因此无法直接访问它。你必须(递归地)为 every 属性 做这个你想要不可变的,虽然 - 你可能想要概括代码以便你可以调用像 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