You can create an immutable object in JavaScript using the Object.freeze
, and an immutable reference using the Object.defineProperty
:
// Atribui a classe ao escopo global 'window'
Object.freeze(StaticTest);
Object.defineProperty(window, "StaticTest", {
value:StaticTest,
configurable:false,
writable:false
});
// Todas essas tentativas vão falhar silenciosamente:
// (ou lançar uma exceção, se o modo "strict" estiver ativado)
StaticTest = outroObjeto;
window.StaticTest = outroObjeto;
StaticTest.StaticAttribute = outroValor;
delete StaticTest.StaticAttribute;
As for preventing an object from being inherited , I do not know of any way to do that, and I do not think it's possible at all.
OO Classical vs. Prototypic
Notice that you asked about classes , but I gave my answer by speaking only of objects . Because? Simply because, strictly speaking, JavaScript does not have the concept of "classes".
In the classical object orientation used by the vast majority of languages that follow this paradigm, classes and objects (or instances) are distinct concepts: the class defines the "structure" and "behavior" of its objects, and each object belongs to to a single class. Class inherits from class, so instances of the specific class have structure and behavior similar to instances of the general class.
In prototypical OO, there are only objects. An object defines its own structure and behavior independently of the others. To reuse these features in other objects, they inherit directly from the existing object (here called prototype ), modifying whatever you want and keeping (sharing) the rest. There are no classes, just constructor functions .
Inheritance in JavaScript
For historical reasons, while JavaScript is conceptually a language that follows prototypical OO, its syntax tries to "hide" the fact - making it more a bit like the classic. The result is a "salad", as I will exemplify below:
// Objeto simples: sem classe, sem construtor
var obj = {
atributo:"planeta",
metodo:function() {
return "Olá, " + this.atributo + "!";
}
}
// Construindo um objeto que herda de "obj"
function herdarDeObj() { }
herdarDeObj.prototype = obj;
var obj2 = new herdarDeObj();
alert(obj2.metodo()); // "Olá, planeta!"
obj2.atributo = "mundo";
alert(obj2.metodo()); // "Olá, mundo!"
alert( obj.isPrototypeOf(obj2) ); // true
alert( obj === Object.getPrototypeOf(obj2) ); // true
// Sintaxe confusa
alert( obj === obj2.prototype ); // false
alert( obj2.prototype ); // undefined
alert( obj === herdarDeObj.prototype ); // true
alert( obj === Object.getPrototypeOf(herdarDeObj) ); // false
alert( Object.getPrototypeOf(herdarDeObj) ); // function Empty() {}
// (varia conforme o browser)
alert( obj2 instanceof obj ); // false
alert( obj2 instanceof herdarDeObj ); // true
herdarDeObj.foo = "bar";
alert( obj2.foo ); // undefined
obj.foo = "baz";
alert( obj2.foo ); // "baz"
As you can see, we have two objects obj
and obj2
in which the second inherits from the first (or: the first is a prototype of the second). However, JavaScript "hides" this simple relationship, forcing us to create a constructor method, assign it the prototype
property and invoke it using the new
keyword.
But note that obj
is not prototype of herdarDeObj
- it is a prototype of built objects using the new herdarDeObj()
command. The constructor is a normal function, so much so that its prototype is the "empty function".
Probably because of this fact (of the constructor defining everything about the object - both the initial attributes, placed in the body of the constructor through this.atr = val
, and the prototype, that of whom the object will inherit) with the "class" of the object. And for the convenience that this constructor method offers, rarely anyone uses [explicitly] prototypical inheritance in practice, so much so that there are plans to introduce classic OO concepts into future versions of JavaScript. Maybe someday, what you ask is in fact possible.
Conclusion
Since there are no classes in JavaScript, it does not make sense to speak of "static classes" (not even "static attributes" or "class attributes"). If you want to expose a collection of attributes and methods through a given name, the most natural is to do this using a simple object:
window.StaticTest = {
StaticAttribute:"O atributo estático diz: Olá Planeta!",
StaticMethod:function() {
return "O método estático diz: Olá Mundo!";
}
};
You can make the object and reference immutable, as I have explained, but can not prevent other objects from inheriting from it: anyone can create a new constructor function, assign StaticTest
to their prototype
, and call that function - producing objects that inherit from StaticTest
.