JavaScript: Using dedicated functions or general purpose functions with arguments? - javascript

I wonder which approach is better for creating functions in JavaScript classes:
Having a list of functions each dedicated to one specific operation.
Having a general purpose function that takes arguments to decide what to execute.
My belief is the first option provides a nice interface but may cause redundant code, and second option is clean and flexible but may become confusing to use.
I really did not know how to ask this question, so I would like to explain it by a code example.
Suppose we have these Classes for printing names of creatures.
class GeneralPurposePrint {
constructor (args) {
this.isHuman = args.isHuman || false;
this.isOld = args.isOld || false;
this.name = args.name || "Nameless"
}
//This is what I mean by "general purpose function"
//arguments may as well come with the printName functions...
printName(){
const type = this.isHuman ? "the human" : "the animal";
const age = this.isOld ? "Old" : "Young";
console.log(`${age} ${this.name} ${type}`)
}
}
class DedicatedPrint {
constructor (name) {
this.name = name;
}
//And by dedicated functions I mean the following functions here
printOldHuman() {
console.log("Old human", this.name, "the human")
}
printYoungHuman() {
console.log("Young", this.name, "the human")
}
printOldAnimal() {
console.log("Old", this.name, "the animal")
}
printYoungAnimal() {
console.log("Young", this.name, "the animal")
}
}
This question is out of pure curiosity and maybe it's best to use both of the approaches. And please don't mind the funky code example I wrote, you may think of the similar structure for a class for choosing a sorting algorithm, a type of connection, creating a shape or such.

Thats rather a design decision, so you should ask yourself does GeneralPurposePrint really get old or is it really sometimes human and sometimes not? If not that definetly shouldn't be properties of the class. To reduce the redundant code of the second approach you could just pass in arguments to the method:
printName(old, human) {
console.log((old ? "Old" : "Young") + this.name + (human ? "the human" : "the animal"));
}

Related

why MDN argues that JS classes "may cause an error"?

Edit In regard of Barmar request, I upload this screenshot. As Jake claims, this is about that statement.
In this article MDN explains some details on JS inheritance, including a meant demonstration of why JS classic model of inheritance is safer than JS classes. They did many useful things in this text, but I don't see this particular point demonstrated. Could somebody point out the MDN arguments that demonstrate how traditional syntax is safer than classes syntax?
Thank you
Bonus: I did this short version of "The employee example" implemented in the mentioned article. According to this, traditional syntax is not safer, but rather longer and difficult to follow:
//TRADITIONAL SYNTAX
function Participant ({gender, tastes}){
this.gender = gender;
this.tastes = tastes || [];
}
function NotPayer({gender, tastes, role}){
this.role = role || 'kid';
this.base = Participant;
this.job = 'Not Valid';
this.base({gender, tastes});
}
NotPayer.prototype = Participant.prototype;
const kid1 = new NotPayer({role: 'nephew', gender: 'male', tastes: ['golf']});
console.log(kid1.gender); //male
const kid2 = new Participant({gender: 'female'});
console.log(kid2.gender); // female
//MODERN SYNTAX
class Participant {
constructor({gender, tastes}){
this.gender = gender;
this.tastes = tastes || [];
}
}
class NotPayer extends Participant {
constructor({gender, tastes, role}){
super({gender, tastes});
this.role = role || 'kid';
}
}
const kid1 = new NotPayer({role: 'nephew', gender: 'male', tastes: ['golf']});
console.log(kid1.gender);//male
const kid2 = new Participant({tastes: ['dance'], gender: 'female2'});
console.log(kid2.gender);// 'female2'
The text in article is a caption for the code sample below it. It says
JavaScript (using this may cause an error for the following examples)
and then goes on to show an example of class syntax. Immediately following that example is a caption saying
JavaScript ** (use this instead)
followed by an example of a (constructor) function syntax.
It then shows how Java does classes. Then the article talks a little about prototypal inheritance, a key part of JavaScript's object oriented design prior to the introduction of classes, and follows up with examples of that type of inheritance.
It is in these examples where, if one used the class syntax example introduced originally, the code would fail.
Just for giggles, here's a Stack Snippet showing what happens:
class Employee {
constructor() {
this.name = '';
this.dept = 'general';
}
}
function Manager() {
Employee.call(this);
this.reports = [];
}
Manager.prototype = Object.create(Employee.prototype);
Manager.prototype.constructor = Manager;
console.log(new Manager());
The error that arises (Uncaught TypeError: Class constructor Employee cannot be invoked without 'new') when you click Run code snippet here (on a suitably modern browser) is what that "using this may cause an error" text is talking about. That "for the following examples" is a key part of the phrase.
The MDN warning regards that the examples developed in the article could not run in some engines, rather than suggests that traditional syntax is better than modern syntax. As Ashish and Jake pointed out this is related to JS engines support for classes syntax.
Even though, I think that the MDN article could be even more explicit about that (since, the argumentation regards many complex subjects.)

Prototype (separately) and constructor (separately) on real examples from sites?

Read about constructors in functions:
function Animal(name) {
this.name = name;
this.canWalk = true;
}
var animal = new Animal("Hedgehog");
and also about prototypes:
Animal.prototype.draw = function () {
}
But until the end I did not understand exactly how they reduce the code and, in principle, improve the life of programmers. Why? Because it is better understood on real examples from sites and not on examples of animal or "hedgehogs" of all sorts.
An example from my personal experience: I started the cycles well when I needed to prescribe a function for 30 images, but instead of 30 functions I passed one function into a cycle and reduced it the way the code, so I understood the whole essence of the cycle, and not just memorized its anatomy. That would be for learning resources to make examples of real projects beginners would not ask 100 questions of the same type.
Therefore, I have such questions:
Can you write here how the code would look at first without a prototype and then with a prototype on some small example from the site? Or an example that could be implemented on which site.
Can you write here how the code would look at first without a constructor and then with a prototype on some small example from the site? Or an example that could be implemented on which site.
But do not post in the responses or comments a link from the GitHuB with a large code. Just give a small example here. And it is desirable not an example from the game, but from the site
Using an object constructor is a way to initialize an instance with a specific functionality. In most cases it is used to initialize properties with values (like in your code), but can be used for other things as well.
Let use more realistic example - I can initialize a few users object simply by object literals:
const user1 = {
id: 'usr123',
name: 'Max',
questions: 4
}
const user2 = {
id: 'usr124',
name: 'Danny',
questions: 2
}
But there are few problems with this approach.
First, it can be tedious when used a lot.
Second, it's harder to distinguish it from other objects.
Both of these issues can be solved with construction function:
function User(id, name, questions) {
this.id = id;
this.name = name;
this.questions = questions ? questions : 0;
}
const user1 = new User('usr123', 'Max', 4);
const user2 = new User('usr125', 'Ben'); // default questions value would be 0
const isUser = user1 instanceof User; // true
Prototype is a special object which can be used on Objects which has a constructor function (Well, all objects are descendant of Object, but let's leave this aside for a moment). The basic idea is - if I have 100 user objects - I might have some use for have a special properties or logic which relevant for all of them, and not specific for a single instance. For example, let's assume that in case of error, I would like to log all the data of the users.
I can create a special function which get and object and do this:
function userToString(user) {
return user.id + ':' + user.name + '[' + user.questions + ']'; // usr123:Max[4]
}
This would work, but harder to maintain, since it is not really part of "User".
I large projects I would probably put this function in a file with other utilities function, and call it every time i would like to use it.
Another option is to include it as part of the prototype:
User.prototype.toString() {
return this.id + ':' + this.name + '[' + this.questions + ']';
}
user1.toString(); // usr123:Max[4]
I would strongly suggest to using ES6 standard (at least). It's exist for several years, it looks much more intuitive and do some of the complex work for you.
In ES6 this code would look like this:
class User {
constructor(id, name, questions) {
this.id = id;
this.name = name;
this.questions = questions ? questions : 0;
}
toString() {
return this.id + ':' + this.name + '[' + this.questions + ']';
}
}
Look nicer isn't it? but it basically the same. This ES6 syntax is simply sugar coating for the older syntax you've included in your question.

Javascript: How to get the parent key inside a function?

I've some functions, stored in a collection/array and would like to get the key (function-name) without retyping it. Is there any short way to access it?
var functions_collection = {
"function_x": function() {
var name = "function_x";
// name = this.key; <- how to get the key/function-name "function_x"?
// some more code like:
$(".function_x .button").val();
alert(name);
}
}
Edit: I'd like to avoid retyping the "function_x" inside the function itself and prefer to call it like this.key.
Sorry for the weird topic and thanks in advance!
Solution: A lot of good answers, but I was just looking for this snipped:
Object.keys(this)
I'm not sure it's what you want but you can do this :
var functions_collection = {};
(function(name){
functions_collection[name] = function(){
// use name, which is the function
alert(name);
};
})("function_x");
I'm not really sure it's better. But depending on your (unspecified) goal, there's probably a better solution.
To get the name of the objects keys, you can use Object.getOwnPropertyNames(this) or in newer browsers just Object.keys(this), and that will get you an array of all and any keys the this object has :
var functions_collection = {
function_x: function() {
var name = Object.keys(this);
console.log(name);
}
}
FIDDLE
In my opinion you´d need to change you above code since you are having anonymous functions which have no name - a change like this should work:
var functions_collection = {
'function_x' : function function_x () {
var myName = arguments.callee.name;
alert(myName);
}
}
see http://jsfiddle.net/9cN5q/1/
There are several ways you could go here. Some are good ideas, some are not.
First, some bad ideas
Bad idea: arguments.callee.name
This translates most directly to what you ask. arguments.callee is
a reference to the function you're currently in. However, it's
considered bad
practice,
and you should avoid using it unless you have a really good reason.
Bad idea: Currying
After constructing the function, bind its own name into it as a parameter:
var functions_collection = {
"function_x": function(name) {
alert(name);
},
//more functions
};
for (var name in functions_collection) {
if (typeof functions_collection[name] === "function") {
functions_collection[name] =
functions_collection[name].bind(functions_collection, name);
}
}
Currying is useful for lots of things in JavaScript, and it's a great idea in many situations. Not here, though, and I'll explain why below.
Bad idea: Use a local parameter and iterate through the containing object
var functions_collection = {
"function_x": function(name) {
alert(name);
},
//more functions
};
for (var name in functions_collection) {
if (typeof functions_collection[name] === "function") {
functions_collection[name](name);
}
}
Of course, the obvious problem with this one is that you might not want to call every function in the collection at once. The more fundamental problem is that it continues the trend of dangerously tight coupling. This is a bad thing, potentially a Very Bad Thing that will cost you all kinds of headaches down the line.
Now the "right" way
Change your whole approach. Forget trying to recycle class names from your HTML; just keep it simple.
Good idea: Use a local variable
Who cares what you name your functions? If you know which HTML classes you want them to touch, just code them that way.
var functions_collection = {
"function_x": function() {
var name = "function_x"; //or "button" or any other class name
alert(name);
},
//more functions
};
functions_collection.function_x();
Good idea: Pass a parameter
You're already calling the function, right? So there's probably already code somewhere with access to the name you want.
var functions_collection = {
"function_x": function(name) {
alert(name);
},
//more functions
};
functions_collection.function_x("function_x"); //or any other class name
Now you can use function_x on any class in your HTML, even if it doesn't match the function name:
functions_collection.function_x("function_y");
functions_collection.function_x("class_z");
functions_collection.function_x("button");
I've saved the simplest for last because I think you're making a mistake by trying to be "clever", if that makes sense. There are significant risks in your approach, and the payoff isn't going to be worth it.
Why the bad ideas are bad and the good ideas are good
Other than the arguments.callee.name option, the reason 2 and 3 are bad in this case is tight coupling. You're coupling function_x to the structure of functions_collection; you're coupling behavior to a variable name; and worst of all, you're coupling JS variables to the class names of HTML elements. This will make your code extremely fragile, and when you want to change something (and you will), get ready for a world of hurt.
For example, what happens if you reorganize your HTML? The page probably breaks, since the structure of your JS has to match the classes in your HTML/CSS. You'll have to rename or rewrite functions_collection and all others like it, or else you'll have to carefully plan new HTML around the JS you already have.
What happens if you want to use a JS minifier? Depends, but if you allow it to change member names in object literals, it completely breaks everything and you have to start over with one of the "good" ideas.
Now, what do you get in exchange for this inflexibility? You save an extra line at the beginning of each function. Not worth it, IMHO. Just bite the bullet and keep it simple.
Supposing that the variable name has the same name as its containing function:
var keys = [];
for (var p in functions_collection) {
if (typeof(functions_collection[p]) == 'function') {
keys.push(p);
}
}
And there you have it, an array with all the function names.

Is trying to imitate a interface/abstract class in javascript bad practice

I am writing some code in Node.js that jumped out at me as being better structured using the strategy pattern. Coming from .Net I would create the interface the rest were based on and move from there, in JavaScript this is not so clear cut.
I understand as a prototypical language JavaScript does not have the notion of interface inheritance, so I am not sure what I have done is a smell or not, as I cant seem to find references, apart from one blog post which tries to infer an interface by using a base abstract class which forces the inheriting classes to implement the function (as it throws).
My base class
QueryStrategy = function () {
};
QueryStrategy.prototype.create = function(){
throw new Error("Not Implemented");
}
module.exports = QueryStrategy;
Implementation 1
var util = require('util');
var QueryStrategy = require('./queryStrategy');
SelectQueryStrategy = function (query) {
this.parameters = query.parameters || [];
this.entity = query.entity || '';
};
util.inherits(SelectQueryStrategy, QueryStrategy);
SelectQueryStrategy.prototype.create = function () {
var self = this,
params = self.parameters,
paramList = self.parameters.length >= 1 ? '' : '*';
for (var i = 0; i < params.length; i++) {
var suffix = i === (params.length - 1) ? '' : ', ';
paramList = paramList + params[i].key + suffix;
}
return util.format("SELECT %s FROM %s", paramList, self.entity);
};
module.exports = SelectQueryStrategy;
Currently the base does not have any shared functions, or properties. Shared functions will come, properties, because of the prototypical chain search i didn't see the point of adding the "shared" properties as they are overwritten by the instances created (please if this is wrong, let me know).
Is this an acceptable approach or should I disregard inheritance in this instance. There may be some type checking and it would make it easier if your could infer the the type to one (i.e. they must all be of the Type QueryStrategy) but I don't want my .Net prejudice to take over here.
Alternative Approach
Firstly, i am not trying to sell books here, i am just reading a lot around the subject with books that i have, but want to give credit where its due.
Based on the couple of comments, it is correct to say that the type inference won't really make any difference here and possibly should be just left down to Duck Typing to check, and maybe trying to slot something in that is not defined in the language is not the best approach. I have read in Addy Osmani Javascript patterns about interfaces, although my implementation was not the same, and although interface usage is acceptable, it is probably not needed.
It might be simpler to keep the strategy approach but with a different implementation, one that is outlined in Javascript Patterns by Stoyan Stefanov, where you have one implementation and based on some form of configuration you know which strategy to use.
Pseudo Sample
QueryBuilder = function () {
this.types = [];
}
QueryBuilder.prototype.create = function (type, query) {
var strategy = types[type];
strategy.create(query);
};
QueryBuilder.types.Select = {
create: function (query) {
params = query.parameters,
paramList = query.parameters.length >= 1 ? '' : '*';
for (var i = 0; i < params.length; i++) {
var suffix = i === (params.length - 1) ? '' : ', ';
paramList = paramList + params[i].key + suffix;
}
return util.format("SELECT %s FROM %s", paramList, query.entity);
}
};
That might be a cleaner way to go, one thing i am note sure about is if I should add types to the prototype, but I guess in this simple case it wouldn't be needed, but in a more complex scenario you could have a lot of strategies and in one file might need to be abstracted out.
is this a more acceptable approach?
What I ended up with
I looked around and tried to understand more about Duck typing, Pros and Cons etc. and tried to simplify my design based on some of the comments and answer I received. I stuck with the strategy-ish approach in that every strategy defined the same function(s), essentially encapsulating what varied across the implementations and giving them a common contract for want of a better term.
One thing that changed was the base class/interface which, as correctly pointed was not doing anything constructive was removed, each strategy is independent (so not 100% in the classical representation of the pattern) they, as stated just define the same create function.
From the place where the nested ifs and switches once belonged has been replaced with a single switch which decides which query strategy to use based on the type of query type requested. This could be re-factored into a factory later on, but for now it serves its purpose:
Query.prototype.generate = function () {
var self = this,
strategy = undefined;
switch (this.queryType) {
case "SELECT":
strategy = new Select(self);
break;
case "INSERT":
strategy = new Insert(self);
break;
case "UPDATE":
strategy = new Update(self);
break;
case "DELETE":
strategy = new Delete(self);
break;
}
return strategy.create();
};
Each strategy is independently tested, and i feel this is easier to maintain as if something fails, it will fail in one place and investigation will be easier based on the unit tests. Obviously there is a trade off, more files, and a slightly more complex structure...we will see what happens.
It is an acceptable approach but it isn't really going to benefit you in any way, and may make this piece of code more difficult to maintain. The Strategy patterns are really only beneficial in languages with static typing. You could look into TypeScript, as another commenter mentioned.
In JavaScript you're going to rely more on "Duck Typing"...If it looks like a duck, smells like a duck, it's probably a duck.
http://en.wikipedia.org/wiki/Duck_typing

Why/How should I used objects in JavaScript?

I understand how to instantiate objects and call them, but I just cannot find a reason to use them in my script. I could do
var obj = {
hi: function() {
return "Hello";
}
};
but why can't I just do it the same way like:
function hi() {
return "Hello";
}
I've never understood the reasons why I should use prototyping either. Most of the things I do in JavaScript I can do well without objects. But I want to use objects. What are objects for and what are the reasons why I should use them?
Objects are useful for example for making a single unit out of values that belong together. Example:
function Person(firstName, lastName, gender, age) {
this.firstName = firstName;
this.lastName = lastName;
this.gender = gender;
this.age = age;
}
Person.prototype = {
getFullName: function() { return this.firstName + ' ' + this.lastName; },
isMale: function() { return this.gender == 'Male'; },
isFemale: function() { return this.gender == 'Female'; }
};
var amanda = new Person('Amanda', 'Smith', "Female", 42);
var john = new Person('John', 'Doe', 'Male', 72);
alert(amanda.getFullName());
alert(john.isMale());
Compared to the less structured:
function getFullName(firstName, lastName) {
return firstName + ' ' + lastName;
}
function isMale(gender) {
return gender == 'Male';
}
function isFemale(gender) {
return gender == 'Female';
}
var amandaFirstName = 'Amanda';
var amandaLastName = 'Smith';
var amandaGender = 'Female';
var amandaAge = 42;
var johnFirstName = 'John';
var johnLastName = 'Doe';
var johnGender = 'Male';
var johnAge = 72;
alert(getFullName(amandaFirstName, amandaLastName));
alert(isMale(johnGender));
Objects are useful because
They are stateful.
They can store relations between strings and data.
It can be easier to decompose a problem by breaking it up into objects that collect related operations and state.
If you don't need non-global state, have no need of lookup tables, and your problem is small or more easily decomposed functionally then don't use objects.
Without what you are referring to as objects, you are going to have loose functions all over the place. This very often will result in code that is very difficult to maintain. At a bare minimum objects give you the ability to lump functions together in order to simulate namespaces-- and that's at a bare minimum.
In your simple example, it makes indeed no sense to write a semi "class" / object to hold that method. But when your code grows, you're getting more and more functions and methods, you don't really want to have them all in one big (global) namespace. That is just so impossible to maintenain, no one will understand that code including you at some later point.
That is the first good reason to wrap methods together in an object/"class". Another good reason is re-usabilty. If you're writting objects which are able to inherit their methods, you can re-create another object and abstract it from there on. Most simple concept, but you want to use it if you're describing "things" in your application as module/object.
It tries to simulate the OOP paradigm that's all. There are various ways of doing this. But ask yourself, doe 'hi' belong in 'obj' or can it be a standalone function? Its all about how closely related is the function to the object. Does the function needs to access the objects private variables and such?
This is less of a "objects in Javascript" and more of an objects in general" question.
I'd say the most relevant Javascript The only thing Javascript specific about objects is their neat use when namespacing. For example, most Javascript libraries pack all their stuff in a single object to avoid namespace collision:
dojo.create( ... )
dojo.connect( ... )
As for the other questions of why OOP, there are 2 basic things I think OOP excels at (generic, dumb, examples follow):
Dynamic dispatching - get rid of "ifs" and put responsabilitty where it belongs
When you look at a code that has tons of "switchs":
function doStuff(animal){
if animal is a tiger:
print_tiger_roar();
else if animal is a cow
print_cow_moo();
if animal is a tiger:
print_tiger_wants_meat();
else if animal is a cow
print cow_wants_grass();
It might be a good idea to bundle each different kind of behaviour in a different kind of object and use dynamic dispatching instead:
function doStuff(animal):
animal.print_speak();
animal.print_food_type();
Now, if you come up with another kind of animal in the future, you don't need to go looking around your code to add it - all you need to do is create a new class with the appropriate print_speack and print_food_type methods and the rest of the code won't notice a thing.
Inheritance + reusing methods
In a normal OO language each object stores (and spends memory) for its instance variables, while all methods + static variables are stored in a single place by the class. Javascript doesn't have classes, but it has prototypes and they serve the same basic function in the end.
Some generic thoughts concerning "Why" part:
Objects exist to communicate. It is a common vocabulary for everyone involved in a project. People are used to operate with things (objects) and their operations (messages or methods), rather than just with disconnected actions (functions).

Categories