1. background

In pursuit of a real-world application, let’s say we need an e-commerce web application
for a mail-order coffee bean company. They sell several types of coffee and in different
quantities, both of which affect the price.

  1. Imperative methods

First, let’s go with the procedural route. To keep this demonstration down to earth, we’ll
have to create objects that hold the data. This allows the ability to fetch the values from a
database if we need to. But for now, we’ll assume they’re statically defined:

  1. // create some objects to store the data.
  2. var columbian = {
  3. name: 'columbian',
  4. basePrice: 5
  5. };
  6. var frenchRoast = {
  7. name: 'french roast',
  8. basePrice: 8
  9. };
  10. var decaf = {
  11. name: 'decaf',
  12. basePrice: 6
  13. };

// we'll use a helper function to calculate the cost
// according to the size and print it to an HTML list
function printPrice(coffee, size) {
  if (size == 'small') {
    var price = coffee.basePrice + 2;
  }
  else if (size == 'medium') {
    var price = coffee.basePrice + 4;
  }
  else {
    var price = coffee.basePrice + 6;
  }
  // create the new html list item
  var node = document.createElement("li");
  var label = coffee.name + ' ' + size;
  var textnode = document.createTextNode(label+' price: $'+price);
  node.appendChild(textnode);
  document.getElementById('products').appendChild(node);
}
// now all we need to do is call the printPrice function
// for every single combination of coffee type and size
printPrice(columbian, 'small');
printPrice(columbian, 'medium');
printPrice(columbian, 'large');
printPrice(frenchRoast, 'small');
printPrice(frenchRoast, 'medium');
printPrice(frenchRoast, 'large');
printPrice(decaf, 'small');
printPrice(decaf, 'medium');
printPrice(decaf, 'large');

  1.  
  1. Functional programming

While imperative code tells the machine, step-by-step, what it needs to do to solve the
problem, functional programming instead seeks to describe the problem mathematically so
that the machine can do the rest.
With a more functional approach, the same application can be written as follows:

  1. // separate the data and logic from the interface
  2. var printPrice = function(price, label) {
  3. var node = document.createElement("li");
  4. var textnode = document.createTextNode(label+' price: $'+price);
  5. node.appendChild(textnode);
  6. document.getElementById('products 2').appendChild(node);
  7. }
  8. // create function objects for each type of coffee
  9. var columbian = function(){
  10. this.name = 'columbian';
  11. this.basePrice = 5;
  12. };
  13. var frenchRoast = function(){
  14. this.name = 'french roast';
  15. this.basePrice = 8;
  16. };
  17. var decaf = function(){
  18. this.name = 'decaf';
  19. this.basePrice = 6;
  20. };
  21. // create object literals for the different sizes
  22. var small = {
  23. getPrice: function(){return this.basePrice + 2},
  24. getLabel: function(){return this.name + ' small'}
  25. };
  26. var medium = {
  27. getPrice: function(){return this.basePrice + 4},
  28. getLabel: function(){return this.name + ' medium'}
  29. };
  30. var large = {
  31. getPrice: function(){return this.basePrice + 6},
  32. getLabel: function(){return this.name + ' large'}
  33. };
  34. // put all the coffee types and sizes into arrays
  35. var coffeeTypes = [columbian, frenchRoast, decaf];
  36. var coffeeSizes = [small, medium, large];
  37. // build new objects that are combinations of the above
  38. // and put them into a new array
  39. var coffees = coffeeTypes.reduce(function(previous, current) {
  40. var newCoffee = coffeeSizes.map(function(mixin) {
  41. // `plusmix` function for functional mixins, see Ch.7
  42. var newCoffeeObj = plusMixin(current, mixin);
  43. return new newCoffeeObj();
  44. });
  45. return previous.concat(newCoffee);
  46. },[]);
  47. // we've now defined how to get the price and label for each
  48. // coffee type and size combination, now we can just print them
  49. coffees.forEach(function(coffee){
  50. printPrice(coffee.getPrice(),coffee.getLabel());
  51. });
  52.  
  1. The first thing that should be obvious is that it is much more modular. This makes adding
  2. a new size or a new coffee type as simple as shown in the following code snippet:
  1. var peruvian = function(){
  2. this.name = 'peruvian';
  3. this.basePrice = 11;
  4. };
  5. var extraLarge = {
  6. getPrice: function(){return this.basePrice + 10},
  7. getLabel: function(){return this.name + ' extra large'}
  8. };
  9. coffeeTypes.push(Peruvian);
  10. coffeeSizes.push(extraLarge);

Arrays of coffee objects and size objects are “mixed” together,—that is, their methods and
member variables are combined—with a custom function called plusMixin (see Chapter
7, Functional and Object-oriented Programming in JavaScript). The coffee type classes
contain the member variables and the sizes contain methods to calculate the name and
price. The “mixing” happens within a map operation, which applies a pure function to each
element in an array and returns a new function inside a reduce() operation—another
higher-order function similar to the map function, except that all the elements in the array
are combined into one. Finally, the new array of all possible combinations of types and
sizes is iterated through with the forEach() method The forEach() method is yet another
higher-order function that applies a callback function to each object in an array. In this
example, we provide it as an anonymous function that instantiates the objects and calls the
printPrice() function with the object’s getPrice() and getLabel() methods as
arguments.
Actually, we could make this example even more functional by removing the coffees
variable and chaining the functions together—another little trick in functional
programming.

  1. coffeeTypes.reduce(function(previous, current) {
  2. var newCoffee = coffeeSizes.map(function(mixin) {
  3. // `plusMixin` function for functional mixins, see Ch.7
  4. var newCoffeeObj = plusMixin(current, mixin);
  5. return new newCoffeeObj();
  6. });
  7. return previous.concat(newCoffee);
  8. },[]).forEach(function(coffee) {
  9. printPrice(coffee.getPrice(),coffee.getLabel());
  10. });

Also, the control flow is not as top-to-bottom as the imperative code was. In functional
programming, the map() function and other higher-order functions take the place of for
and while loops and very little importance is placed on the order of execution. This makes
it a little trickier for newcomers to the paradigm to read the code but, once you get the
hang of it, it’s not hard at all to follow and you’ll see that it is much better.

  1.  

a primary example for Functional programming in javascript的更多相关文章

  1. JavaScript Functional Programming

    JavaScript Functional Programming JavaScript 函数式编程 anonymous function https://en.wikipedia.org/wiki/ ...

  2. BETTER SUPPORT FOR FUNCTIONAL PROGRAMMING IN ANGULAR 2

    In this blog post I will talk about the changes coming in Angular 2 that will improve its support fo ...

  3. Functional Programming without Lambda - Part 1 Functional Composition

    Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...

  4. Sth about 函数式编程(Functional Programming)

    今天开会提到了函数式编程,针对不同类型的百年城方式,查阅了一部分资料,展示如下: 编程语言一直到近代,从汇编到C到Java,都是站在计算机的角度,考虑CPU的运行模式和运行效率,以求通过设计一个高效的 ...

  5. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

  6. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  7. Functional programming

    In computer science, functional programming is a programming paradigm, a style of building the struc ...

  8. Java 中的函数式编程(Functional Programming):Lambda 初识

    Java 8 发布带来的一个主要特性就是对函数式编程的支持. 而 Lambda 表达式就是一个新的并且很重要的一个概念. 它提供了一个简单并且很简洁的编码方式. 首先从几个简单的 Lambda 表达式 ...

  9. Functional programming idiom

    A functional programming function is like a mathematical function, which produces an output that typ ...

随机推荐

  1. ireport5.6+jasperreport6.3开发(四)--以javabean为基准的报表开发(ireport)

    javabean完成以后就是添加ireport的报表了 打开ireport的option然后在classpath中添加路径. 然后在ireport中追加数据源如图,点击图标后会出现数据源列表然后按ne ...

  2. AES,RSA对称加密和非对称加密

    1.关于RSA加密机制:是非对称加密方式,两个钥,公钥和私钥,公钥用于加密数据,可以分享给其他用户,私钥可以用于解密用公钥加密的数据,关于安全问题是公钥泄露不会影响安全问题,公钥与私钥是一一对应的关系 ...

  3. MySQL问题记录--Can't connect to MySQL server on localhost (10061)解决方法

    本文mysql的安装环境为win7 64位,mysql版本为MySQL5.7 问题描述:在命令行输入 mysql -u root -p 登录mysql,返回"Can't connect to ...

  4. 摸索Tableau

    将本年度第几周转变为对应范围内的某日期 201607 → 2016-02-18 DATEADD('day',7*(int(RIGHT([WEEK_ID],2))-1),DATEPARSE(" ...

  5. Unity3D 中的定时器

    不算上 C# 自带的,目前知道两种,以下分别介绍. 1.每帧检查 定义一个时间变量 timer,每帧将此时间减去帧间隔时间 Time.deltaTime,如果小于或者等于零,说明定时器到了,执行相应功 ...

  6. PHP5.3.3+Apache2.2.16+MySQL5.1.49

    轻松配置PHP5.3.3+Apache2.2.16+MySQL5.1.49,下面是有详细的步骤说明.   第一步:下载安装的文件 1. MySQL:下载地址mysql-5.1.49-win32.msi ...

  7. systemctl命令用法详解

    systemctl命令用法详解系统环境:Fedora 16binpath:/bin/systemctlpackage:systemd-units systemctl enable httpd.serv ...

  8. c#数据绑定(4)——向查询中添加参数

    本实例主要练习了ADO.Net 连接到外部数据库的基础上,向查询中添加参数.使用的是ACCESS数据库. 在ACCESS数据库中可以用MSSQL的形式定义操作字符串,也可以采用OLEDB的形式. MS ...

  9. 269. Alien Dictionary 另类字典 *HARD*

    There is a new alien language which uses the latin alphabet. However, the order among letters are un ...

  10. 用于阻止div上的事件和div上的按钮的事件同时触发

    event.stopPropagation()  阻止事件冒泡  用于ie11以上