Enumerables

枚举

In Ember.js, an Enumerable is any object that contains a number of child objects, and which allows you to work with those children using the Ember.Enumerable API. The most common Enumerable in the majority of apps is the native JavaScript array, which Ember.js extends to conform to the Enumerable interface.

在Ember.js中,任何包含子对象集合的,并允许使用Ember.Enumerable接口来访问这些子对象的对象称为枚举。在大部分应用中最为常见的枚举是Ember.js为了确保枚举接口的一致性,而进行过扩展的Javascript的原生数组。

By providing a standardized interface for dealing with enumerables, Ember.js allows you to completely change the way your underlying data is stored without having to modify the other parts of your application that access it.

通过提供一个标准接口来处理枚举,Ember.js允许在不改变应用程序其他使用到枚举的部分的情况下,完全的改变数据的存储方式。

For example, you might display a list of items from fixture data during development. If you switch the underlying data from synchronous fixtures to an array that fetches data from the server lazily, your view, template and controller code do not change at all.

例如,在开发过程中,显示的列表条目是通过固定的测试数据来加载。当将该列表条目数据从同步的测试数据切换为从服务器延迟加载的模式来获取的时候,试图、模板和控制器代码不需要进行任何修改。

The Enumerable API follows ECMAScript specifications as much as possible. This minimizes incompatibility with other libraries, and allows Ember.js to use the native browser implementations in arrays where available.

枚举API尽可能的遵从ECMAScript规范,这将与其他库的不兼容情况降至最低,并且允许Ember.js使用浏览器自身实现的数组。

For instance, all Enumerables support the standard forEach method:

例如,所有的枚举都支持标准的forEach方法:

  1. [1,2,3].forEach(function(item) {
  2. console.log(item);
  3. });
  4. //=> 1
  5. //=> 2
  6. //=> 3

In general, Enumerable methods, like forEach, take an optional second parameter, which will become the value of this in the callback function:

通常情况下,类似forEach这样的枚举方法都支持一个可选第二参数,该参数值将用作回调函数里的this

  1. var array = [1,2,3];
  2. array.forEach(function(item) {
  3. console.log(item, this.indexOf(item));
  4. }, array)
  5. //=> 1 0
  6. //=> 2 1
  7. //=> 3 2

Enumerables in Ember.js

Ember.js中的枚举

Usually, objects that represent lists implement the Enumerable interface. Some examples:

通常,代表一个列表的对象实现枚举接口。例如:

  • Array - Ember extends the native JavaScript Array with the Enumerable interface (unless you disable prototype extensions.)
  • Array - Ember采用枚举接口扩展Javascript原生Array(除非显示关闭prototype扩展)
  • Ember.ArrayController - A controller that wraps an underlying array and adds additional functionality for the view layer.
  • Ember.ArrayController - 一种控制器其包裹了一个数组和其他一些视图层的辅助功能。
  • Ember.Set - A data structure that can efficiently answer whether it includes an object.
  • Ember.Set - 一种数据结构其可以高效的回答是否包含某一个对象。

API Overview

API概要

In this guide, we’ll explore some of the most common Enumerable conveniences. For the full list, please see the Ember.Enumerable API reference documentation.

在本指南中,将讲述一些最为常用的枚举惯例。完整的内容请查看Ember.Enumerable API参考文档

Iterating Over an Enumerable

遍历枚举

To enumerate all the values of an enumerable object, use the forEach method:

为了遍历枚举对象的所有值,可以使用forEach方法:

  1. var food = ["Poi", "Ono", "Adobo Chicken"];
  2. food.forEach(function(item, index) {
  3. console.log('Menu Item %@: %@'.fmt(index+1, item));
  4. });
  5. // Menu Item 1: Poi
  6. // Menu Item 2: Ono
  7. // Menu Item 3: Adobo Chicken

Making an Array Copy

拷贝数组

You can make a native array copy of any object that implements Ember.Enumerable by calling the toArray() method:

可以通过调用实现了Ember.Enumerable接口的任意对象的toArray()方法来将其创建一个原生的数组。

  1. var states = Ember.Set.create();
  2. states.add("Hawaii");
  3. states.add("California")
  4. states.toArray()
  5. //=> ["Hawaii", "California"]

Note that in many enumerables, such as the Ember.Set used in this example, the order of the resulting array is not guaranteed.

注意在很多枚举中,例如在本例中使用的Ember.Set,生成的数组元素的顺序无法得到保证。

First and Last Objects

首尾对象

All Enumerables expose firstObject and lastObject properties that you can bind to.

所有枚举提供firstObjectlastObject属性来获取首尾对象。

  1. var animals = ["rooster", "pig"];
  2. animals.get('lastObject');
  3. //=> "pig"
  4. animals.pushObject("peacock");
  5. animals.get('lastObject');
  6. //=> "peacock"

Map

映射

You can easily transform each item in an enumerable using the map() method, which creates a new array with results of calling a function on each item in the enumerable.

通过使用map()方法,可以方便的转换枚举中的每个元素。该方法使用对每个元素进行处理后的结果创建一个新的数组。

  1. var words = ["goodbye", "cruel", "world"];
  2. var emphaticWords = words.map(function(item) {
  3. return item + "!";
  4. });
  5. // ["goodbye!", "cruel!", "world!"]

If your enumerable is composed of objects, there is a mapBy() method that will extract the named property from each of those objects in turn and return a new array:

如果枚举由对象构成,那么通过mapBy()方法可以抽取对象指定的属性,来形成一个新的数组:

  1. var hawaii = Ember.Object.create({
  2. capital: "Honolulu"
  3. });
  4. var california = Ember.Object.create({
  5. capital: "Sacramento"
  6. });
  7. var states = [hawaii, california];
  8. states.mapBy('capital');
  9. //=> ["Honolulu", "Sacramento"]

Filtering

过滤

Another common task to perform on an Enumerable is to take the Enumerable as input, and return an Array after filtering it based on some criteria.

另外一个常规任务是将一个枚举作为输入,为其设定一些过滤条件来返回一个新的数组。

For arbitrary filtering, use the filter method. The filter method expects the callback to return true if Ember should include it in the final Array, and false or undefined if Ember should not.

对于采用filter方法的任意过滤。如果回调方法返回true,那么Ember将在返回结果中包含该元素,如果返回false或者undefined则不包含。

  1. var arr = [1,2,3,4,5];
  2. arr.filter(function(item, index, self) {
  3. if (item < 4) { return true; }
  4. })
  5. // returns [1,2,3]

When working with a collection of Ember objects, you will often want to filter a set of objects based upon the value of some property. The filterBy method provides a shortcut.

当处理一个Ember对象的集合时,经常需要基于对象的某些属性值来过滤。filterBy方法可以快速的实现此过滤。

  1. Todo = Ember.Object.extend({
  2. title: null,
  3. isDone: false
  4. });
  5. todos = [
  6. Todo.create({ title: 'Write code', isDone: true }),
  7. Todo.create({ title: 'Go to sleep' })
  8. ];
  9. todos.filterBy('isDone', true);
  10. // returns an Array containing only items with `isDone == true`

If you want to return just the first matched value, rather than an Array containing all of the matched values, you can use find and findBy, which work just like filter and filterBy, but return only one item.

如果只想返回第一个匹配的值,而不是一个包含所有匹配值的数组,可以使用findfindBy方法,其工作原理与filterfilterBy一样,不同的是只返回一个元素。

Aggregate Information (All or Any)

聚合信息(全部或者部分)

If you want to find out whether every item in an Enumerable matches some condition, you can use the every method:

如果希望检查是否所有的枚举的元素都符合某些条件,可以使用every方法:

  1. Person = Ember.Object.extend({
  2. name: null,
  3. isHappy: false
  4. });
  5. var people = [
  6. Person.create({ name: 'Yehuda', isHappy: true }),
  7. Person.create({ name: 'Majd', isHappy: false })
  8. ];
  9. people.every(function(person, index, self) {
  10. if(person.get('isHappy')) { return true; }
  11. });
  12. // returns false

If you want to find out whether at least one item in an Enumerable matches some conditions, you can use the some method:

如果希望检查是否枚举的元素至少有一个符合某些条件,那么可以使用some方法:

  1. people.some(function(person, index, self) {
  2. if(person.get('isHappy')) { return true; }
  3. });
  4. // returns true

Just like the filtering methods, the every and some methods have analogous isEvery and isAny methods.

如同过滤方法一样,everysome也有isEveryisAny方法。

  1. people.isEvery('isHappy', true) // false
  2. people.isAny('isHappy', true) // true