I delve into the OOP JavaScript. I am trying to figure out how to create objects with private methods and properties.

In JavaScript, you can create objects via new

 function Constructor() { var name = 'foo'; this.get_name = function() { return name; } } var foo = new Constructor(); 

And without

 function ConstructorWithoutNew() { var name = 'bar'; var that = {}; that.get_name = function() { return name; } return that; } var bar = ConstructorWithoutNew(); 

The first question is - is there a fundamental difference between these approaches? Under what conditions should this or that be used, or perhaps there is a third, more universal / productive / correct one?

  • one
    in the first case, the constructor is used and the instanceof operator will work, in the second, just the function returning the object is used - Grundy
  • @Grundy Ie, in JavaScript, is it still possible to create custom types? - torokhkun
  • one
    but somewhere it was written that it is impossible? :) - Grundy
  • And what do you understand as universal / productive / correct? What are the evaluation criteria? - Dmitriy Simushev
  • @DmitriySimushev so the fact of the matter is that I previously worked on a template - I designed it in UML, I wrapped interfaces, implemented them in classes, I create instances through new. And here ... you can create through the object literal, or through the constructor function ... to understand what technique to use when - torokhkun

1 answer 1

The difference of these approaches is that in the first case the inheritance mechanisms in js are activated, and in the second case, duck typing mechanisms are used.

When using the second method, the instanceof operator will not work - but then it can be "inherited" from the function, which cannot normally be done with prototypes.

But both methods are not ideal - in each of them a separate method is created for each object instance. When an (erroneous) attempt to apply such a method to a "foreign" instance of an object through call or apply , strange things are possible that will not be immediately apparent.

Therefore, the most modern way to create private fields is through symbols. In short: a call to Symbol("...") will give you some object that can be used as a field name, while calling the Symbol function again will give a new object. That is, if you “hide” a symbol, then the field will be private.

Here is an example, here the symbol is “hidden” using the “module” pattern:

 var Constructor; !function() { var sName = Symbol("name") Constructor = function Constructor() { } Constructor.prototype[sName] = "foo" Constructor.prototype.get_name = function() { return this[sName]; } }() var foo = new Constructor(); 

The variable sName not visible outside the module - and therefore there is no access to the private name field from the outside, although it is quite easy to access it from inside the module.

The characters at the time of writing this answer are supported, unfortunately, only by Chrome and Ognelis from the main browsers. But for other browsers (IE) you can use a polyfill:

 !function() { if (typeof window.Symbol === "function") return; var counter = 0; window.Symbol = function (name) { return "__" + name + "@" + ++counter; } }() 

Such a symbol will not have most of the properties of the "real" symbols - but to create almost-private variables, it is fine.

  • Why not return the constructor from the closure instead of using the global variable in your first example? - Dmitriy Simushev
  • @DmitriySimushev you can return something, but where can you save it then? In the global variable? Who cares? :) - Pavel Mayorov
  • one
    @ totorro.stackoverflow.com / q / 483559 / 178779 - Pavel Mayorov
  • one
    @totorro this syntax is used to declare a function and immediately call it. The result is an additional scope for local variables. - Pavel Mayorov
  • one
    @totorro, but it was possible instead ! just take this function in parentheses :) for example: (function(){...})() it would be clearer - Grundy