CoffeeScript的循环和推导式

2018-08-25 14:47 更新
for ... in推导适用于数组、对象和范围
推导使用可选的控制子句和当前数组索引的值代替循环:for value, index in array
数组推导是表达式,可以返回和赋值
推导可以代替each/forEach、map或select/filter
在知道循环的起点和终点的情况下使用范围(整数步长)
使用by指定固定大小的步长
在把推导的结果赋值给变量时,CoffeeScript会把每次迭代的结果收集到一个数组中
如果循环的结果只产生副作用,那么要返回null、undefined或true
要迭代对象的键和值,使用of
使用for own key, value of object迭代直接在对象中定义的键
while是CoffeeScript提供的唯一的低级循环;while循环可以用作表达式,返回一个数组,包含每次循环的结果
until等价于while not

loop等价于whilt true _ do关键字用于插入闭包,转发所有参数并调用传入的函数


循环
这点主要讲的是对数组和对象的遍历。


数组的遍历
数组的遍历我们只需要拿到每个元素和当前元素的下标就可以了。数组的遍历也可以采用操作前置写法:


#编译前
array = ['xxx', 'yyy', 'zzz']

console.log item for item in array

#编译后
var array, item, _i, _len;

array = ['xxx', 'yyy', 'zzz'];

for (_i = 0, _len = array.length; _i < _len; _i++) {
  item = array[_i];
  console.log(item);
}


获取下标:

#编译前
array = ['xxx', 'yyy', 'zzz']

console.log i + ':' + item for item,i in array

#编译后
var array, i, item, _i, _len;

array = ['xxx', 'yyy', 'zzz'];

for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
  item = array[i];
  console.log(i + ':' + item);
}


多操作的时候就不能采用操作前置的写法了,要采用下面的写法,要注意缩进。

#编译前
array = ['xxx', 'yyy', 'zzz']

for item,i in array
  console.log i + ':' + item
  alert i + ':' + item
对象的遍历

对象的遍历只要拿到key和value就可以做爱做的事了。嘿嘿先看操作前置写法:

#编译前
obj =
  name: 'xxx'
  age: 10

console.log key + ':' + value for key,value of obj

#编译后
var key, obj, value;

obj = {
  name: 'xxx',
  age: 10
};

for (key in obj) {
  value = obj[key];
  console.log(key + ':' + value);
}


多操作还是得这样写,注意缩进

#编译前
obj =
  name: 'xxx'
  age: 10

for key,value of obj
  console.log key + ':' + value
  alert key + ':' + value

#编译后
var key, obj, value;

obj = {
  name: 'xxx',
  age: 10
};

for (key in obj) {
  value = obj[key];
  console.log(key + ':' + value);
  alert(key + ':' + value);
}


如果你希望仅迭代在当前对象中定义的属性,通过hasOwnProperty检查并避免属性是继承来的,可以这样来写:

#编译前
obj =
  name: 'xxx'
  age: 10

for own key,value of obj
  console.log key + ':' + value

#编译后
var key, obj, value,
  __hasProp = {}.hasOwnProperty;

obj = {
  name: 'xxx',
  age: 10
};

for (key in obj) {
  if (!__hasProp.call(obj, key)) continue;
  value = obj[key];
  console.log(key + ':' + value);
}


注意:别搞错关键字了

for item in array
for key of obj
推导式

所谓的推导式其实就是在遍历数组进行操作的同时,将操作后的结果生成一个新的数组。注意啊,这里仅仅是操作数组,对象可不行。看例子:将每个数组的每个元素进行+1

#编译前
array = [1, 2, 3, 4]

addOne = (item)->
  return item + 1

newArray = (addOne item for item in array)

#编译后
var addOne, array, item, newArray;

array = [1, 2, 3, 4];

addOne = function(item) {
  return item + 1;
};

newArray = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = array.length; _i < _len; _i++) {
    item = array[_i];
    _results.push(addOne(item));
  }
  return _results;
})();


推导式的代码就一行,但是编译到JavaScript,大家可以看到节省了大量的代码,而且从CoffeeScript代码上,我们一眼就看出了代码功能。当然了,实际上推导式不可能就这样简单:遍历所有元素进行操作。有时候得进行一些过滤。CoffeeScript里面也提供了这些功能,看例子:

#编译前
array = [1, 2, 3, 4]


addOne = (item)->
  return item + 1

newArray = (addOne item for item,i in array)newArray1 = (addOne item for item,i in array when i isnt 0) #过滤掉第一个元素newArray2 = (addOne item for item,i in array when item > 3) #过滤掉小于4的元素newArray3 = (addOne item for item,i in array by 2) #迭代的跨度
#编译后
var addOne, array, i, item, newArray, newArray1, newArray2, newArray3;


array = [1, 2, 3, 4];


addOne = function(item) {
  return item + 1;
};

newArray = (function() {
  var _i, _len, _results;
  _results = [];
  for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
    item = array[i];
    _results.push(addOne(item));
  }
  return _results;
})();

newArray1 = (function() {
  var _i, _len, _results;
  _results = [];
  for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
    item = array[i];
    if (i !== 0) {
      _results.push(addOne(item));
    }
  }
  return _results;
})();

newArray2 = (function() {
  var _i, _len, _results;
  _results = [];
  for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) {
    item = array[i];
    if (item > 3) {
      _results.push(addOne(item));
    }
  }
  return _results;
})();

newArray3 = (function() {
  var _i, _len, _results;
  _results = [];
  for (i = _i = 0, _len = array.length; _i < _len; i = _i += 2) {
    item = array[i];
    _results.push(addOne(item));
  }
  return _results;
})();


相信大家也发现了,推导式都是写在一行的,如果要使用推导式,得将你的操作封装成一个函数供调用。


切片
CoffeeScript构建的思想,借鉴了很多Python和Ruby的。比如现在所说的切片功能。切片其实就是对数组的截断,插入和删除操作。说白了就是用JavaScript的数组slice和splice函数操作数组。还是先简单说明一下这两函数吧。注意啊,这里讲的JavaScript

slice(start,end)

功能:数组截取
**参数: 
start:开始位置
end:结束位置**
返回值:新的数组
注意:数组本身不发生变化

第一个参数是截取开始位置(数组下标是从0开始),第二个参数是结束位置,但是不包括结束位置。

如果只有一个参数,从开始位置截取到剩下所有数据
开始位置和结束位置也可以传递负数,负数表示倒着数。例如-3是指倒数第三个元素

var array = [1, 2, 3, 4, 5];

var newArray = array.slice(1); //newArray: [2,3,4,5]
var newArray1 = array.slice(0, 3); //newArray1: [1,2,3]
var newArray2 = array.slice(0, -1); //newArray2: [1,2,3,4]
var newArray3 = array.slice(-3, -2); //newArray3: [3]
splice(start,len,data...)

功能:数组插入数据、删除数据
**参数: 
start:开始位置
len:截断的个数
data:插入的数据**
返回值:截断的数据,是数组
注意:操作的是数组本身
如果只有一个参数,从开始位置截取剩下所有数据

var array = [1, 2, 3, 4, 5]

var newArray = array.splice(1);//array=[1] newArray=[2,3,4,5]
var newArray1 = array.splice(0, 2);//array=[3,4,5] newArray1=[1,2]
var newArray2 = array.splice(0, 1, 6, 7);//array=[6,7,2,3,4,5] newArray2=[1]
好了,回到CoffeeScript,看看所谓的切片。

#编译前
array = [1, 2, 3, 4]

newArray = array[0...2] #newArray=[1,2]
newArray1 = array[0..2] #newArray1=[1,2,3]
newArray2 = array[..] #newArray2=[1,2,3,4]
newArray3 = array[-3...-1] #newArray3=[2,3]

#编译后
var array, newArray, newArray1, newArray2, newArray3;

array = [1, 2, 3, 4];

newArray = array.slice(0, 2);    
newArray1 = array.slice(0, 3);    
newArray2 = array.slice(0);    
newArray3 = array.slice(-3, -1);
注意: ... 不包括结束位置的元素, .. 包括结束位置的元素

CoffeeScript里面是这样操作数组的。

#编译前
array = [1, 2, 3, 4]

array[0...1] = [5] #array=[5,2,3,4]
array[0..1] = [5] #array=[5,3,4]

#编译后
var array, _ref, _ref1;

array = [1, 2, 3, 4];

[].splice.apply(array, [0, 1].concat(_ref = [5])), _ref;

[].splice.apply(array, [0, 2].concat(_ref1 = [5])), _ref1;


其实就是把两个下标之间的元素替换成新的数据。同样的, ... 不包括结束位置的元素, .. 包括结束位置的元素



以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号