4

Im a bit confused learning all the new ES6 vs ES5 syntax with javascript and when it comes to functions/classes with methods and calling upon those methods I can't really tell what is the "right way".

For example take this code:

function account(amount) {
    let cash = amount;
  this.setCash = function(amt)
  {
    cash = amt;
  }
  this.getCash = function()
  {
    return cash;
  }
}
var person = new account(100);
console.log(person.getCash()); //returns 100
person.setCash(150);
console.log(person.getCash()); //returns 150

Works like normal as expected (This is how I originally saw the methods being used when going through tutorials).

However i've seen this occasionally:

function account2(amount) {
    let cash = amount;
    function setCash(amt)
  {
    cash = amt;
  }
  function getCash()
  {
    return cash;
  }
  return{
    getCash,
    setCash
  }
}
var person2 = new account2(50);
console.log(person2.getCash()); //returns 50
person2.setCash(175);
console.log(person2.getCash()); //returns 175

Both of these work perfectly fine, and do as I think they should. However is one just an older way of doing it? or less correct maybe? This is my biggest barrier in learning JS right now, since ES6 is here there are so many different ways to do something as simple as making a "class" in JS with methods.

Personally the first way seems easier since you don't have to return the functions....but for example at work I see the 2nd way used mostly?

8
  • None of them is older. They are equally "old". And none of them is "better", they are just different. Choose the one that works for you in your particular case. Commented Apr 23, 2017 at 5:54
  • 3
    There is no single "standard" of doing anything in javascript. Do whatever suits you better. Commented Apr 23, 2017 at 5:55
  • 3
    The second way is "wrong" in that it doesn't make sense to call account2() with new if the function returns an object that isn't an instance of account2. (It still gets the desired result, but it is misleading.) Commented Apr 23, 2017 at 5:56
  • 1
    @msmith1114 it's not that it "should" be but using new does not make much sense with the second example. Commented Apr 23, 2017 at 7:24
  • 1
    Yes, the second way "should" be called without new as per your comment. It's not a syntax error either way (as you already showed, it works), but new causes an object to be created automatically with a specific prototype and then that object gets thrown away when the function explicitly creates and returns a different object. Commented Apr 23, 2017 at 12:31

2 Answers 2

4

If you removed new from the second version (more on that in a moment) then both of your examples are perfectly fine ways of creating an object with private data accessed via public get/set methods. Which one you would choose is personal preference, or dependent on whether you want to extend the functionality further with prototype methods, etc.

The reason I suggest removing new from the second version is that although both examples work, the first is a "normal" use of the new operator, but the second is an "incorrect" use of the new operator - not a syntax error, just semantically incorrect and potentially misleading for other people reading your code.

So why is that second use of new semantically incorrect? When you say var person = new account(100):

  1. A new object is created with a prototype that is account.prototype. That means the new object inherits any methods and properties of the account.prototype, and from its prototype, etc. (In your case you haven't defined any methods on the prototype, but you could.)
  2. Within the account() function, this will refer to the object created in step 1. Which is why you can attach methods to it with this.setCash = ...
  3. The new object is returned from account() by default. This step will not occur if there is an explicit return statement returning something else as in your account2() function.

So in the first example, person instanceof account is true, because the default object was returned. In the second example, person2 instanceof account2 is false, because a different object was returned - this is misleading for people reading your code, because when they see person2 = new account2() they might reasonably expect that person2 will be an instance of account2 but it's not. It's also a bit inefficient, because the JS engine goes to the trouble of creating an object for you and then you don't use it.

So the second example would be more "correct" without new, providing the same behaviour minus the unnecessary auto object creation:

var person2 = account2(50);

(Almost) any JS function that you write can be called with new, but there is a convention that we describe functions intended to be called with new as "constructors", and usually the function name is capitalised, so Account(), not account(). (The spelling doesn't change the behaviour, it's just an extra hint for people reading the code.)

Note that use of new isn't the only way to link objects to particular prototypes: it is the old-school-but-still-perfectly-valid way, but you can use Object.create() instead.

By the way, the behaviour in question is not new in ES5 or 6, though let and the shortcut object literal syntax in account2 are new.

Sign up to request clarification or add additional context in comments.

5 Comments

Quick question, why is person2 instanceof account2 false? I mean....person2 has access to all of account2's functions? So why wouldn't it be an instance of it? Or is it literally just a copy of it?
The instanceof operator tests whether the object has in its prototype chain the prototype property of the specified constructor. What person2 can access is irrelevant because it has a different prototype. It isn't a copy of account2. It has access to those functions because the returned object has references to them. Those functions have access to the local cash variable because of the closure (which is also why the functions in the account version can access their cash variable).
Closures and instances are two separate concepts, though they can work together.
So is the second way...not really a normal way to declare big function/classes (not using the ES6 way of class). and essentially the return functions are closure that have access to the private variable?
I wouldn't say it's not normal. It's fine. Some people prefer it, and you can still use Object.create() to set the prototype of the new object, etc. - if you Google you can find articles from people who think factory functions are better than constructors with new, and vice versa, so...
2

When you create an instance with new keyword this is returned implicitly where as when assign a function to a variable without new, you need to use return explicitly.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.