It is impossible to create a singleton in JavaScript, given the prototypical nature of the language. The vast majority of object-oriented languages use what we call Classical OO , where class inherits from class and object instance class:
classe A <== classe B (herda de A - sua "superclasse")
^ ^
| |
objeto 1 objeto 2 (não herda de objeto 2 - não diretamente, pelo menos)
In Prototypic OO , there are no classes, and object inherits from object:
objeto 1 <== objeto 2 (herda de objeto 1 - seu "protótipo")
JavaScript (in its current version) has prototype semantics only, but a bizarre syntax that makes seem that it implements Classic OO, when in fact this does not occur:
function A() { this.foo = 10; }
var objeto1 = new A();
function B() { this.bar = 20; }
B.prototype = new A(); // Vou chamar esse objeto de "anônimo"; poderia ser o próprio objeto1
var objeto2 = new B();
It seems that "class" B inherited from A, and the objects "instantiated the class", right? But the above code could also be spelled as follows:
var objeto1 = { foo:10 };
var objeto2 = Object.create({ foo:10 }, { bar:{ value:20 } }); // anônimo poderia ser objeto1
In both cases, anônimo
is the prototype of objeto2
. This means that any read access type objeto2.foo
will first see if the foo
property exists in objeto2
and, if it does not exist, it will return anônimo.foo
. Already in a script, it will create this property in objeto2
if it does not exist (or update, if it already exists). You can read more about how prototypes work in that related question .
The consequence of this, however, is that if you have a reference to an object nothing prevents you from creating another one that inherits from it:
var xyz = xyz || (function (){ // Essa função só será chamada uma única vez, garantidamente
this.foo = function() { ... };
})();
var abc = Object.create(xyz, { bar:{ value:20 } }); // Mas agora abc herda de xyz
abc.foo(); // Chamou o método foo de xyz, usando abc como this!
Although xyz
is immutable , or has "banned extensions" via Object.preventExtensions
or Object.seal
, none of this prevents it from being inherited. If there is a way to mark an object as "it is forbidden to use it as a prototype of other objects," I do not know. Only by preventing others from getting a reference to him ...
Finally, if it was not clear, creating an "empty" object inheriting from another would be the same as "creating another instance of your class". For all the methods of the first are available to be called, and the new object has a copy of all its properties - being able to change them or not. If any method of the old object assumes that it will always be called using xyz
as this
, calling it via abc
will violate this premise and may have negative consequences. That is, do not assume that a JavaScript object is guaranteed to be singleton .