[英]How to track changes with shared, immutable reference types in Javascript
[英]Immutable types in javascript
在我看來,Javascript中不可變的類型是不可能的,或者有沒有人知道創建它們的任何技巧? 這是一種好的還是壞的做法?
例如,像,
var Point2D = function Point2D(x, y) {
var _x = x;
var _y = y;
function constructor() {
var self = {};
// Pseudo-Immutable concept
self.x = function() {
return _x;
}();
self.y = function() {
return _y;
}();
return self;
}
return constructor();
}
這當然不是真正不可改變的,但如果它是1)有充分證據表明屬性'x'和'y'是getter-functions或2)在驗證不變性時拋出某種警報然后它可以作為一個事實上不可變的對象。
思考?
你可以使用Object.freeze(o);
在新的瀏覽器中使對象不可變。
因此, Point2D
可以像這樣實現:
var Point2D = function(x, y) {
this.x = x;
this.y = y;
Object.freeze(this);
}
現在,沒有新的屬性可以添加到Point2D
對象,並且它的現有屬性不能更改:
> var p = new Point2D(99, 123)
undefined
> p.x
99
> p.x = 7
7
> p.x
99
> p.foo = "This won't be added"
undefined
> JSON.stringify(p);
"{"x":99,"y":123}"
如果您只想鎖定對象而沒有添加任何新屬性,那么您可以使用Object.seal(o);
代替。 這將允許您改變現有屬性,但不能添加新屬性。
> var o = {x:1, y:2}
undefined
> Object.seal(o);
[object Object]
> JSON.stringify(o);
"{"x":1,"y":2}"
> o.foo = "This won't be added";
99
> o.x = 37 // Seal allows to mutate object
37
JSON.stringify(o);
"{"x":37,"y":2}"
freeze
和seal
是ECMAScript 5.1的一部分, 在這里更正式地描述
MDN聲明freeze
支持:
或者,您可以使用更實用的編碼樣式:
var Point2D = function(x, y) {
return function(prop) {
switch (prop) {
case "x": return x;
case "y": return y;
default: throw new Error("Property '" + prop + "' not supported");
}
};
}
用法如下:
> var p = Point2D(1,2)
undefined
> p("x")
1
> p("y")
2
> p("foo")
Error: Property 'foo' not supported
我知道無法使用此方法更改“屬性” x
和y
因為它們受Point2D
函數范圍的約束。 這種方法在javascript中並不常見(據我所知),但類似於如何在例如Scheme中實現消息傳遞/ OO。
如果您不必擔心舊版瀏覽器,可以查看Object.defineProperty
。
除此之外,我認為沒有太多選項,因為對象上的任何函數/屬性都可以在JavaScript中的任何位置重新定義。
在javascript中可以定義屬性getter和setter:
function Point2D(){
this.__defineGetter__("x", function(){
});
this.__defineSetter__("x", function(val){
});
}
但是,他們修改的基礎變量是可變的。
Point2D = function(x, y)
{
var privateX = x;
var privateY = y;
return {
getX: function()
{
return privateX;
},
getY: function()
{
return privateY;
}
};
};
var foo = new Point2D(20, 30);
console.log(foo.getX(), foo.getY());
由於privateX和privateY僅存在於構造函數的范圍內,因此只能通過構造函數(getX,getY)中定義的函數來訪問它們。
現在有一個新的javascript保留字const
。 const
使得運行時常量是不可變的。
通過使用Object.freeze
來防止對象的突變,你可以有點不可變。
投入一些ES2015可以幫助:
function Point2D(x, y) {
const instanceX = x,
instanceY = y;
return {
get x() { return instanceX; },
get y() { return instanceY; }
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.