6

Function scoping offers the only privacy in JavaScript.

So the canonical:

function Ctor(dep1, dep2) {
  this._dep1 = dep1;
  this._dep2 = dep2;
}

Ctor.prototype.foo = function() {
  // use this._dep1/2...
}

...is problematic in that it offers no encapsulation for the injected dependencies.

An alternative (albeit slightly different in terms of location of foo) that offers real encapsulation might be:

function factory(dep1, dep2) {
  return {
    foo: partial(foo, dep1, dep2), // or use bind (partial could be a library fn for partial application)
  };
}

function foo(dep1, dep2) {
  // use dep1/2
}

But I rarely see this pattern. Is there a good reason to not use the latter?

Ben Aston
  • 53,718
  • 65
  • 205
  • 331
  • 1
    To some extent, support for Symbol properties will make things better, as it'll be possible to create property keys that are guaranteed not to collide with other keys. However, they're still not fully "private". – Pointy Jun 15 '16 at 12:56
  • 1
    Vote for close - why?! – Ben Aston Jun 15 '16 at 12:56

2 Answers2

3

Simple: why?

"Privacy" is terrifically overrated. It doesn't hide anything from anyone who really wants it. Having "protected" or "private" members is purely for the programmer's benefit, specifically to indicate how a particular member is supposed to be used (this here is a public API, this here is not so please don't touch it unless you know what it does). That's all. A naming convention like starting underscores is perfectly enough to implement that. If a member name starts with an underscore, don't touch it, unless you know what you're doing.

There's no intrinsic need to bend over backwards further than that.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • In answer to your question: "because with `_foo`, when working in a shared codebase, you cannot be confident it is not being used because the name is 'just a name'". Confidence is significantly increased in the latter, improving the non-functional aspects of the code. – Ben Aston Jun 15 '16 at 12:50
  • 1
    If you have no confidence in your coworkers, making private members more private won't help you. That's a communication and/or review issue between programmers and not a technical issue to be solved. There are still many more things untrusted programmers are able to screw up than accessing private members. – deceze Jun 15 '16 at 12:52
  • There are lots of problems in software development. You name a few. Does that mean we shouldn't try and mitigate the risk posed by those problems? – Ben Aston Jun 15 '16 at 12:56
  • Yes, we should, but again: not all solutions are technical in nature. Making members "truly" private in Javascript requires quite some bending over backwards which often results in code which is less clear. Your first code example: everyone gets it; your second one: ...uh... what does this do? If the issue is with team members not respecting others' privacy, educate your team members, don't obfuscate your code. – deceze Jun 15 '16 at 13:01
  • How did we solve the problem of version control? With elaborate commenting techniques within Javascript? No: by external means. How do you solve the problem of a team trampling all over each others code? By talking to the people involved educating them how to work together. – deceze Jun 15 '16 at 13:03
  • "don't touch it, unless you know what you're doing." You've heard of Dunning–Kruger? I take your point by the way. I have heard it elsewhere too. I strongly disagree; but I can see your point. – Ben Aston Jun 15 '16 at 13:10
  • If your team regularly suffers from Dunning-Kruger, restate that as *"don't touch it unless you defined/wrote/created/spec'd it"*. – Assuming you're working with halfway competent adults, you don't need true privacy. If that basic assumption falls flat: first of all my condolences, and secondly you're then free to implement whatever restraints and madness that is necessary to keep your project from toppling over. But as a general rule: you don't need privacy as much as you think. – deceze Jun 15 '16 at 13:14
3

You already state the advantages of the second pattern. The disadvantages are:

  • you must either group methods by visibility (even if the private method is intimately related with a public one, but barely related to other private methods), or repeat all public methods in the object literal (which doesn't work well with jsdoc).

  • the code introduces a separate function object for every instance of your class, which sacrifices some performance (this usually doesn't matter, but sometimes might)

  • unlike private modifiers in many programming languages, this encapsulation can not be circumvented, even if misapplied and I really know what I am doing (historically, JavaScript has been an environment where anything goes, and many attribute its success to this extensibility)

meriton
  • 68,356
  • 14
  • 108
  • 175
  • "the code introduces a separate function object for every instance of your class" - even if the code uses `bind` directly e.g. `foo: foo.bind(null, dep1, dep2)`? – Ben Aston Jun 15 '16 at 13:23
  • Yes, I just tested it in Chrome: `foo.bind(null, 1, 2) === foo.bind(null, 1, 2)` returns `false`. – meriton Jun 15 '16 at 14:22
  • Ah yes you are right. Thanks for the confirmation. Also https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind – Ben Aston Jun 15 '16 at 15:08