How to choose OO design patterns for JavaScript

Through OO, I mean classic OO. I keep going back and forth between defining my “classes” (javascript has no traditional classes) using a module template for privacy and using object literals to create a collection of “public statics”.

I have no leadership when I create “classes” that let me determine which organization to use. Well, except that my code skips both jshint and jslint w / no options.

I work with approximately 1,500 lines of code, so I need a “guiding force” before the code becomes unmanageable and I have to trick it.

I know very well the different ways to write "classes" in JavaScript. Those taught by JavaScript web applications written by Alex McCau, as well as the many ways listed here at SO.

However, when using the application, I just don’t know which method to use.

The simplest is the set of methods and variables in the object literal:

var public_statics = { public_func: function () {}, public_var: "hello" } 

and the most difficult is IIFE.

 (function(){ var private_var; function private_func(){ } })(); 

How do you know which one to use, or the many options inside?

For a specific example: how about a controller in MVC.

Currently (and some of them are randomly selected) I am implementing a controller as follows:

 var Co = {}; Co.Controller = function(){ // 'classes' from Mo are called here // 'classes' from Su are called here } 

then I stick to another management-related method with Co.

How to choose an OO usage style?


Update

My library is currently divided into 4 namespaces:

 var Mo = {}, Vi = {}, Co = {}, Su = {}; 

Model, View and Controller should be understandable and (Su) pport for all "classes" not contained in MVC, for example, DOM access, effects, debugging code, etc.

What OO style should I use to further organize this library / code?

Example "Class" of the controller:

 /** ** Controller */ Co.Controller = function (o_p) { var o_p_string_send; Su.time(); o_p = Mo[o_p.model].pre(o_p); if (o_p.result !== 'complete') { o_p_string_send = JSON.stringify(o_p); Su.time(); //Su.log(o_p_string_send); Co.serverCall('pipe=' + o_p_string_send, function (o_p_string_receive) { Su.time(); //Su.log(o_p_string_receive); o_p.server = JSON.parse(o_p_string_receive); Mo[o_p.model].post(o_p); Su.time(true); Su.log('Server time: [' + o_p.server.time + ']'); }); } }; 
+6
source share
3 answers

IFFE often confused to read and personally, I have no idea why they have become so popular. I think the code should be easy to read and concise. Trying to mimic language behavior that is not part of the language specification is often a very stupid idea.

For example, JavaScript does not support multiple inheritance, polymorphism, or many other interesting paradigms. Therefore, many times we see people trying to create these crazy ways of sorting “kind”, having polymorphism or private members, etc. In JS. I think this is a mistake.

I am currently working as a kind of hobby project in the high-performance JS data structures library (I try to beat Google's closure and many others). Based on the background of C ++ and Java, I always like material classes, and I love inheritance, etc. Etc. Let me share some code snippets with you. At first, I thought I was smart because I wrote things like this:

 function __namespace(n, v) { return {"meta":{"namespace":n,"version":v}}; } var FJSL = FJSL == undefined ? new __namespace("Fast JavaScript Library", 0.1) : FJSL; __using = function(parent, child) { clazz = new child(); clazz.super = new parent(); if (clazz.super == undefined) return clazz; for (a in clazz.super) { for (b in clazz) { if (a == "constructor" || b == "constructor") continue; if (clazz[b] === clazz.super[a]) continue; if (a == b && typeof clazz[b] != typeof clazz.super[a]) throw "Typesafety breached on '" + a + "' while trying to resolve polymorphic properties."; if (a == b && typeof clazz[b] == typeof clazz.super[a]) { clazz["_"+a] = clazz.super[a]; } else if (clazz[a] == undefined) { clazz[a] = clazz.super[a]; } } } return clazz; }; 

And I used it like this (in the simple queue example):

 FJSL.Array = function() { this.data = []; this.contains = function(idx, element) { for (var i = idx; i < this.data.length; i++) { if (this.data[i] === element) return i; } return -1; } this.size = function() { return this.data.length; } } FJSL.Queue = function() { return __using(FJSL.Array, function() { this.head = 0; this.tail = 0; this.enqueue = function(element) { this.data[this.tail++] = element; }; this.dequeue = function() { if (this.tail == this.head) return undefined; return this.data[this.head++]; }; this.peek = function() { return this.data[this.head]; }; this.size = function() { return this.tail - this.head; }; this.contains = function(element) { return this._contains(this.head, element); }; } )}; 

You will notice how I am in far-fetched inheritance (Array is used in the queue, har har, I'm smart). However, this is an absolutely insane expression for a) to read and b) to understand . I could not help but recall this meme:

enter image description here

Let me show you functionally equivalent code if I don’t try to make all this fancy before and after processing:

 FJSL.Queue = function(opts) { this.options = opts; this.head = 0; this.tail = 0; this.data = []; }; FJSL.Queue.prototype = { add : function(element) { this.data[this.tail++] = element; }, enqueue : function(element) { this.data[this.tail++] = element; }, dequeue : function() { if (this.tail == this.head) { return undefined; } return this.data[this.head++]; }, peek : function() { return this.data[this.head]; }, size : function() { return this.tail - this.head; }, contains : function(element) { // XXX: for some reason a for : loop doesn't get JIT'ed in Chrome for (var i = this.head; i < this.data.length; i++) { if (this.data[i] === element) { return true; } } return false; }, isEmpty : function() { if (size) { return true; } return false }, clear : function() { this.data = []; } }; 

Obviously, I will have to duplicate the prototype constructor for any other structures that can use the array, but what I'm trying to do is much clearer, even a novice JS programmer can tell what is happening. Not only that, but if people want to change the code, they know exactly where to go and what to do.

My suggestion doesn't go crazy, trying to get JS to behave like C ++ or Java. It will never be. And yes, you can fake the inheritance of both private / public / protected members, but JS was never meant to be. I think the consequences of having such bloated code (which tries to mimic non-standard behavior) greatly burden high-performance web applications, etc.

In short, I suggest using an object literal:

 var public_statics = { public_func: function () {}, public_var: "hello" } 

Easy to understand, easy to modify and easy to expand. If your system is fragile enough to crash and burn, if someone accidentally changes a private variable, you just need to document it.

+2
source

I personally prefer IIFE simply because you can make methods private. Otherwise, you will need to make some strange convention with underscores.

Also, stylistically, if you encapsulate it in a function, you have the option of making semicolons - your plain old javascript. The requirement that each line in the object literal end with a comma seems ridiculous to me.

+1
source

Since the JavaScript language itself is implemented in different ways, that is, it is different for each browser, you already need to start with inconsistency.

JavaScript does not support direct classic inheritance. (It supports prototypical inheritance).

For my needs I will choose not to implement classical inheritance. This is not ideal bc classic inheritance allows you to directly implement the best practice of OO - encapsulation, inheritance and polymorphism.

However, I prefer to wait until the language directly supports OO through classical inheritance or the like.

At the same time, I'm just using basic prototypal inheritance to help enable code reuse.

0
source

Source: https://habr.com/ru/post/923505/


All Articles