Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript polymorphism without OOP classes

In JS or OOP language the polymorhpism is created by making different types.

For example:

class Field {...}

class DropdownField extends Field {
  getValue() { 
     //implementation ....
  }
}

Imagine I have library forms.js with some methods:

class Forms {
    getFieldsValues() {
      let values = [];
      for (let f of this.fields) {
          values.push(f.getValue());
      }
      return values;
    }
}

This gets all field values. Notice the library doesnt care what field it is.

This way developer A created the library and developer B can make new fields: AutocompleterField.

He can add methods in AutocompleterField withouth changing the library code (Forms.js) .

If I use functional programming method in JS, how can I achieve this?

If I dont have methods in object i can use case statements but this violates the principle. Similar to this:

if (field.type == 'DropdownField')...
else if (field.type == 'Autocompleter')..

If developer B add new type he should change the library code.

So is there any good way to solve the issue in javascript without using object oriented programming.

I know Js isnt exactly OOP nor FP but anyway.

Thanks


2 Answers

JavaScript being a multi-purpose language, you can of course solve it in different ways. When switching to functional programming, the answer is really simple: Use functions! The problem with your example is this: It is so stripped down, you can do exactly the same it does with just 3 lines:

// getValue :: DOMNode -> String
const getValue = field => field.value;

// readForm :: Array DOMNode -> Array String
const readForm = formFields => formFields.map(getValue);

readForm(Array.from(document.querySelectorAll('input, textarea, select')));
// -> ['Value1', 'Value2', ... 'ValueN']

The critical thing is: How is Field::getValue() implemented, what does it return? Or more precisely: How does DropdownField::getValue() differ from AutocompleteField::getValue() and for example NumberField::getValue()? Do all of them just return the value? Do they return a pair of name and value? Do they even need to be different?

The question is therefor, do your Field classes and their inheriting classes differ because of the way their getValue() methods work or do they rather differ because of other functionality they have? For example, the "autocomplete" functionality of a textfield isn't (or shouldn't be) tied to the way the value is taken from it.

In case you really need to read the values differently, you can implement a function which takes a map/dictionary/object/POJO of {fieldtype: readerFunction} pairs:

/* Library code */

// getTextInputValue :: DOMNode -> String
const getTextInputValue = field => field.value;

// getDropdownValue :: DOMNode -> String
const getDropdownValue = field => field.options[field.selectedIndex].value;

// getTextareaValue :: DOMNode -> String
const getTextareaValue = field => field.textContent;

// readFieldsBy :: {String :: (a -> String)} -> DOMNode -> Array String
readFieldsBy = kv => form => Object.keys(kv).reduce((acc, k) => {
  return acc.concat(Array.from(form.querySelectorAll(k)).map(kv[k]));
}, []);



/* Code the library consumer writes */

const readMyForm = readFieldsBy({
  'input[type="text"]': getTextInputValue,
  'select': getDropdownValue,
  'textarea': getTextareaValue
});

readMyForm(document.querySelector('#myform'));
// -> ['Value1', 'Value2', ... 'ValueN']

Note: I intentionally didn't mention things like the IO monad here, because it would make stuff more complicated, but you might want to look it up.

like image 96
David Avatar answered Nov 20 '25 15:11

David


In JS or OOP language the polymorhpism is created by making different types.

Yes. Or rather, by implementing the same type interface in different objects.

How can I use Javascript polymorphism without OOP classes

You seem to confuse classes with types here. You don't need JS class syntax to create objects at all.

You can just have

const autocompleteField = {
    getValue() {
        …
    }
};
const dropdownField = {
    getValue() {
        …
    }
};

and use the two in your Forms instance.

like image 26
Bergi Avatar answered Nov 20 '25 16:11

Bergi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!