4 ms·
I guess I need to be schooled by why not just use closures? var Person = function(first last) { this.fullName = function() { return first + "
by greggman 11y ago
I guess I need to be schooled by why not just use closures?
var Person = function(first last) {
this.fullName = function() {
return first + " " + last;
};
this.rename = function(newFirst, newLast) {
first = newFirst;
last = newLast;
};
};
Problem solved, you can't access `first` and `last` outside the class. You might retort "they're bigger" or something but just like everything else in JS they just need the right people to concentrate on them and they'll likely get optimized.
I don't get the relucatance to use the language's features rather than hacks (using naming standards and compilers to obfusticate names and then cross fingers) or other hacks (Symbol). Really? You Really want me to write code using Symbol? That's going to be awesome in the debugger. Let's add a watch to "weke30o304_first". Refresh, of shit it's now "gtgrf40r3fe_first", my watches all broke (T_T)
It also makes me sad the `class` spec didn't take that into account so you could use a closure with a `class`.
- braythwayt 11y ago> I don't get the relucatance to use the language's features rather than hacks Symbol is a language feature. As is accessing a property with `[` and `]`. Using the language's features as they were designed is not a hack. And I think we may see your browser's tooling improve when it natively supports ECMAScript 2015, instead of whatever is transpiled today. Now: Why do you think that properties named by symbols have this special property of being non-enumerable by default? Do you think it is just a coïncidence that it is useful for making a pseudo-private property? I do not think this particular pattern is a "hack," I think it is one of the use cases that were considered when designing symbols in the first place. But returning to the purpose of the article, whatever you or I may think of the performance of using closures to create private data, your pattern again supports the article's thesis: By making classes out of functions, objects, and prototypes, we can use the features of the language to extend a class's semantics. If there was a full-featured monolithic class system like Ruby, we might find that the scoping for methods is not like the scoping for lambdas, and thus we can't just use a closure when we want one. Your proposed solution leverages the exact same property of JavaScript as TFA.
- greggman 11y agoI guess I don't see obfusticating my own code as a good pattern. I gave the debugging example. Similarly serialization? With the closure solution I just do var Person = function(first, last) { var serializable = { first: first, last: last, }; ... With Symbol? I guess I just don't see making things more complicated as a positive pattern.
- braythwayt 11y agoIf you consider the use of symbols as “obfuscating your own code," use closures with my blessing. What, exactly, is the problem here? I don’t recall the article saying that symbols are the only way to do this, or the best way to do this out of all the options. I recall people saying similar things about closures for a while, until it caught on that closures and lexical scope are a natural part of JavaScript. TFA’s point is that ECMAScript 2015’s choice to keep classes as first-class functions with prototypes that are objects is what allows us to use all of the techniques we already have for first-class values, including returning them from functions. As I keep saying, using a closure (if that’s what you want to do) demonstrates the exact same thing, it works because a method is just a function. Now that we have established that I am not claiming that symbols are better than closures, I will warn you about an edge case: When you use compact method syntax, you do get something that an ordinary function does not provide, the `super` keyword. I do not know how to make that work in the case where you assign a function to an instance of an object. So if you want to override a function while calling the super-class’s implementation, it might be tricky to use the closure solution. That being said... I wouldn’t stay up late worrying about it.
- deleted 11y ago[deleted]
- serve_yay 11y agoI don't understand why you're talking about this like yours is the normal way and his isn't, or something. Symbols are "real" too.
- matchu 11y agoThe closure-based solution has been around for a long time; the symbol-based approach is new. My reaction to the article's approach was largely: okay, cool, this seems approximately as good as the closure-based solution; is there any reason for me to switch? Or is this just a cool toy example to show off classes-as-expressions?
- malkia 11y agoIt's not new in the some other language worlds, where your approach is also not new - I mean "make-symbol" in Common Lisp... Btw, once a symbol is created, is it ever garbage collected? (They are not in Common Lisp for example). Possibly on page reload (for javascript in browser) they would. But how about long-running javascript code?
- matchu 11y agoOkay, some better phrasing, then: the closure-based approach has been idiomatic for years, but the symbol-based idiom is new. What lessons have folks learned from trying these approaches in other languages? Which is more idiomatic, and why?
- deleted 11y ago[deleted]
- munificent 11y agoClosures give you object privacy. Symbols give you class (or whatever other scope you want) privacy. Take a look at this symbol example: let Person = (() = > { let firstNameProperty = Symbol('firstName'), lastNameProperty = Symbol('lastName'); return class Person { constructor (first, last) { this[firstNameProperty] = first; this[lastNameProperty] = last; } sameFirstName (otherPerson) { return this[firstNameProperty] == otherPerson[firstNameProperty]; } }; )(); Now try implementing sameFirstName() using closures. Good luck! :)
- rmrfrmrf 11y agosure :P (EDIT: Just kidding; the parent's point totally flew over my head). I've actually created classes this way in the past when I worked with a team of enterprise Java developers lol. You could also make magic getter/setter methods if you really wanted to get crazy with it. var Person = (function() { return function(firstName, lastName) { var privateVars = { firstName: "", lastName: "" }; this.getFirstName = function() { return privateVars.firstName; }; this.setFirstName = function(firstName) { privateVars.firstName = firstName; return this; }; this.getLastName = function() { return privateVars.lastName; } this.setLastName = function(lastName) { privateVars.lastName = lastName; return this; }; this.sameFirstName = function(otherPerson) { return this.getFirstName() == otherPerson.getFirstName(); } this.setFirstName(firstName); this.setLastName(lastName); Object.freeze(this); return this; } }()); var p = new Person("John", "Doe"); var q = new Person("John", "Smith"); var r = new Person("Jane", "Doe"); p.sameFirstName(q); // true p.sameFirstName(r); // false
- Cushman 11y agoThis isn't quite the same; the parent is pointing out that you can implement `sameFirstName` without exposing `firstName` publicly at all, not even as a getter.