0

I'm struggling with my JS code structure that's becoming apparent during my unit testing attempts. I'm used to the class structure, but I'm a bit lost in the JS world where there aren't any classes. I'm looking for a way to organize my code in the traditional class/constructor architecture. Here's what I have:

function ddGridSelector(primaryId, templateDefault, gridObj) {
    //set the variables
    this.primaryId = primaryId,
    this.defaultTemplate = templateDefault,
    this.gridObj = gridObj,
    this.gridObj.searchVal = '',

    this.init = ddgs_init
}

function ddgs_init(ddgs_obj) {
    ddgs_setDefaultTemplate(ddgs_obj);
    ddgs_initGrid(ddgs_obj);
    ddgs_initKendoWindow(ddgs_obj);
    ddgs_initKendoButton(ddgs_obj);
    ddgs_initResetButton(ddgs_obj);
    ddgs_addGridEventListener(ddgs_obj);
}

function ddgs_setDefaultTemplate(ddgs_obj) {
    //doing stuff
}

function ddgs_initGrid(ddgs_obj) {
    //more stuff
}

To call any of these...

var ddGridSelector_new = new ddGridSelector('PrimaryIdentifier', templateDefault, gridObj);

ddGridSelector_new.init(ddGridSelector_new);

It seems really redundant to pass my object to my function that's specified in my constructor so I'm sure I'm missing something obvious here. Really would appreciate some guidance on the matter. I think I'm close to being on a good path.

Smak
  • 95
  • 12
  • [There is `class` syntax in JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes). Just make sure to not apply it where it doesn't fit, but you already have a traditional constructor. – Bergi Aug 14 '17 at 16:15
  • Maybe you want to learn about the [`this` keyword](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this) before. – Bergi Aug 14 '17 at 16:18

3 Answers3

2

ES5 Way

You can do "functional classes" like this, which are pretty self explainable:

function User(name) {
  // name is thus "private" here because it's
  // not put under "this.name"

  this.sayHi = function() {
    alert(name);
  };
}

let user = new User("John");
user.sayHi(); // John

There's also the prototype class pattern as well:

function User(name, birthday) {
  this._name = name;
}

User.prototype.sayHi = function() {
  alert(this._name);
};

let user = new User("John");
user.sayHi(); // John

Source/Tutorial with the examples listed here

ES6+ Way

In ES6 you can declare classes in a way that looks more like traditional programming languages:

class User {

  constructor(name) {
    this.name = name;
  }

  sayHi() {
    alert(this.name);
  }
}

let user = new User("John");
user.sayHi(); // John

However you will need a transplier like Babel or Typescript to compile it down to web compatible code if you are targeting platforms such as IE (all versions), Opera Mini, and the Android Browser (4.4.x, ~16% of all Android versions in the field) (web compat sources), or things such as Cordova on older iOS devices (< 10, UIWebView, etc).

Node.js should have support for classes from 4.8.4(!) and above, surprisingly enough (source).

Michael Fedora
  • 508
  • 4
  • 10
  • You don't need a transpiler to work with classes nowadays: https://caniuse.com/#feat=es6-class – lilezek Aug 14 '17 at 16:36
  • 1
    I chose this answer because the sources provided helped me to understand the logic behind your reasoning. That and any questions I had were easily answered by referencing those said sources. Thank you! – Smak Aug 14 '17 at 18:17
0

but I'm a bit lost in the JS world where there aren't any classes.

But... there are!

class ddGridSelector {
    constructor(primaryId, templateDefault, gridObj) {
        //set the variables
        this.primaryId = primaryId,
        this.defaultTemplate = templateDefault,
        this.gridObj = gridObj,
        this.gridObj.searchVal = '',
     }

     init() {
        this.setDefaultTemplate();
        this.initGrid();
        this.initKendoWindow();
        this.initKendoButton();
        this.initResetButton();
        this.addGridEventListener();
    }

    setDefaultTemplate() {
        //doing stuff
    }

    initGrid() {
        //more stuff
    }
}
lilezek
  • 5,800
  • 19
  • 43
0

I tend to love this structure for a class-like layout when I want to avoid new features. It gives you a private scope where you can scope functions and shared variables as you need them and lets you separate out a "constructor" and public methods on the prototype.

var MyType = (function () {
    function MyType() {
        //My Constructor
    }

    MyType.prototype = {
        constructor: MyType,
        publicMethod: privateMethod
    };

    function privateMethod() {
        ...
    }

    return MyType;
}());

The outer scope runs immediately and keeps the global namespace clean. We augment the private function with prototype instance methods, define any "private" methods needed, and return the private type after setup. This lets you instantiate a class like normal and call any methods.

var example = new MyType();
example.publicMethod();
Marie
  • 1,891
  • 12
  • 27
  • Private-like functions increase the memory usage a lot. I would not recommend this, as it will have a negative impact in memory usage. – lilezek Aug 14 '17 at 16:19
  • I have never heard that before. Do you just mean defining them and referencing them in the prototype vs using an anonymous function in the prototype? – Marie Aug 14 '17 at 16:21
  • Yes, read this https://philipwalton.com/articles/implementing-private-and-protected-members-in-javascript/#the-problems – lilezek Aug 14 '17 at 16:22
  • I dont think that applies to this code. I am not implementing an object store, just a prototype for new instances. – Marie Aug 14 '17 at 16:23
  • It applies for `privateMethod`, which is hidden to the public scope and stores a closure of the elements of the class. – lilezek Aug 14 '17 at 16:24
  • You can check it here too: https://stackoverflow.com/a/33533611/2832398 – lilezek Aug 14 '17 at 16:26
  • Both of those are talking about creating scoped instance privates and storing references in relation to the constructor. My recommendation is to use the above structure for scoping public instance methods and private static methods (which would still require the context be passed) – Marie Aug 14 '17 at 16:35
  • Sorry, I've mistook it because it says privateMethod, not privateStaticMethod which is what you were building. – lilezek Aug 14 '17 at 16:38