Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>There's only a couple of real technical differences between those two (pointed out by Bergi in the comments). The differences aren't likely to matter unless you're doing thousands and thousands of these. There's a <em>style</em> difference, which is subjective, but the technical differences are small. See the breakdown below for the gory details.</p> <p>At a high level, both forms create a new object, they both rely on a closure for the private member. The second way uses a bit more memory, because the function can't be garbage-collected after use, whereas in the first one, it can be. Similarly, the object created to be the function's <code>prototype</code> property is reclaimable in the first version, but not the second. The second way may also be less clear to some than the first (witness the questions below from @djechlin), not least because of the implicit return value, but that's a style point.</p> <p>Re your second question:</p> <blockquote> <p>Are there any other possibilities to implement private members?</p> </blockquote> <p>For one-off objects like yours, the way you're doing it is probably best (either form, really). But right now, there's <em>sort of</em> another way, and as of ES.Next (the next version of ECMAScript), there's a new truly private way. In both cases, though, it's more useful for when you're doing classes of objects rather than one-offs.</p> <p>More in <a href="http://blog.niftysnippets.org/2013/05/private-properties-in-es6-and-es3-and.html" rel="nofollow">this entry on my blog</a> (which also talks about the stuff coming with ES.Next), but I'll go into the most salient details here.</p> <p>The typical pattern for private members in classes of objects looks something like this:</p> <pre><code>function Foo(toBePrivate) { var privateMember = toBePrivate; this.method1 = function() { // ...do something with the truly private `privateMember` }; } Foo.prototype.method2 = function() { // ...doesn't have access to the truly private `privateMember` }; var f = new Foo("private stuff"); // f.method1() can use the private data // f.method2() cannot </code></pre> <p>The problem with it is that each and every object created via <code>new Foo</code> gets its <strong>own</strong> <code>method1</code> function. We don't get the reuse we get with <code>method2</code>, where there's only <em>one</em> of them shared by all objects created by <code>new Foo</code>. (This isn't necessarily a big deal with modern engines, which are able to reuse the <em>code</em> of <code>method1</code> even though a new <code>method1</code> <em>object</em> is created for each <code>Foo</code> object. But there are some development patterns that dynamically change the prototype, which are obviously unable to act on <code>method1</code> above.)</p> <p>Here's the nearly-private pattern we can do today:</p> <pre><code>var Foo = (function() { // Create a private name object for our private property var privateKey = makeRandomString(); // Our constructor function Foo(toBePrivate) { this[privateKey] = toBePrivate; } // Define the private property so it's non-enumerable Object.defineProperty(Foo.prototype, privateKey, { writable: true }); // Methods shared by all Foo instances Foo.prototype.method1 = function() { // ...use this[privateKey] here... }; Foo.prototype.method2 = function() { // ...use this[privateKey] here... }; return Foo; })(); var f = new Foo("private stuff"); // f.method1() can use the private data // f.method2() can too! // Both `method1` and `method2` are *reused* by all `Foo` objects </code></pre> <p>...where <code>makeRandomString</code> does exactly that, it gives us a new random string every time we call it.</p> <p>The property we create is not private, but it's really obscure. It doesn't show up in <code>for-in</code> loops (because the property we created is non-enumerable) and its name changes every time the code runs. So any code attempting to use the private data must first figure out the property name, which is a non-trivial exercise as that code can't get a list of the non-enumerable property names of the object. Naturally, though, one glance at the object in a debugger shows you the property and its value. The property is <em>really obscure</em>, but not quite truly private.</p> <p>This pattern is improved markedly by the stuff coming in ES.Next, the next version of ECMAScript. We'll get <a href="http://wiki.ecmascript.org/doku.php?id=harmony%3aprivate_name_objects" rel="nofollow">private name objects</a>, which are useful on their own and are also used by the <a href="http://wiki.ecmascript.org/doku.php?id=harmony%3aclasses" rel="nofollow">the new classses</a>.</p> <p>Here's how private names apply to the above:</p> <pre><code>// **ES.Next, not yet available in the wild** import Name from "@name"; var Foo = (function() { // Create a private name object for our private property var privateKey = new Name(); function Foo(toBePrivate) { this[privateKey] = toBePrivate; } Foo.prototype.method1 = function() { // ...use this[privateKey] here... }; Foo.prototype.method2 = function() { // ...use this[privateKey] here... }; return Foo; })(); var f = new Foo("private stuff"); // f.method1() can use the private data // f.method2() can too! // Both `method1` and `method2` are *reused* by all `Foo` objects </code></pre> <p>Properties created with private name objects never show up in <code>for-in</code> enumerations <strong>at all</strong>, and their names are not strings. Code <strong>cannot</strong> access a property whose name is a private name object without having <em>that specific name object</em>. Since the <code>privateKey</code> variable above is completely private to the <code>Foo</code> class, no other code can use that property. It's completely private. Naturally, these will show up in debuggers, but then, nothing is private from debuggers.</p> <hr> <p>@djechlin asked for a breakdown of exactly how each of your forms for a private member work, and it helps us understand the difference between them that Bergi highlighted:</p> <h2>Your first example:</h2> <pre><code>var myObject1 = (function(){ var privateMember = 42; return { publicMember: function() { return privateMember; } } })(); </code></pre> <p><em>(This list leaves out a few details that I don't think are relevant.)</em></p> <ol> <li><p>A property called <code>myObject1</code> is created on the current variable binding object (which may be <code>window</code> if this is global) with the value <code>undefined</code>.</p></li> <li><p>The function expression is evaluated: <br>A) A <code>Function</code> object to be created. <br>B) A blank object is created and assigned to the new function's <code>prototype</code> property. <br>C) A <code>constructor</code> property is created on that object and given a reference to the function. <br>D) A reference to the current variable binding object is stored on the function.</p></li> <li><p>The function is called, creating (amongst other things) a variable binding object for the execution context of the call.</p></li> <li><p>A property called <code>privateMember</code> is created and assigned to the variable binding object from Step 3.</p></li> <li><p>The value 42 is assigned to the <code>privateMember</code> property of the VBO.</p></li> <li><p>A blank object is created and given a prototype from <code>Object.prototype</code>.</p></li> <li><p>The inner function expression is evaluated, a <code>Function</code> object created (with a blank object for its <code>prototype</code> property and a <code>constructor</code> property put on that object, and with a reference to the current variable binding object [the one from Step 3]).</p></li> <li><p>That function is assigned to a property on the blank object from Step 5 as <code>publicMember</code>.</p></li> <li><p>A reference to the object from Step 6 is returned from the main anonymous function.</p></li> <li><p>That object reference is stored in the <code>myObject1</code> property created in Step 1.</p></li> <li><p>The main anonymous function (from Step 2) has no outstanding references, and so can be reclaimed by GC; and so the object referenced by its <code>prototype</code> property can also be reclaimed by GC.</p></li> </ol> <h3>Your second example:</h3> <pre><code>var myObject2 = new function() { var privateMember = 42; this.publicMember = function() { return privateMember; } } </code></pre> <p><em>(Again, some irrelevant details left out.)</em></p> <ol> <li><p>A property called <code>myObject2</code> is created on the current variable binding object (which may be <code>window</code> if this is global) with the value <code>undefined</code>.</p></li> <li><p>The function expression is evaluated: <br>A) A <code>Function</code> object to be created. <br>B) A blank object is created and assigned to the new function's <code>prototype</code> property. <br>C) A <code>constructor</code> property is created on that object and given a reference to the function. <br>D) A reference to the current variable binding object is stored on the function.</p></li> <li><p>A new, blank object is created and assigned its prototype from the anonymous function's <code>prototype</code> property.</p></li> <li><p>The function is called with the object from Step 3 passed in as <code>this</code>, creating (amongst other things) a variable binding object for the execution context of the call.</p></li> <li><p>A property called <code>privateMember</code> is created and assigned to the variable binding object from Step 4.</p></li> <li><p>The value 42 is assigned to the <code>privateMember</code> property of the VBO.</p></li> <li><p>The inner function expression is evaluated, a <code>Function</code> object created (with a blank object for its <code>prototype</code> property and a <code>constructor</code> property put on that object, and with a reference to the current variable binding object [the one from Step 4]).</p></li> <li><p>That function is assigned to a property on the blank object from Step 5 as <code>publicMember</code>.</p></li> <li><p>The function returns, and because it doesn't return an object, the result of the <code>new</code> expression is a reference to the object created in Step 3.</p></li> <li><p>That object reference is stored in the <code>myObject2</code> property created in Step 1.</p></li> <li><p>The main anonymous function (from Step 2) cannot be reclaimed by GC, because <code>myObject2</code>'s underlying prototype has a reference to it on the <code>constructor</code> property (and so both the function and the object assigned to its <code>prototype</code> property remain in memory).</p></li> </ol> <p>You could release the function (but not the object assigned to its <code>prototype</code> property) by adding this line inside it:</p> <pre><code>delete this.constructor.prototype.constructor; </code></pre> <p>That removes the reference to the function from the object assigned to its <code>prototype</code> property. That object remains as <code>myObject2</code>'s underlying prototype, but it no longer refers back to the function, so the function is eligible for GC.</p> <p>But at that point, we're well into obscurity land. :-) </p> <h2>Conclusions</h2> <p>So they're very nearly the same, with the small difference that the main anonymous function and the object on its <code>prototype</code> property aren't eligible for GC. It would take thousands and thousands of these for that to matter in the real world.</p> <p>(Side note: Some implementations may well defer some of the steps of creating a function&nbsp;&mdash; such as creating a blank object for its <code>prototype</code> property and setting its <code>constructor</code>&nbsp;&mdash; until/unless that <code>prototype</code> property is used, since of course in the <em>vast</em> majority of cases, it's never used, because the vast majority of functions are never used as constructor functions. So your first form may be <em>a little tiny teeny bit</em> more efficient because it can skip those steps. It's a difference that is unlikely to matter unless you're doing thousands of these.)</p> <hr> <p>FWIW, the first can also be written like this, if your concern is the number of lines, number of parentheses, or not liking the object literal, etc.:</p> <pre><code>var myObject1 = function(){ var obj = {}; var privateMember = 42; obj.publicMember = function() { return privateMember; }; return obj; }(); </code></pre> <p>As a matter of <em>style</em>, I prefer the explicit return, but that's a matter of style.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload