injectOptions jQuery plugin Over the past year I've found myself moving from back-end development to something more akin to full-stack development. I've created the following jQuery plugin as a test of my hopefully-not-so-fledgling JavaScript/jQuery skills. The plugin is used to inject &lt;option&gt; tags into the element(s) specified, and should follow the guidelines for creating basic plugins posted here.



(function($) {
  $.fn.injectOptions = function(opts) {
    opts = opts.map(function(opt) {
      if (typeof opt === 'string')
        return '&lt;option&gt;'+opt+'&lt;/option&gt;';
      return '&lt;option value="'+opt.key+'"&gt;'+opt.val+'&lt;/option&gt;';
    });
    var optHTML = opts.reduce(function(html, opt) { return html+opt; });
    this.each(function() { $(this).html(optHTML); });
    return this;
  };
}(jQuery));

//example:
var fooArr = ["foo", "bar", "baz", "faz"];
var quxArr = [
  { key: 1, val: "qux"},
  { key: 2, val: "quux"},
  { key: 3, val: "quuux"},
];

$(".foo-options").injectOptions(fooArr);
$(".qux-options").injectOptions(quxArr);
&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;
&lt;select class="foo-options"&gt;
&lt;/select&gt;
&lt;select class="qux-options"&gt;
&lt;/select&gt;
&lt;select class="qux-options"&gt;
&lt;/select&gt;




Any/all suggestions are welcome!
This code does not seem right:


var optHTML = opts.reduce(function(html, opt) { return html+opt; });
this.each(function() { $(this).html(optHTML); });



Here your .reduce() function is aggregating ALL the HTML for ALL of the options, which I think is an appropriate use of reduce function.  But I do not understand why there is call to each() here as this can only refer to a single element.  In fact I am guessing this doesn't even have an each() method on it , since this is an Element object.  Shouldn't this just be:

var optHTML = opts.reduce(function(html, opt) { return html+opt; }, '');
$(this).html(optHTML);




I am not seeing great utility in separate map and reduce steps. This causes you to iterate your input options an extra time that could be considered removed if you wanted to simply consolidate all this logic into the reduce step.  If the use cases are for small lists, maybe this performance isn't important and the added "clarity" of having two separate steps is acceptable.



Does it truly makes sense to support this extension on an arbitrary jQuery collection?  Right now, as this code is written, if I had HTML like this:

&lt;select class="foo-options"&gt;
&lt;/select&gt;
&lt;select class="foo-options"&gt;
&lt;/select&gt;


And I called your extension on $('.foo-options'), you would end up with duplicated options for these two different selects. Is this desirable behavior?



Rather than writing HTML strings and having to hold the aggregated string in memory, you should give some consideration to actually creating the DOM Nodes and appending them.

Along with suggestion on removing redundant iterations over options, might have you function looking like this:

$.fn.injectOptions = function(opts) {
  // not shown - perhaps validate opts is array with at least 1 element
  // and fail out if this is not the case

  // simply iterate the passed options appending each element as you go
  opts.forEach( opt =&gt; {
      var val, txt;
      if (typeof opt === 'string') {
          val = opt;
          txt = opt;
      } else {
          val = opt.key;
          txt = opt.val;
      }
      $(this).append( $.('&lt;option&gt;', { value: val, text: txt }) );
}