polyfill.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. // ES2015 Symbol polyfill for environments that do not (or partially) support it
  2. "use strict";
  3. var d = require("d")
  4. , validateSymbol = require("./validate-symbol")
  5. , NativeSymbol = require("ext/global-this").Symbol
  6. , generateName = require("./lib/private/generate-name")
  7. , setupStandardSymbols = require("./lib/private/setup/standard-symbols")
  8. , setupSymbolRegistry = require("./lib/private/setup/symbol-registry");
  9. var create = Object.create
  10. , defineProperties = Object.defineProperties
  11. , defineProperty = Object.defineProperty;
  12. var SymbolPolyfill, HiddenSymbol, isNativeSafe;
  13. if (typeof NativeSymbol === "function") {
  14. try {
  15. String(NativeSymbol());
  16. isNativeSafe = true;
  17. } catch (ignore) {}
  18. } else {
  19. NativeSymbol = null;
  20. }
  21. // Internal constructor (not one exposed) for creating Symbol instances.
  22. // This one is used to ensure that `someSymbol instanceof Symbol` always return false
  23. HiddenSymbol = function Symbol(description) {
  24. if (this instanceof HiddenSymbol) throw new TypeError("Symbol is not a constructor");
  25. return SymbolPolyfill(description);
  26. };
  27. // Exposed `Symbol` constructor
  28. // (returns instances of HiddenSymbol)
  29. module.exports = SymbolPolyfill = function Symbol(description) {
  30. var symbol;
  31. if (this instanceof Symbol) throw new TypeError("Symbol is not a constructor");
  32. if (isNativeSafe) return NativeSymbol(description);
  33. symbol = create(HiddenSymbol.prototype);
  34. description = description === undefined ? "" : String(description);
  35. return defineProperties(symbol, {
  36. __description__: d("", description),
  37. __name__: d("", generateName(description))
  38. });
  39. };
  40. setupStandardSymbols(SymbolPolyfill);
  41. setupSymbolRegistry(SymbolPolyfill);
  42. // Internal tweaks for real symbol producer
  43. defineProperties(HiddenSymbol.prototype, {
  44. constructor: d(SymbolPolyfill),
  45. toString: d("", function () { return this.__name__; })
  46. });
  47. // Proper implementation of methods exposed on Symbol.prototype
  48. // They won't be accessible on produced symbol instances as they derive from HiddenSymbol.prototype
  49. defineProperties(SymbolPolyfill.prototype, {
  50. toString: d(function () { return "Symbol (" + validateSymbol(this).__description__ + ")"; }),
  51. valueOf: d(function () { return validateSymbol(this); })
  52. });
  53. defineProperty(
  54. SymbolPolyfill.prototype,
  55. SymbolPolyfill.toPrimitive,
  56. d("", function () {
  57. var symbol = validateSymbol(this);
  58. if (typeof symbol === "symbol") return symbol;
  59. return symbol.toString();
  60. })
  61. );
  62. defineProperty(SymbolPolyfill.prototype, SymbolPolyfill.toStringTag, d("c", "Symbol"));
  63. // Proper implementaton of toPrimitive and toStringTag for returned symbol instances
  64. defineProperty(
  65. HiddenSymbol.prototype, SymbolPolyfill.toStringTag,
  66. d("c", SymbolPolyfill.prototype[SymbolPolyfill.toStringTag])
  67. );
  68. // Note: It's important to define `toPrimitive` as last one, as some implementations
  69. // implement `toPrimitive` natively without implementing `toStringTag` (or other specified symbols)
  70. // And that may invoke error in definition flow:
  71. // See: https://github.com/medikoo/es6-symbol/issues/13#issuecomment-164146149
  72. defineProperty(
  73. HiddenSymbol.prototype, SymbolPolyfill.toPrimitive,
  74. d("c", SymbolPolyfill.prototype[SymbolPolyfill.toPrimitive])
  75. );