Prototype Enumerable对象 学习 |
Enumerable provides a large set of useful methods for enumerations, that is, objects that act as collections of values. It is a cornerstone of Prototype. 复制代码 代码如下: var YourObject = Class.create(); Object.extend(YourObject.prototype, Enumerable); Object.extend(YourObject.prototype, { initialize: function() { // with whatever constructor arguments you need // Your construction code }, _each: function(iterator) { // Your iteration code, invoking iterator at every turn }, // Your other methods here, including Enumerable overrides }); 可以看出最重要的就是实现_each方法,initialize方法就相当于构造函数,如果不需要外部传进来什么参数,完全可以省略 。下面我自己写了一个产生随机数数组的类,非常简单,有许多不完善的地方,这里只做演示用: 复制代码 代码如下: //创建RandomArray类 var RandomArray = Class.create(); //mixin Enumerable Object.extend(RandomArray.prototype, Enumerable); //实现_each和所需方法 Object.extend(RandomArray.prototype, { initialize: function(min,max,count) { this.min=min; this.max=max; this.count=count; this._numbers=[]; this._createRandomArray(); }, _each: function(iterator) { var index=this.count; while(index-->0){ iterator(this._numbers[index]); } }, //产生随机数数组 _createRandomArray:function(){ var index=0; while(index<this.count){ var random=Math.round(Math.random()*(this.max-this.min)+this.min); if(this.include(random)){ continue; } this._numbers[index++]=random; } }, include:function(number){ return this._numbers.indexOf(number)!=-1; } }); var obj = new RandomArray(4,19,5); //alert(obj.size()); alert(obj.entries()); 看一下Enumerable的源码,然后具体学习其中的每个方法: 复制代码 代码如下: var $break = { }; var Enumerable = (function() { //遍历每个数据 function each(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; } //把数据划分成N组,其中每组有number个数,最后一组可能小于number个数 function eachSlice(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); } //测试是否所有数据都满足某个条件 function all(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; } //检查是否有任意一个数据满足某个条件 function any(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; } //可以对所有数据进行任何操作,并返回结果数组 function collect(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; } //查找第一个满足某个条件的数据,并返回,相当于find方法的别名 function detect(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; } //查找所有满足某个条件的数据,并返回结果 function findAll(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; } //根据filter条件过滤所有数据,找到满足filter条件的数据,并返回结果 //filter为字符串或者正则表达式 function grep(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(RegExp.escape(filter)); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, value, index)); }); return results; } //检查是否包含某个数据 function include(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; } //和eachSlice方法类似,如果最后一组元素个数不足number,则用fillWith参数填充 function inGroupsOf(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); } //对所有数据连续进行某个操作,可以实现累加或者累乘等操作 function inject(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; } //在所有数据上执行某个方法 function invoke(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); } //找数据中的最大值 function max(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; } //找数据中的最小值 function min(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; } //把所有数据一分为二,第一组为满足某个条件的数据,第二组为不满足条件的数据 function partition(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; } //取出所有数据的property的值,并返回结果 function pluck(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; } //找到不满足某个条件的数据 function reject(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; } //根据某个条件对所有数据进行排序 function sortBy(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, value, index) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck(value); } //返回数据的数组表示形式 function toArray() { return this.map(); } //基本就是把两组数据放在一起进行某些操作 function zip() { var iterator = Prototype.K, args = $A(arguments); if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); } function size() { return this.toArray().length; } //返回表示Enumerable对象的字符串表示形式 function inspect() { return #<Enumerable: + this.toArray().inspect() + >; } return { each: each, eachSlice: eachSlice, all: all, every: all, any: any, some: any, collect: collect, map: collect, detect: detect, findAll: findAll, select: findAll, filter: findAll, grep: grep, include: include, member: include, inGroupsOf: inGroupsOf, inject: inject, invoke: invoke, max: max, min: min, partition: partition, pluck: pluck, reject: reject, sortBy: sortBy, toArray: toArray, entries: toArray, zip: zip, size: size, inspect: inspect, find: detect }; })(); 下面学习Enumerable所提供的方法: all Determines whether all the elements are boolean-equivalent to true, either directly or through computation by the provided iterator. 基本就是调用each方法,检查每个数据是否满足iterator条件,其中有一个不满足就抛出$break异常,然后在each方法里面会捕获这个异常 。这里注意一下!!的用法,可以把某些对象转换成相应的bool值: !!{} true !![] true !! false !!string true !!0 false 下面看一下示例: 复制代码 代码如下: [].all() // -> true (empty arrays have no elements that could be false-equivalent) $R(1, 5).all() // -> true (all values in [1..5] are true-equivalent) [0, 1, 2].all() // -> false (with only one loop cycle: 0 is false-equivalent) [9, 10, 15].all(function(n) { return n >= 10; }) // -> false (the iterator will return false on 9) $H({ name: John, age: 29, oops: false }).all(function(pair) { return pair.value; }) // -> false (the oops/false pair yields a value of false) |