了解 Functional Programming 的通用函数,能让咱们写出更简洁的代码,也能帮助咱们学习 RxJS。javascript
这是【30天精通 RxJS】的 03 篇,若是还没看过 02 篇能够往这边走:
[30 天精通 RxJS (02): Functional Programming 基本观念]
github.com/ShaofeiZi/3…java
读者可能会很好奇,咱们的主题是 RxJS 为何要特别讲 Functional Programming 的通用函数呢? 实际上,RxJS 核心的 Observable 操做观念跟 FP 的数组操做是极为相近的,只学会如下几个基本的方法跟观念后,会让咱们以后上手 Observable 简单不少!react
今天的代码比较多,你们能够直接看视频!webpack
forEach 是 JavaScript 在 ES5 后,原生就有支援的方法。git
本来咱们可能要透过 for loop 取出数组中的每个元素github
var arr = ['Jerry', 'Anna'];
for(var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}复制代码
如今能够直接透过数组的 forEach 取出每个元素。web
var arr = ['Jerry', 'Anna'];
arr.forEach(item => console.log(item));复制代码
forEach 是 FP 操做数组的基本方法,咱们能够用这个方法来实例下面三个咱们今天要讲的重点分别为 map, filter, concatAll。gulp
试着把 newCourseList 每一个元素的 { id, title } 塞到新的数组 idAndTitlePairs数组
var newCourseList = [
{
"id": 511021,
"title": "React for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"rating": 5
},
{
"id": 511022,
"title": "Vue2 for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"rating": 5
},
{
"id": 511023,
"title": "Angular2 for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"rating": 5
},
{
"id": 511024,
"title": "Webpack for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"rating": 4
}
], idAndTitle = [];
newCourseList.forEach((course) => {
idAndTitle.push({ id: course.id, title: course.title });
});复制代码
虽然咱们成功的把 newCourseList 转成 idAndTitlePairs,但这样的写法仍是显得有点太复杂了,咱们能够用更抽象化的方式来完成。app
上面咱们练习到 newCourseList 转换成一个新的数组 idAndTitlePairs,这个转换的过程其实就是两件事
把这个过程抽象化成一个方法 map,如下是简化的基本思路:
虽然 ES5 以后原生的 JavaScript 数组有 map 方法了,但但愿读者本身写一遍,能帮助理解。
// 咱们但愿每个数组都有 map 这个方法,因此咱们在 Array.prototype 扩充 map function
Array.prototype.map = function(callback) {
var result = []; // map 最后必定会返回一个新数组,因此咱们先建立一个新数组
this.forEach(function(element, index) {
// this 就是呼叫 map 的数组
result.push(callback(element, index));
// 执行使用者定义的 callback, callback 会回传使用者预期的元素,因此咱们把它 push 进新数组
})
return result;
}复制代码
这里用到了 JavaScript 的 prototype chain 以及 this 等观念,能够看此视频了解!
到这里咱们就实例完成 map 的方法了,让咱们来试试这个方法吧!
var idAndTitle = newCourseList
.map((course) => {
return { id: course.id, title: course.title };
});复制代码
能够看到咱们的代码更加的简洁!
若是咱们但愿过滤一个数组,留下数组中咱们想要的元素,并产生一个新的数组,要怎么作呢?
先让咱们用 forEach 完成!
让咱们过滤出 rating 值是 5 的元素
var ratingIsFive = [];
newCourseList.forEach((course) => {
if(course.rating === 5) {
ratingIsFive.push(course);
}
});复制代码
一样的咱们试着来简化这个过程,首先在这个转换的过程当中,咱们作了两件事:
Array.prototype.filter = function(callback) {
var result = [];
this.forEach((item, index) => {
if(callback(item, index))
result.push(item);
});
return result;
}复制代码
试试这个方法
var ratingIsFive = newCourseList
.filter((course) => course.rating === 5);复制代码
会发现咱们的代码又变简单了,接着咱们试着把 filter, map 串起来。
若是我想要取出全部 rating 是 5 的全部 course title
var ratingIsFive = newCourseList
.filter((course) => course.rating === 5)
.map(course => course.title);复制代码
有时候咱们会遇到组出一个二维数组,但咱们但愿数组是一维的,问题以下:
假如咱们要取出 courseLists 中全部 rating 为 5 的课程,这时可能就会用到两个 forEach
var user = {
id: 888,
name: 'JerryHong',
courseLists: [{
"name": "My Courses",
"courses": [{
"id": 511019,
"title": "React for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"tags": [{ id: 1, name: "JavaScript" }],
"rating": 5
}, {
"id": 511020,
"title": "Front-End automat workflow",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"tags": [{ "id": 2, "name": "gulp" }, { "id": 3, "name": "webpack" }],
"rating": 4
}]
}, {
"name": "New Release",
"courses": [{
"id": 511022,
"title": "Vue2 for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"tags": [{ id: 1, name: "JavaScript" }],
"rating": 5
}, {
"id": 511023,
"title": "Angular2 for Beginners",
"coverPng": "https://res.cloudinary.com/dohtkyi84/image/upload/v1481226146/react-cover.png",
"tags": [{ id: 1, name: "JavaScript" }],
"rating": 4
}]
}]
};
var allCourseIds = [];
user.courseLists.forEach(list => {
list.courses
.filter(item => item.rating === 5)
.forEach(item => {
allCourseIds.push(item)
})
})复制代码
能够看到上面的代码,咱们用了较为低阶的操做来解决这个问题,咱们刚刚已经试着用抽象化的方式实例了 map 跟 filter,那咱们一样也可以定义一个方法用来 摊平二维数组。
让咱们来加入一个 concatAll 方法来简化这段代码吧!
concatAll 要作的事情很简单,就是把一个二维数组转成一维。
Array.prototype.concatAll = function() {
var result = [];
// 用 apply 完成
this.forEach((array) => {
result.push.apply(result, array);
});
// 用两个 forEach 完成
// this.forEach((array) => {
// array.forEach(item => {
// result.push(item)
// })
// });
// 用 ES6 spread 完成
// this.forEach((array) => {
// result.push(...array);
// })
return result;
};复制代码
一样的咱们用前面定要好的 courseLists 来试试 concatAll 吧!
var allCourseIds = user.courseLists.map(list => {
return list.courses.filter(course => course.rating === 5)
}).concatAll()复制代码
这边出一个比较难的题目,你们能够想一想看要怎么解
var courseLists = [{
"name": "My Courses",
"courses": [{
"id": 511019,
"title": "React for Beginners",
"covers": [{
width: 150,
height: 200,
url: "http://placeimg.com/150/200/tech"
}, {
width: 200,
height: 200,
url: "http://placeimg.com/200/200/tech"
}, {
width: 300,
height: 200,
url: "http://placeimg.com/300/200/tech"
}],
"tags": [{
id: 1,
name: "JavaScript"
}],
"rating": 5
}, {
"id": 511020,
"title": "Front-End automat workflow",
"covers": [{
width: 150,
height: 200,
url: "http://placeimg.com/150/200/arch"
}, {
width: 200,
height: 200,
url: "http://placeimg.com/200/200/arch"
}, {
width: 300,
height: 200,
url: "http://placeimg.com/300/200/arch"
}],
"tags": [{
"id": 2,
"name": "gulp"
}, {
"id": 3,
"name": "webpack"
}],
"rating": 5
}]
}, {
"name": "New Release",
"courses": [{
"id": 511022,
"title": "Vue2 for Beginners",
"covers": [{
width: 150,
height: 200,
url: "http://placeimg.com/150/200/nature"
}, {
width: 200,
height: 200,
url: "http://placeimg.com/200/200/nature"
}, {
width: 300,
height: 200,
url: "http://placeimg.com/300/200/nature"
}],
"tags": [{
id: 1,
name: "JavaScript"
}],
"rating": 5
}, {
"id": 511023,
"title": "Angular2 for Beginners",
"covers": [{
width: 150,
height: 200,
url: "http://placeimg.com/150/200/people"
}, {
width: 200,
height: 200,
url: "http://placeimg.com/200/200/people"
}, {
width: 300,
height: 200,
url: "http://placeimg.com/300/200/people"
}],
"tags": [{
id: 1,
name: "JavaScript"
}],
"rating": 5
}]
}];
/* var result = courseList 不得直接使用索引 covers[0],请用 concatAll, map, filter, forEach 完成 result 结果为 [ { id: 511019, title: "React for Beginners", cover: "http://placeimg.com/150/200/tech" }, { id: 511020, title: "Front-End automat workflow", cover: "http://placeimg.com/150/200/arch" }, { id: 511022, title: "Vue2 for Beginners", cover: "http://placeimg.com/150/200/nature" }, { id: 511023, title: "Angular2 for Beginners", cover: "http://placeimg.com/150/200/people" }, ] */复制代码
这题有点难,你们能够想一想看,我把答案写在这里了!
若是你们还想作更多的练习能够到这个连结:reactivex.io/learnrx/
这个连结是 Jafar 大神为他的 RxJS workshop 所作的练习网站!
今天讲了 FP 操做数组的三个通用函数 forEach, map, filter,以及咱们本身定义的一个方法叫 concatAll。这几天咱们把学习 RxJS 的前置观念跟知识基本上都讲完了,明天咱们就开始进入 RxJS 的重点核心 Observable 喽!