Неизменяемые типы в JavaScript - PullRequest
8 голосов
/ 13 октября 2011

Мне кажется, что неизменяемые типы невозможны в 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» являются функциями-получателями или 2) выдавали какое-то предупреждение при проверке неизменности, после чего оно могло бы действовать как де-факто неизменный объект.

Мысли?

Ответы [ 6 ]

19 голосов
/ 30 апреля 2014

Вы можете использовать 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 поддерживается в:

  • Firefox (Gecko) 4 (2.0)
  • Chrome 6
  • Internet Explorer 9
  • Опера 12
  • Safari 5.1

Кроме того, вы можете использовать более функциональный стиль кодирования:

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 (насколько я знаю), но он похож на то, как передача сообщений / OO может быть достигнута, например, в Scheme.

5 голосов
/ 13 октября 2011

Если вам не нужно беспокоиться о старых браузерах, вы можете посмотреть Object.defineProperty.

Кроме этого, я не думаю, что есть много вариантов, поскольку любая функция / свойство объекта может быть переопределено в любой точке JavaScript.

2 голосов
/ 14 октября 2011
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).

2 голосов
/ 13 октября 2011

В javascript можно определить методы получения и установки свойств:

function Point2D(){
    this.__defineGetter__("x", function(){

    });

    this.__defineSetter__("x", function(val){

    });
}

Однако изменяемые ими базовые переменные будут изменяемыми.

0 голосов
/ 11 марта 2017

Добавление ES2015 в смесь может помочь:

function Point2D(x, y) {
  const instanceX = x,
    instanceY = y;

  return {
    get x() { return instanceX; },
    get y() { return instanceY; }
  }
}
0 голосов
/ 04 апреля 2014

Теперь есть новое зарезервированное слово javascript const. const делает постоянные времени выполнения неизменными.

Примечание: const НЕ делает объекты или массивы неизменяемыми.

Вы можете быть своего рода неизменяемым, используя Object.freeze для предотвращения мутации объектов.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const http://caniuse.com/#search=const

DEMO

...