函数式编程

函数式编程是新添加的一个模块,其中重点讲了函数式编程的特点以及一些能用于函数式编程的方法。

函数式编程的特色

  • 方法独立:对于环境变量的依赖小
  • 用法单纯:输入相同的参数总是产生相同的结果
  • 对环境污染小:会谨慎控制对函数外部数据产生的影响

函数式编程的准则

  • 不改变任何东西,无论是全局变量还是对象
  • 明确依赖,把函数依赖的对象直接作为参数传递给函数

函数式编程相关的概念

  • callback回调函数
  • first class function一级函数
  • high-order function高阶函数
  • lambda函数

适用函数方法

  • **map**:遍历数组,执行特定操作,并返回新数组
  • **filter**:按照特定标准筛选数组中符合标准的元素,返回新数组
  • **slice**:切分数组,返回特定元素的拷贝,不改变原数组
  • **concat**:连接数组或字符串,返回原数组的副本,不改变原数组
  • **reduce**:遍历数组,执行特定操作,最终返回一个值
  • **sort**:按照特定规则给数组排序,会改变原数组的顺序,所以建议先用[].concat(array)再排序
  • **split**:切分字符串,返回一个新的数组
  • **join**:将数组按照特定分界符连接成字符串
  • **every**:检测数组内的每个元素是否都符合特定要求,返回一个布尔值
  • **some**:检测数组内的部分元素是否符合特定要求,返回一个布尔值
  • curring柯里化:将一个接受n个参数的函数转换为n个只接受一个参数的函数
  • partial application偏函数:接受部分参数,并返回一个接受余下参数的函数的函数

以下是这部分的习题,及根据习题的知识点记录:


Introduction to the Functional Programming Challenges

  • Learn About Functional Programming

    函数式编程是编程风格的一种,它的方法简单、独立,对编程环境的影响小。

    INPUT => PROCESS => OUTPUT

    函数式编程的风格包括:

    1. 方法独立:对编程环境依赖较弱,如果修改全局变量,对方法的没有影响
    2. 用法单纯:一样的参数总是产生一样的结果
    3. 方法副作用小:函数会谨慎控制其对函数外部产生的影响

    这道习题首先提出了prepareTea方法,内容是输出greenTea,然后是getTea方法,接受一个数字作为参数,输出一个长度等于参数的数组。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /**
    * A long process to prepare tea.
    * @return {string} A cup of tea.
    **/
    const prepareTea = () => 'greenTea';

    /**
    * Get given number of cups of tea.
    * @param {number} numOfCups Number of required cups of tea.
    * @return {Array<string>} Given amount of tea cups.
    **/
    const getTea = (numOfCups) => {
    const teaCups = [];

    for(let cups = 1; cups <= numOfCups; cups += 1) {
    const teaCup = prepareTea();
    teaCups.push(teaCup);
    }

    return teaCups;
    };

    // Add your code below this line

    const tea4TeamFCC = getTea(40); // :(

    // Add your code above this line

    console.log(tea4TeamFCC);

  • Understand Functional Programming Terminology

    关于函数式编程有一些需要注意的概念:

    • callback回调函数:回调函数是一个方法,它通常被作为参数传递到另一个方法内部,用于控制在合适的时候调用
    • first class function一级函数:有些函数可以赋值给变量,或者传递给另一个方法使用,或者作为函数的返回值,这样的函数叫做一级函数。在JavaScript中,所有的函数都是一级函数
    • high-order function高阶函数:可以作为函数参数的,或者作为函数返回值的函数叫做高阶函数
    • **lambda**:当函数被作为参数传递或作为函数结果返回时,这个函数被称为lambda
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    const prepareGreenTea = () => 'greenTea';

    /**
    * A long process to prepare black tea.
    * @return {string} A cup of black tea.
    **/
    const prepareBlackTea = () => 'blackTea';

    /**
    * Get given number of cups of tea.
    * @param {function():string} prepareTea The type of tea preparing function.
    * @param {number} numOfCups Number of required cups of tea.
    * @return {Array<string>} Given amount of tea cups.
    **/
    const getTea = (prepareTea, numOfCups) => {
    const teaCups = [];

    for(let cups = 1; cups <= numOfCups; cups += 1) {
    const teaCup = prepareTea();
    teaCups.push(teaCup);
    }

    return teaCups;
    };

    // Add your code below this line

    const tea4GreenTeamFCC = getTea(prepareGreenTea, 27); // :(
    const tea4BlackTeamFCC = getTea(prepareBlackTea, 13); // :(

    // Add your code above this line

    console.log(
    tea4GreenTeamFCC,
    tea4BlackTeamFCC
    );

  • Understand the Hazards of Using Imperative Code

    • 命令式编程: 命令式编程就是一步一步告诉计算你接下来要做什么操作。这些操作经常会改变编程环境,如更新全局变量。一个典型的例子就是使用for循环利用遍历i指代索引遍历数组
    • 函数式编程:函数式编程是一种声明式的编程,你告诉计算机你喜欢通过什么方法来获得什么结果。

    JavaScript语言有需要内置的方法来帮你完成操作,不需要你单独写一个方法,例如for循环操作,你可以使用map方法来完成遍历,这样可以帮助你避免如“差一错误”之类的语法错误。

    这题主要是学习代码风格,并不需要你自己改动哪里。

    代码模拟了一个浏览器也没保存打开标签的名称的功能,假设每个窗口都有一个tabs数组,用于保存打开的标签名,同时有join,tabOpen, tabClose功能。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    // tabs is an array of titles of each site open within the window
    var Window = function(tabs) {
    this.tabs = tabs; // we keep a record of the array inside the object
    };

    // When you join two windows into one window
    Window.prototype.join = function (otherWindow) {
    this.tabs = this.tabs.concat(otherWindow.tabs);
    return this;
    };

    // When you open a new tab at the end
    Window.prototype.tabOpen = function (tab) {
    this.tabs.push('new tab'); // let's open a new tab for now
    return this;
    };

    // When you close a tab
    Window.prototype.tabClose = function (index) {
    var tabsBeforeIndex = this.tabs.splice(0, index); // get the tabs before the tab
    var tabsAfterIndex = this.tabs.splice(index); // get the tabs after the tab

    this.tabs = tabsBeforeIndex.concat(tabsAfterIndex); // join them together
    return this;
    };

    // Let's create three browser windows
    var workWindow = new Window(['GMail', 'Inbox', 'Work mail', 'Docs', 'freeCodeCamp']); // Your mailbox, drive, and other work sites
    var socialWindow = new Window(['FB', 'Gitter', 'Reddit', 'Twitter', 'Medium']); // Social sites
    var videoWindow = new Window(['Netflix', 'YouTube', 'Vimeo', 'Vine']); // Entertainment sites

    // Now perform the tab opening, closing, and other operations
    var finalTabs = socialWindow
    .tabOpen() // Open a new tab for cat memes
    .join(videoWindow.tabClose(2)) // Close third tab in video window, and join
    .join(workWindow.tabClose(1).tabOpen());

    alert(finalTabs.tabs);

  • Avoid Mutations and Side Effects Using Functional Programming

    上面例子中有一个错误是代码希望我们能够发现的,就是代码中对数组进行切分时使用了splice方法,splice方法会改变原数组,从而导致结果和预期不一样。

    以小见大,我们很容易在函数中使用某个变量、数组或对象,而这个函数悄悄改变了原来的数据。

    函数式编程的一个核心准则就是「不改变任何东西」,改变会导致bug。当你明确自己的函数不会改变任何数据,包括函数参数或全局变量时,能够更好地防止bug的产生。

    像上面一题,其实代码没有做任何复杂的操作,只是splice方法修改了原始数组,并且导致bug。

    在函数式编程中,修改事物被称为**mutation变动,产生的结果叫做side effect副作用**。函数应该只是单纯的函数,不应该造成任何副作用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // the global variable
    var fixedValue = 4;

    function incrementer () {
    // Add your code below this line
    let result = 0;
    return result = fixedValue + 1;
    // Add your code above this line
    }

    var newValue = incrementer(); // Should equal 5
    console.log(fixedValue); // Should print 4

  • Pass Arguments to Avoid External Dependence in a Function

    上一道题中,我们需要获得一个累加器,返回的结果是全局变量+1,但是全局变量的值不能变。我们在解答的过程中并没有改变全局变量的值,但是还是用到了全局变量的值。

    函数式编程的另一个准则就是「明确依赖」,也就是说,当函数需要依赖一个存在的变量或对象时,直接将这个变量或者对象作为参数传递给函数

    这么做有很多好处,函数会更容易调试,也更容易明确到底传递了什么内容给函数内部,而且函数本身不必依赖程序里的其他任何东西。这样当你需要修改、删除或者添加代码时,你会更清楚哪些能改哪些不能,而且也更清晰地知道哪些地方更容易造成bug。

    最终,这个函数能够实现无论代码的其他部分如何改变,函数总是同样的输入产生同样的结果,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // the global variable
    var fixedValue = 4;

    // Add your code below this line
    function incrementer (fixedValue) {
    return fixedValue + 1;

    // Add your code above this line
    }

    var newValue = incrementer(fixedValue); // Should equal 5
    console.log(fixedValue); // Should print 4

  • Refactor Global Variables Out of Functions

    所以我们明确了函数式编程的两个准则:

    • 不要修改变量或对象:当函数需要变量或对象时,创建新的变量或对象
    • 声明函数的参数:函数内部的操作仅依赖参数,而不是任何全局对象或变量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    // the global variable
    var bookList = ["The Hound of the Baskervilles", "On The Electrodynamics of Moving Bodies", "Philosophiæ Naturalis Principia Mathematica", "Disquisitiones Arithmeticae"];

    /* This function should add a book to the list and return the list */
    // New parameters should come before the bookName one

    // Add your code below this line
    function add (bookList, bookName) {

    return bookList.concat(bookName);

    // Add your code above this line
    }

    /* This function should remove a book from the list and return the list */
    // New parameters should come before the bookName one

    // Add your code below this line
    function remove (bookList, bookName) {
    if (bookList.indexOf(bookName) >= 0) {
    let beforeBooks = bookList.slice(0, bookList.indexOf(bookName));
    let afterBooks = bookList.slice(bookList.indexOf(bookName)+1);
    return beforeBooks.concat(afterBooks);

    // Add your code above this line
    }
    }

    var newBookList = add(bookList, 'A Brief History of Time');
    var newerBookList = remove(bookList, 'On The Electrodynamics of Moving Bodies');
    var newestBookList = remove(add(bookList, 'A Brief History of Time'), 'On The Electrodynamics of Moving Bodies');

    console.log(bookList);

  • Use the map Method to Extract Data from an Array

    函数式编程如其名,核心围绕函数思想。在JavaScript中,函数作为一级对象,可以被作为参数传入其他函数,也可以作为结果被其他函数返回,可以被保存在变量中或者对象中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    // the global variable
    var watchList = [
    {
    "Title": "Inception",
    "Year": "2010",
    "Rated": "PG-13",
    "Released": "16 Jul 2010",
    "Runtime": "148 min",
    "Genre": "Action, Adventure, Crime",
    "Director": "Christopher Nolan",
    "Writer": "Christopher Nolan",
    "Actors": "Leonardo DiCaprio, Joseph Gordon-Levitt, Ellen Page, Tom Hardy",
    "Plot": "A thief, who steals corporate secrets through use of dream-sharing technology, is given the inverse task of planting an idea into the mind of a CEO.",
    "Language": "English, Japanese, French",
    "Country": "USA, UK",
    "Awards": "Won 4 Oscars. Another 143 wins & 198 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMjAxMzY3NjcxNF5BMl5BanBnXkFtZTcwNTI5OTM0Mw@@._V1_SX300.jpg",
    "Metascore": "74",
    "imdbRating": "8.8",
    "imdbVotes": "1,446,708",
    "imdbID": "tt1375666",
    "Type": "movie",
    "Response": "True"
    },
    {
    "Title": "Interstellar",
    "Year": "2014",
    "Rated": "PG-13",
    "Released": "07 Nov 2014",
    "Runtime": "169 min",
    "Genre": "Adventure, Drama, Sci-Fi",
    "Director": "Christopher Nolan",
    "Writer": "Jonathan Nolan, Christopher Nolan",
    "Actors": "Ellen Burstyn, Matthew McConaughey, Mackenzie Foy, John Lithgow",
    "Plot": "A team of explorers travel through a wormhole in space in an attempt to ensure humanity's survival.",
    "Language": "English",
    "Country": "USA, UK",
    "Awards": "Won 1 Oscar. Another 39 wins & 132 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMjIxNTU4MzY4MF5BMl5BanBnXkFtZTgwMzM4ODI3MjE@._V1_SX300.jpg",
    "Metascore": "74",
    "imdbRating": "8.6",
    "imdbVotes": "910,366",
    "imdbID": "tt0816692",
    "Type": "movie",
    "Response": "True"
    },
    {
    "Title": "The Dark Knight",
    "Year": "2008",
    "Rated": "PG-13",
    "Released": "18 Jul 2008",
    "Runtime": "152 min",
    "Genre": "Action, Adventure, Crime",
    "Director": "Christopher Nolan",
    "Writer": "Jonathan Nolan (screenplay), Christopher Nolan (screenplay), Christopher Nolan (story), David S. Goyer (story), Bob Kane (characters)",
    "Actors": "Christian Bale, Heath Ledger, Aaron Eckhart, Michael Caine",
    "Plot": "When the menace known as the Joker wreaks havoc and chaos on the people of Gotham, the caped crusader must come to terms with one of the greatest psychological tests of his ability to fight injustice.",
    "Language": "English, Mandarin",
    "Country": "USA, UK",
    "Awards": "Won 2 Oscars. Another 146 wins & 142 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw@@._V1_SX300.jpg",
    "Metascore": "82",
    "imdbRating": "9.0",
    "imdbVotes": "1,652,832",
    "imdbID": "tt0468569",
    "Type": "movie",
    "Response": "True"
    },
    {
    "Title": "Batman Begins",
    "Year": "2005",
    "Rated": "PG-13",
    "Released": "15 Jun 2005",
    "Runtime": "140 min",
    "Genre": "Action, Adventure",
    "Director": "Christopher Nolan",
    "Writer": "Bob Kane (characters), David S. Goyer (story), Christopher Nolan (screenplay), David S. Goyer (screenplay)",
    "Actors": "Christian Bale, Michael Caine, Liam Neeson, Katie Holmes",
    "Plot": "After training with his mentor, Batman begins his fight to free crime-ridden Gotham City from the corruption that Scarecrow and the League of Shadows have cast upon it.",
    "Language": "English, Urdu, Mandarin",
    "Country": "USA, UK",
    "Awards": "Nominated for 1 Oscar. Another 15 wins & 66 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BNTM3OTc0MzM2OV5BMl5BanBnXkFtZTYwNzUwMTI3._V1_SX300.jpg",
    "Metascore": "70",
    "imdbRating": "8.3",
    "imdbVotes": "972,584",
    "imdbID": "tt0372784",
    "Type": "movie",
    "Response": "True"
    },
    {
    "Title": "Avatar",
    "Year": "2009",
    "Rated": "PG-13",
    "Released": "18 Dec 2009",
    "Runtime": "162 min",
    "Genre": "Action, Adventure, Fantasy",
    "Director": "James Cameron",
    "Writer": "James Cameron",
    "Actors": "Sam Worthington, Zoe Saldana, Sigourney Weaver, Stephen Lang",
    "Plot": "A paraplegic marine dispatched to the moon Pandora on a unique mission becomes torn between following his orders and protecting the world he feels is his home.",
    "Language": "English, Spanish",
    "Country": "USA, UK",
    "Awards": "Won 3 Oscars. Another 80 wins & 121 nominations.",
    "Poster": "http://ia.media-imdb.com/images/M/MV5BMTYwOTEwNjAzMl5BMl5BanBnXkFtZTcwODc5MTUwMw@@._V1_SX300.jpg",
    "Metascore": "83",
    "imdbRating": "7.9",
    "imdbVotes": "876,575",
    "imdbID": "tt0499549",
    "Type": "movie",
    "Response": "True"
    }
    ];

    // Add your code below this line

    var rating = [];
    watchList.map(obj => rating.push({"title": obj.Title, "rating": obj.imdbRating}));

    // Add your code above this line

    console.log(rating);

  • Implement map on a Prototype

    map这样返回一个与原数组等长的新数组,遍历原数组的每个元素,并且不改变原数组的方法,我们称之为pure function,而且它只依赖它输入的参数。

    需要注意的是,pure function可以改变它自身函数作用域中的本地变量,但是同样不建议这么做。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var s = [23, 65, 98, 5];

    Array.prototype.myMap = function(callback){
    var newArray = [];
    // Add your code below this line
    this.forEach(ele => newArray.push(callback(ele)))
    // Add your code above this line
    return newArray;

    };

    var new_s = s.myMap(function(item){
    return item * 2;
    });

  • Use the filter Method to Extract Data from an Array

    另一个非常有用的函数是Array.prototype.filter(),它能够返回一个新的数组,新数组的长度可以和原数组等长,但通常情况下新数组长度都会少于原数组。

    filter有一个回调函数作为参数,如果数组元素在回调函数中返回true则可以被添加到新数组中。

    1
    2
    3
    4
    5
    6
    var filteredList = []; 
    watchList.filter(movie => movie.imdbRating >= 8).map(movie => filteredList.push({"title": movie.Title, "rating": movie.imdbRating}));

    // Add your code above this line

    console.log(filteredList);

  • Implement the filter Method on a Prototype

    同样地,我们可以用for循环或者forEach来实现我们自己的filter方法,并添加到数组的原型上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var s = [23, 65, 98, 5];

    Array.prototype.myFilter = function(callback){
    var newArray = [];
    // Add your code below this line
    this.forEach(ele => callback(ele)? newArray.push(ele): newArray);
    // Add your code above this line
    return newArray;

    };

    var new_s = s.myFilter(function(item){
    return item % 2 === 1;
    });

  • Return Part of an Array Using the slice Method

    slice方法会返回数组中特定元素的拷贝。它接受两个参数,一个是开始切分数组的索引,另一个是结束切分的索引(不包括这一个元素)如果第二个元素没有传入,默认切分到数组结束。这样很容易帮我们拷贝整个数组。slice方法不会改变原数组,只会返回一个新的。

    1
    2
    3
    4
    5
    6
    7
    8
    function sliceArray(anim, beginSlice, endSlice) {
    // Add your code below this line
    return anim.slice(beginSlice, endSlice);

    // Add your code above this line
    }
    var inputAnim = ["Cat", "Dog", "Tiger", "Zebra", "Ant"];
    sliceArray(inputAnim, 1, 3);

  • Remove Elements from an Array Using slice Instead of splice

    当我们需要从一个数组中移除一个元素时,我们会经常使用splice方法,它接受两个参数,第一个是开始移除元素的索引,第二个是移除的个数,如果第二个参数没有传入,则默认移除之后的所有元素。但是splice有一个问题是它会修改原数组。

    如上题,我们可以通过slice方法来获取数组拷贝,而不修改原数组。

    1
    2
    3
    4
    5
    6
    7
    8
    function nonMutatingSplice(cities) {
    // Add your code below this line
    return cities.slice(0,3);

    // Add your code above this line
    }
    var inputCities = ["Chicago", "Delhi", "Islamabad", "London", "Berlin"];
    nonMutatingSplice(inputCities);

  • Combine Two Arrays Using the concat Method

    concat方法可以连接数组或者字符串

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function nonMutatingConcat(original, attach) {
    // Add your code below this line

    return original.concat(attach);
    // Add your code above this line
    }
    var first = [1, 2, 3];
    var second = [4, 5];
    nonMutatingConcat(first, second);

  • Add Elements to the End of an Array Using concat Instead of push

    函数式编程围绕创建函数和使用不污染环境的函数展开。

    上题提到的concat方法和push比较会发现,concat可以连接两个数组,并返回一个副本,原数组不受影响。因此,concat可以作为没有副作用的为数组添加新元素的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function nonMutatingPush(original, newItem) {
    // Add your code below this line
    return original.concat(newItem);

    // Add your code above this line
    }
    var first = [1, 2, 3];
    var second = [4, 5];
    nonMutatingPush(first, second);

  • Use the reduce Method to Analyze Data

    reduce是JavaScript中几乎使用最广泛的处理数组的方法。它能解决大部分的数组问题。

    mapfilter方法都无法处理两个数组元素之间的操作,如比较大小或求和,相比之下,reduce能够用来解决更为广泛的数组处理。我们可以理解成filtermap都是源于reduce的一种特别应用。

    1
    2
    3
    4
    5
    6
    let movies = watchList.filter(movie => movie.Director === "Christopher Nolan");
    var averageRating=movies.reduce((acc, cur) => acc + parseFloat(cur.imdbRating), 0)/movies.length;

    // Add your code above this line

    console.log(averageRating);

  • Sort an Array Alphabetically using the sort Method

    sort方法用于按照参数callback的规则给数组排序。

    在实际使用sort时,建议使用callback回调函数来明确排序的方法,因为sort方法的默认排序是Unicode编码,使用默认排序可能会造成预期外的结果。

    1
    2
    3
    4
    5
    6
    7
    function alphabeticalOrder(arr) {
    // Add your code below this line
    return arr.sort();

    // Add your code above this line
    }
    alphabeticalOrder(["a", "d", "c", "a", "z", "g"]);

  • Return a Sorted Array Without Changing the Original Array

    sort方法的一个副作用是会改变原数组中的顺序,换句话说,它污染了数组数据。规避这一问题可以使用一个空数组,让它使用concat方法去连接需要排序的原数组,这样就能在concat方法返回的新数组上修改顺序了。

    1
    2
    3
    4
    5
    6
    7
    8
    var globalArray = [5, 6, 3, 2, 9];
    function nonMutatingSort(arr) {
    // Add your code below this line
    return [].concat(globalArray).sort((a, b) => a-b);

    // Add your code above this line
    }
    nonMutatingSort(globalArray);

  • Split a String into an Array Using the split Method

    split方法能够将一个字符串切分成一个由字符串组成的数组。split方法接受一个参数作为切分字符串的分界符,这个参数可以是字符串也可以是正则表达式。

    因为字符串本身不可遍历,split方法让字符串转换成数组从而可以遍历。

    1
    2
    3
    4
    5
    6
    7
    function splitify(str) {
    // Add your code below this line
    return str.split(/[^A-Za-z]/);

    // Add your code above this line
    }
    splitify("Hello World,I-am code");

  • Combine an Array into a String Using the join Method

    join方法用来将数组连接成一个字符串。它同样接受一个参数作为连接字符串的分界符。

    1
    2
    3
    4
    5
    6
    7
    function sentensify(str) {
    // Add your code below this line
    return str.split(/[^A-Za-z]/).join(" ");

    // Add your code above this line
    }
    sentensify("May-the-force-be-with-you");

  • Apply Functional Programming to Convert Strings to URL Slugs

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // the global variable
    var globalTitle = "Winter Is Coming";

    // Add your code below this line
    function urlSlug(title) {
    return title.toLowerCase().split(/[^A-Za-z]/).filter(str => str!== "").reduce((acc, cur) => acc+"-"+cur);

    }
    // Add your code above this line

    var winterComing = urlSlug(globalTitle); // Should be "winter-is-coming"

  • Use the every Method to Check that Every Element in an Array Meets a Criteria

    every方法用于测试数组内的每个元素是不是都能通过特定的测试。它最终返回一个布尔值作为结果。如果所有元素都满足特定要求则返回true,否则返回false

    1
    2
    3
    4
    5
    6
    7
    function checkPositive(arr) {
    // Add your code below this line
    return arr.every(val => val > 0)

    // Add your code above this line
    }
    checkPositive([1, 2, 3, -4, 5]);

  • Use the some Method to Check that Any Elements in an Array Meet a Criteria

    some方法用于测试数组中的一些元素是否能通过特定的测试。即只要元素中有一个元素满足要求则返回true,如果所有元素都不满足要求则返回false

    1
    2
    3
    4
    5
    6
    7
    function checkPositive(arr) {
    // Add your code below this line
    return arr.some(val => val > 0);

    // Add your code above this line
    }
    checkPositive([1, 2, 3, -4, 5]);

  • Introduction to Currying and Partial Application

    arity参数个数指函数所需要的参数个数。currying柯里化函数把一个需要n个参数的函数转换成n个只需要1个参数的函数。换句话说,curring函数会重构函数,将函数转变成一个值需要一个参数的函数,并且返回结果是需要另一个接受余下参数的函数,一直延续向下。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //例:
    //Un-curried function
    function unCurried(x, y) {
    return x + y;
    }

    //curried function
    function curried(x) {
    return function(y) {
    return x + y;
    }
    }
    curried(1)(2)

    curring函数在无法一次性提供所有参数的情况下非常有用。可以用变量来保存每一次函数,等到函数需要的参数能够提供的时候再通过变量来调用它。

    同样地,partial application偏函数接受部分参数,但不是全部参数,同时返回一个能够接受余下参数的函数。

    1
    2
    3
    4
    5
    6
    //例
    function impartial(x, y, z) {
    return x + y + z;
    }
    var partialFn = impartial/bind(this, 1, 2);
    partialFn(10); //returns 13
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function add(x) {
    // Add your code below this line
    return function(y) {
    return function(z) {
    return x + y + z;
    }
    }
    // Add your code above this line
    }
    add(10)(20)(30);