3
\$\begingroup\$

I've tried to roll out my own HyperScript implementation. I would be interested in any suggestions to improve it or point me to any other better implementation which is still maintained. I checked the HyperScript project, but it doesn't seem to have any recent updates, so I tried this:

var DOM = {
    h: function(tagName, props, children) {
        var element = document.createElement(tagName);
        if (props) {
            for (var item in props) {
                element[item] = props[item];
            }
        }
        if (children && Array.isArray(children) && children.length > 0) {
            children.forEach(function(child) {
                element.appendChild(child);
            });
        }
        return element;
    },
    div: function(props, children) {
        return this.h('div', props, children);
    },
    label: function(props, children) {
        return this.h('label', props, children);
    },
    input: function(props, children) {
        return this.h('input', props, children);
    },
    button: function(props, children) {
        return this.h('button', props, children);
    },
    li: function(props, children) {
        return this.h('li', props, children);
    }
};

Usage:

DOM.button({ className: "destroy" });
\$\endgroup\$
3
\$\begingroup\$

The fun thing about these kinds of libraries is that they're fun to implement. The sad thing about them is that they aren't really fun to work with. You will beg for markup-like syntax in the long run.

But anyways,

div: function(props, children) {
    return this.h('div', props, children);
},
label: function(props, children) {
    return this.h('label', props, children);
},
input: function(props, children) {
    return this.h('input', props, children);
},
button: function(props, children) {
    return this.h('button', props, children);
},
li: function(props, children) {
    return this.h('li', props, children);
}

This can be simplified into a list of element names. You can run through it and assign a function to DOM for each name.

['div', 'li', ...].forEach(elementName => {
  DOM[elementName] = function(props, children){
    return this.h(elementName, props, children);
  };
});

As for your h function, you should guard for-in with hasOwnProperty to avoid iterating over prototype elements. Alternatively, you can use Object.keys and forEach. Also, silencing errors is terrible when debugging. If the user passed in something not an array, best inform them immediately. In the following code, it only catches on falsy values. Anything else, like a non-array or something will throw because forEach expects an array.

h: function(tagName, props, children) {
    var element = document.createElement(tagName);

    Object.keys(props || []).forEach( prop => {
      element[prop] = props[prop];
    });

    (children || []).forEach(child => {
      element.appendChild(child);
    });

    return element;
},
\$\endgroup\$
  • \$\begingroup\$ You won't believe that I tried that but for some reason, document.createElement("div").hasOwnProperty("className") is evaluating to false. How is that even possible? \$\endgroup\$ – Soham Dasgupta Feb 20 '16 at 5:17
  • 1
    \$\begingroup\$ @SohamDasgupta You are looping through props. You use hasOwnProperty on props, not the element. \$\endgroup\$ – Joseph Feb 20 '16 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.