JS 函数式编程思维简述(二):高阶函数

阿拉拉布 · · 766 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

  1. 简述
  2. 无副作用(No Side Effects)
  3. 高阶函数(High-Order Function)
  4. 科里化(Currying)
  5. 闭包(Closure)
  6. 不可变(Immutable)
  7. 惰性计算(Lazy Evaluation)
  8. Monad

一等公民

       高阶函数(High-Order Function)是函数式编程思维中的重要条件,而满足该条件的编程语言则需要将函数作为该语言的一等公民来看待。符合一等公民的条件是:

  • 函数可以作为一种数据类型的值,赋值于一个变量;
  • 函数可以作为参数,在其他函数中进行传递;
  • 函数可以作为返回值,在其他函数中返回;
image

       将函数视作一等公民的语言有:JavaScript、Golang、Python、Scala、Lua、Lisp、Scheme等。同时,有着越来越多的其他语言看上了函数式编程的出彩之处,以其特有的方式实现着符合自身编程方式的高阶函数

函数类型

       在 JavaScript 中,函数是数据类型 object 的子类型——即是指一种对象类型。我们可以通过 typeof 操作符检测一个值是否是一个函数类型:

// 一个函数声明
function foo(x){
    return x + 10;
}
typeof foo; // 返回值:'function'

然而,实际上在 JavaScript 中,函数并非是基本的数据类型,函数隶属于对象类型。能够使用 typeof 操作符进行检测仅仅是语言提供的便利:

// 声明一个 number 类型的变量
const n = 13;
// 一个函数声明
function foo(x){
    return x + 10;
}
typeof foo; // 结果:'function'
typeof n; // 结果:'number'

// 检测 n 所持有的值是否是对象
n instanceof Object; // 结果:false

// 检测 foo 所持有的值是否是对象
foo instanceof Function; // 结果:true
Function instanceof Object; // 结果:true
foo instanceof Object; // 结果:true

可见,函数是一个隶属于 Function 的对象,而 Function 本身又隶属于顶层 Object ,是它的子对象。因此,一个函数的实例,也隶属于 Object ,他们之间拥有间接的继承关系。
       很多有 面向对象 经验的同学可能会想,实例化对象不是通过 new 关键字调用类的构造函数来进行的吗?这个问题很简单:拿 Java 例举,Java 中拥有字面量形式的对象声明方式 String str = "I like Java!";,声明变量 str 的过程中实际上也构建了一个字符串对象,并没有显式的使用关键字 new
       在 JavaScript 中,以字面量的方式构建对象有很多种,比如:

// 数组字面量
const arr = [1, 2, 3];
// 对象字面量
const obj = {id : 'xx001'};
// 函数字面量
function foo(){}            // 函数声明
const bar = function(){}    // 函数表达式
const baz = (x) => x + 3;   // ES6提供的lambda表达式函数

函数入参

       由于函数也是一个对象,因此函数也可以作为其他函数的参数,作为入参:

// 一个函数声明
const add2 = (x) => x + 2;          // 参数x基础上加2的函数
const sub2 = (x) => x - 2;          // 参数x基础上减2的函数
const result = (y, f) => y * f(y);  // 参数y基础上乘以 函数参数f 的运算结果

result(4, add2);    // 结果: 24
result(4, sub2);    // 结果: 8

       在 JavaScript 内置对象中,也有非常多的函数入参实例,比如 Array.prototype.map 函数的简单实现:

// 一个高仿的 Array.prototype.map 函数
const map = function(arr, f){
    const t = []; 
    for(let i=0;i<arr.length; t.push(f(arr[i],i++,arr)));
    return t;
}
// 声明一个数组
const a1 = [1,2,3,4];
// map函数调用:参数 f 所示为每一个值乘以3,并且返回一个新数组
const a2 = map(a1, (e) => e*3); // 结果:[3, 6, 9, 12]

函数返回值

       函数可以作为参数,当然也可以作为返回值。作为返回值的函数,常用于缓存上一个函数的执行状态:

// 一个函数声明
const add2 = (x) => x + 2;          // 参数x基础上加 2 的函数
const mul2 = (x) => x * 2;          // 参数x基础上乘以 2 的函数

// 该函数用于计算,计算结果不会直接得出,而是缓存了用于计算的两个函数
const calc = function(f1, f2){
    return (y) => f1( f2(y) );
}

// 根据缓存顺序不同,生成的新的函数执行过程也不同
const c01 = calc(add2, mul2); 
c01(3); // 结果: 8

const c02 = calc(mul2, add2); 
c02(3); // 结果:10

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:阿拉拉布

查看原文:JS 函数式编程思维简述(二):高阶函数

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

766 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传