API Docs for: v2.11.0
Show:

File: packages/ember-runtime/lib/system/native_array.js

/**
@module ember
@submodule ember-runtime
*/
import Ember, { // Ember.A circular
  replace,
  get,
  Mixin
} from 'ember-metal';
import { ENV } from 'ember-environment';
import EmberArray, {
  arrayContentDidChange,
  arrayContentWillChange
} from '../mixins/array';
import MutableArray from '../mixins/mutable_array';
import Observable from '../mixins/observable';
import Copyable from '../mixins/copyable';
import { FROZEN_ERROR } from '../mixins/freezable';
import copy from '../copy';

// Add Ember.Array to Array.prototype. Remove methods with native
// implementations and supply some more optimized versions of generic methods
// because they are so common.

/**
  The NativeArray mixin contains the properties needed to make the native
  Array support Ember.MutableArray and all of its dependent APIs. Unless you
  have `EmberENV.EXTEND_PROTOTYPES` or `EmberENV.EXTEND_PROTOTYPES.Array` set to
  false, this will be applied automatically. Otherwise you can apply the mixin
  at anytime by calling `Ember.NativeArray.apply(Array.prototype)`.

  @class NativeArray
  @namespace Ember
  @uses Ember.MutableArray
  @uses Ember.Observable
  @uses Ember.Copyable
  @public
*/
let NativeArray = Mixin.create(MutableArray, Observable, Copyable, {

  // because length is a built-in property we need to know to just get the
  // original property.
  get(key) {
    if ('number' === typeof key) {
      return this[key];
    } else {
      return this._super(key);
    }
  },

  objectAt(idx) {
    return this[idx];
  },

  // primitive for array support.
  replace(idx, amt, objects) {
    if (this.isFrozen) {
      throw FROZEN_ERROR;
    }

    // if we replaced exactly the same number of items, then pass only the
    // replaced range. Otherwise, pass the full remaining array length
    // since everything has shifted
    let len = objects ? get(objects, 'length') : 0;
    arrayContentWillChange(this, idx, amt, len);

    if (len === 0) {
      this.splice(idx, amt);
    } else {
      replace(this, idx, amt, objects);
    }

    arrayContentDidChange(this, idx, amt, len);
    return this;
  },

  // If you ask for an unknown property, then try to collect the value
  // from member items.
  unknownProperty(key, value) {
    let ret;// = this.reducedProperty(key, value);
    if (value !== undefined && ret === undefined) {
      ret = this[key] = value;
    }
    return ret;
  },

  indexOf: Array.prototype.indexOf,
  lastIndexOf: Array.prototype.lastIndexOf,

  copy(deep) {
    if (deep) {
      return this.map((item) => copy(item, true));
    }

    return this.slice();
  }
});

// Remove any methods implemented natively so we don't override them
const ignore = ['length'];
NativeArray.keys().forEach((methodName) => {
  if (Array.prototype[methodName]) {
    ignore.push(methodName);
  }
});

NativeArray = NativeArray.without.apply(NativeArray, ignore);

/**
  Creates an `Ember.NativeArray` from an Array like object.
  Does not modify the original object. Ember.A is not needed if
  `EmberENV.EXTEND_PROTOTYPES` is `true` (the default value). However,
  it is recommended that you use Ember.A when creating addons for
  ember or when you can not guarantee that `EmberENV.EXTEND_PROTOTYPES`
  will be `true`.

  Example

  ```js
  export default Ember.Component.extend({
    tagName: 'ul',
    classNames: ['pagination'],

    init() {
      this._super(...arguments);

      if (!this.get('content')) {
        this.set('content', Ember.A());
      }
    }
  });
  ```

  @method A
  @for Ember
  @return {Ember.NativeArray}
  @public
*/
let A;

if (ENV.EXTEND_PROTOTYPES.Array) {
  NativeArray.apply(Array.prototype);
  A = arr => arr || [];
} else {
  A = arr => {
    if (!arr) { arr = []; }
    return EmberArray.detect(arr) ? arr : NativeArray.apply(arr);
  };
}

Ember.A = A;
export {
  A,
  NativeArray // TODO: only use default export
};
export default NativeArray;