constructor(listOptions) {
    /**
     * A reference to a native Intl ListFormatter, only used when
     * USE_ECMASCRIPT_I18N_LISTFORMAT is true.
     * @private {?goog.global.Intl.ListFormat}
     */
    this.intlFormatter_ = null;

    /** @const @private @type {string} */
    this.listType_ = (listOptions && listOptions.type) ? listOptions.type :
                                                         ListFormatType.AND;

    // TODO(user): Investigate why ?. syntax fails on some targets.
    /** @const @private @type {string} */
    this.listStyle_ = (listOptions && listOptions.style) ? listOptions.style :
                                                           ListFormatStyle.LONG;

    if (LocaleFeature.USE_ECMASCRIPT_I18N_LISTFORMAT) {
      // Implement using ECMAScript Intl object.
      let options = {type: this.listType_, style: this.listStyle_};

      this.intlFormatter_ = new Intl.ListFormat(goog.LOCALE, options);
    } else {
      // Implement using JavaScript, requiring data and code.

      /** @const @private @type {!ListSymbols.ListFormatSymbols} */
      this.listSymbols_ = ListSymbols.getListFormatSymbols();

      let styleIndex = 0;  // LONG
      switch (this.listStyle_) {
        case ListFormatStyle.SHORT:
          styleIndex = 1;
          break;
        case ListFormatStyle.NARROW:
          styleIndex = 2;
          break;
      }

      /**
       * String for lists of exactly two items, containing {0} for the first,
       * and {1} for the second.
       * For instance '{0} and {1}' will give 'black and white'.
       * @private @type {string|undefined}
       * Example: for "black and white" the pattern is "{0} and {1}"
       * Example: for "black or white" the pattern is "{0} or {1}"
       * While for a longer list we have "cyan, magenta, yellow, and black"
       * Think "{0} start {1} middle {2} middle {3} end {4}"
       * The last pattern is "{0}, and {1}." Note the comma before "and"/"or".
       * So the "Two" pattern can be different than Start/Middle/End ones.
       * Note that the TWO version is usually the same as END.
       */
      this.listTwoPattern_;
      /**
       * String for the start of a list items, containing {0} for the first,
       * and {1} for the rest.
       * If AND_START is the same as OR_START, OR_START may be omitted.
       * @private @type {string|undefined}
       */
      this.listStartPattern_;
      /**
       * String for the start of a list items, containing {0} for the first part
       * of the list, and {1} for the rest of the list.
       * Note that the MIDDLE version is usually the same as START.
       * This value may fall back to OR_START or AND_START.
       * @private @type {string|undefined}
       */
      this.listMiddlePattern_;
      /**
       * String for the end of a list items, containing {0} for the first part
       * of the list, and {1} for the last item.
       *
       * This is how start/middle/end come together with a conjuction or
       * disjunction start = '{0}, {1}'  middle = '{0}, {1}',  end = '{0},
       * and {1}' will result in the typical English list: 'one, two, three, and
       * four' or 'one, two, three, or four'. There are languages where the
       * patterns are more complex than '{1} someText {1}' and the start pattern
       * is different than the middle one.
       *
       * @private {string|undefined}
       */
      this.listEndPattern_;

      // This might be further optimized to reuse strings.
      switch (this.listType_) {
        case ListFormatType.AND:
          this.listStartPattern_ = this.listSymbols_.AND_START[styleIndex];
          this.listTwoPattern_ =
              (this.listSymbols_.AND_TWO ||
               this.listSymbols_.AND_END)[styleIndex];
          this.listMiddlePattern_ =
              (this.listSymbols_.AND_MIDDLE ||
               this.listSymbols_.AND_START)[styleIndex];
          this.listEndPattern_ = this.listSymbols_.AND_END[styleIndex];
          break;

        case ListFormatType.OR:
          this.listStartPattern_ =
              (this.listSymbols_.OR_START ||
               this.listSymbols_.AND_START)[styleIndex];
          this.listTwoPattern_ =
              (this.listSymbols_.OR_TWO ||
               this.listSymbols_.OR_END)[styleIndex];
          this.listMiddlePattern_ =
              (this.listSymbols_.OR_MIDDLE ||
               this.listSymbols_.AND_START)[styleIndex];
          this.listEndPattern_ = this.listSymbols_.OR_END[styleIndex];
          break;

        case ListFormatType.UNIT:
          this.listStartPattern_ =
              (this.listSymbols_.UNIT_START ||
               this.listSymbols_.AND_START)[styleIndex];
          this.listTwoPattern_ =
              (this.listSymbols_.UNIT_TWO ||
               this.listSymbols_.UNIT_END)[styleIndex];
          this.listMiddlePattern_ =
              (this.listSymbols_.UNIT_MIDDLE ||
               this.listSymbols_.AND_START)[styleIndex];
          this.listEndPattern_ = this.listSymbols_.UNIT_END[styleIndex];
          break;
      }
    }
  }
Returns the listformatter for the locale given by goog.LOCALE.
specified, a listformatter for the user's locale will be returned.
The single optional string parameter may have one of the enums
given in ListFormatType, which is either AND ('conjunction')
or OR ('disjunction'). These gives locale-specific lists formatted
using AND / OR respectively.

@param {?ListOptions=} listOptions
@final