_collectNonEnumProps.js 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. define(['./_setup', './isFunction', './_has'], function (_setup, isFunction, _has) {
  2. // Internal helper to create a simple lookup structure.
  3. // `collectNonEnumProps` used to depend on `_.contains`, but this led to
  4. // circular imports. `emulatedSet` is a one-off solution that only works for
  5. // arrays of strings.
  6. function emulatedSet(keys) {
  7. var hash = {};
  8. for (var l = keys.length, i = 0; i < l; ++i) hash[keys[i]] = true;
  9. return {
  10. contains: function(key) { return hash[key]; },
  11. push: function(key) {
  12. hash[key] = true;
  13. return keys.push(key);
  14. }
  15. };
  16. }
  17. // Internal helper. Checks `keys` for the presence of keys in IE < 9 that won't
  18. // be iterated by `for key in ...` and thus missed. Extends `keys` in place if
  19. // needed.
  20. function collectNonEnumProps(obj, keys) {
  21. keys = emulatedSet(keys);
  22. var nonEnumIdx = _setup.nonEnumerableProps.length;
  23. var constructor = obj.constructor;
  24. var proto = isFunction(constructor) && constructor.prototype || _setup.ObjProto;
  25. // Constructor is a special case.
  26. var prop = 'constructor';
  27. if (_has(obj, prop) && !keys.contains(prop)) keys.push(prop);
  28. while (nonEnumIdx--) {
  29. prop = _setup.nonEnumerableProps[nonEnumIdx];
  30. if (prop in obj && obj[prop] !== proto[prop] && !keys.contains(prop)) {
  31. keys.push(prop);
  32. }
  33. }
  34. }
  35. return collectNonEnumProps;
  36. });