秦粤:“和你聊聊 JS 历史和今年 D2 的语言框架专场”

简介: D2语言框架专场,推荐前端同学们一定要学习下哦。

作者 | 秦粤

点击查看视频

大家好,我是秦粤。阿里巴巴自从2019年加入Ecma后,我们就在Ecma中积极参与推进,决定JavaScript语言发展未来的各种议题,阿里巴巴的议题Error Cause也已经成功的推进到Stage 2。今年在阿里内部由前端委员会牵头也成立了阿里巴巴前端标准化小组,用组织架构保障阿里前端,持续在影响前端生态未来的标准规范上发力。

与此同时我们也特别关注到TC39成员中,不少成员都在关注和推进JavaScript中函数式编程的体验。作为今年D2语言框架会场的出品人,因此我们邀请了RxJS的团队负责人Ben,引入JavaScript函数式编程的议题。另外,今年Ecma组织的大事件ES2020已经发布,我们也将继续邀请TC39的成员Ujjwal,讲解其中有哪些特性值得我们前端同学关注以及这些议题的诞生过程。

函数式编程 in Javascript

函数式编程的思想从1930年提出来已经过去很久了,但大多数工程师使用的场景并不多。函数式编程在JavaScript中几乎是天然就支持的,Brendan Eich参考的语言中包括了函数式编程语言Lisp,因此JavaScript有了函数是一等公民和闭包的概念。

我们大学学习的离散数学,线性代数等等课程,都很容易让我们习惯面向指令编程。我们的代码习惯性都是从上到下,从左到右,加上控制指令block的方式。

ES5之前,如果我们学习了面向原型,会在我们的代码中采用prototype。

ES6和TS后,如果我们学习了面向对象,代码中又会加上Class抽象。

但某种程度而言,这些代码方式都是面向机器友好的。函数式编程是否可以带来一些改变呢?

我自己使用函数式编程的感受是,在面对每个要开发的功能,就像在解数学题。首要是思考数据加工过程如何拆解,初期要不停查工具,看看有哪些函数方法可以给我使用。后期熟练后,会开始用函数式注释,毕竟长时间不看自己原先的代码,同样会忘记。而且不会采用一逗(句号)到底的方式,分段一下。

函数式编程的基础概念,我在此就不啰嗦了。它们是:范畴论,函数一等公民,纯函数,组合,柯里化,等等。

感兴趣的同学可以学习一下:https://mostly-adequate.gitbooks.io/mostly-adequate-guide/content/

举个例子

"show me the code",我们来看看具体例子:调用后台API返回了一个数组,其中我们需要对商品的金额进行汇率运算,转换成用户本地的汇率显示。

{
  success: true,
  data: {
    'name': 'ProductsDetail',
    'list': [
      {
        name:'T shirt',
        price:'10.00',
        unit:'$'
      },
      {
        name:'T shirt with logo',
        price:'15.00',
        unit:'$'
      },
      {
        name:'T shirt with brand logo',
        price:'20.00',
        unit:'$'
      },
    ],
  },
}
{
  userCurrency: '¥',
  userCurrencyRate: '6.5',
}

通常,我们会直接写一个循环,或者用UnderscoreJS这样的库将price获取到转化成数字,然后乘以userCurrencyRate。

我们不妨看看函数式的做法,先从简单的函数拆解来看。例如我们乘法函数,我们通常会这样写:

const multiply = function(x,y) {
  return x * y;
}
multiply(3, 5);// 15

而当我们想复用乘法函数,例如固定乘3的函数。我们可以采用JS高级编程的柯里化Currying。

先复习一下柯里化Currying:一个函数将返回一个新的函数,直到接收所有参数。我们用Vanilla JS可以写成:

const multiply = function(x) {
  return function(y) {
    return x * y;
  }
}
const multiply3 = multiply(3);
multiply3(5);// 15

不过这样还有一些不方便,Curry函数这些的写法,我们想用multiply函数multiply(3,5)又不可以了。JS高级编程常见的面试题之一,就是autoCurry,顾名思义根据参数判断函数如何返回。有兴趣的同学可以自己挑战一下实现autoCurry函数,这里我们就直接采用RamdaJS的curry方法。

const R = require('ramda');

const multiply = function(x, y) {
  return x * y;
};
const multiplyAutoCurry = R.curry(multiply);

multiplyAutoCurry(3)(5);// 15
multiplyAutoCurry(3, 5);// 15

有了Curry函数,对于数组我们可以使用map函数,将函数应用到每一项。

const R = require('ramda');

const multiply = function (x, y) {
  return x * y;
};
const multiplyAutoCurry = R.curry(multiply);
const multiply3 = multiplyAutoCurry(3);
R.map(multiply3, [1, 2, 3]);// [3, 6, 9]

因此函数式编程的版本实现,我们就可以写成:

const R = require('ramda');

const multiply = function (x, y) {
  return x * y;
};
const multiplyAutoCurry = R.curry(multiply);
const multiplyCurrency = multiplyAutoCurry(6.5);
const parseIntCurry = R.curry(parseInt);
const parseInt10 = parseIntCurry(R.__, 10);
const currencyConvert = R.compose(multiplyCurrency, parseInt10);

const result = {
  success: true,
  data: {
    name: 'ProductsDetail',
    list: [
      {
        name: 'T shirt',
        price: '10.00',
        unit: '$'
      },
      {
        name: 'T shirt with logo',
        price: '15.00',
        unit: '$'
      },
      {
        name: 'T shirt with brand logo',
        price: '20.00',
        unit: '$'
      },
    ],
  },
};
const priceArray = R.pluck('price', R.prop('list', R.prop('data', result)));// ['10.00', '15.00', '20.00']
R.map(currencyConvert, priceArray);// [ 65, 97.5, 130 ]

由于API返回的结果中price是字符串,为了消除不确定性,我们需要先将price转为数字。这里我们可以用parsefloat,为了演示如何将build-in函数转化成函数式,我选择了parseInt,通过第二个参数传入10解决低版本浏览器兼容性问题。

R.compose是将2个方法组合使用,执行顺序是从右到左。然后我们只需要将我们组合好的工厂函数应用到获取到的价格数组上就行了。

D2 语言框架专场

大家可以发现,我们整个运算过程只使用一次元数据result,这也就是“无副作用”。另外我们将整个过程都转化成了数学解题,而不是让自己像计算机一样思考。前端同学们熟悉的React库也在使用函数式编程的思想,例如单向数据流,State要求immutable。

对于数组和数据流的操作,特别适合函数式操作。ReactiveX就是将数据看成是函数式流处理,因此抽象出Observable, Observer, Subscription等等概念。

import { fromEvent } from 'rxjs';
import { throttleTime, scan } from 'rxjs/operators';

fromEvent(document, 'click')
  .pipe(
    throttleTime(1000),
    scan(count => count + 1, 0)
  )
  .subscribe(count => console.log(`Clicked ${count} times`));

今年D2的语言与框架专场邀请了RxJS:Reactive Extensions For JavaScript团队负责人Ben Lesh,讲解如何利用JS特性重构RxJS,让代码更小更快。

另外函数式在TC39中,也是大厂专家积极讨论的对象,如何优化JS中写函数式的体验,相关议题有:

https://github.com/tc39/proposal-pipeline-operator

https://github.com/tc39/proposal-partial-application

https://github.com/tc39/proposal-pattern-matching

https://github.com/tc39/proposal-record-tuple

同时我们也邀请了Igalia的TC成员Ujjwal,为我们讲解ES2020和ES2021都有哪些可以提升我们JS开发体验的新特性,以及这些特性是如何从TC39中诞生的,我们如何决定影响JS语言的未来。

结语

函数式编程也不是银弹,但在适用的场景,非常好用。大家无妨给自己的工具箱多装备一个函数式编程的工具。我在今年的D2大会语言与框架专场等你。

参考文献:

https://mostly-adequate.gitbooks.io/mostly-adequate-guide/content/

Hey Underscore, You're Doing It Wrong!:

https://www.youtube.com/watch?v=m3svKOdZijA

JavaScript函数式编程:

https://github.com/doodlewind/jshistory-cn/blob/master/part-1.md

https://mostly-adequate.gitbooks.io/mostly-adequate-guide/content/

image.png


image.png
关注「Alibaba F2E」
把握阿里巴巴前端新动向

相关文章
|
8天前
|
Web App开发 JavaScript 前端开发
深入浅出Node.js后端框架
【10月更文挑战第34天】在数字化时代,后端开发如同一座桥梁,连接着用户界面与数据处理的两端。本文将通过Node.js这一轻量级、高效的平台,带领读者领略后端框架的魅力。我们将从基础概念出发,逐步深入到实战应用,最后探讨如何通过代码示例来巩固学习成果,使读者能够在理论与实践之间架起自己的桥梁。
|
1月前
|
JavaScript 前端开发 中间件
探索后端技术:Node.js与Express框架的完美融合
【10月更文挑战第7天】 在当今数字化时代,Web应用已成为日常生活不可或缺的一部分。本文将深入探讨后端技术的两大重要角色——Node.js和Express框架,分析它们如何通过其独特的特性和优势,为现代Web开发提供强大支持。我们将从Node.js的非阻塞I/O和事件驱动机制,到Express框架的简洁路由和中间件特性,全面解析它们的工作原理及应用场景。此外,本文还将分享一些实际开发中的小技巧,帮助你更有效地利用这些技术构建高效、可扩展的Web应用。无论你是刚入门的新手,还是经验丰富的开发者,相信这篇文章都能为你带来新的启发和思考。
|
1月前
|
JavaScript 前端开发 API
Vue.js:现代前端开发的强大框架
【10月更文挑战第11天】Vue.js:现代前端开发的强大框架
65 41
|
14天前
|
JavaScript 中间件 API
Node.js进阶:Koa框架下的RESTful API设计与实现
【10月更文挑战第28天】本文介绍了如何在Koa框架下设计与实现RESTful API。首先概述了Koa框架的特点,接着讲解了RESTful API的设计原则,包括无状态和统一接口。最后,通过一个简单的博客系统示例,详细展示了如何使用Koa和koa-router实现常见的CRUD操作,包括获取、创建、更新和删除文章。
35 4
|
21天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的完美结合
【10月更文挑战第21天】本文将引导你走进Node.js和Express框架的世界,探索它们如何共同打造一个高效、可扩展的后端服务。通过深入浅出的解释和实际代码示例,我们将一起理解这一组合的魅力所在,并学习如何利用它们来构建现代Web应用。
41 1
|
1月前
|
设计模式 JavaScript 前端开发
浅谈JavaScript 框架在现代 Web 开发中的作用
浅谈JavaScript 框架在现代 Web 开发中的作用
38 12
|
9天前
|
Web App开发 JavaScript 前端开发
构建高效后端服务:Node.js与Express框架的实践
【10月更文挑战第33天】在数字化时代的浪潮中,后端服务的效率和可靠性成为企业竞争的关键。本文将深入探讨如何利用Node.js和Express框架构建高效且易于维护的后端服务。通过实践案例和代码示例,我们将揭示这一组合如何简化开发流程、优化性能,并提升用户体验。无论你是初学者还是有经验的开发者,这篇文章都将为你提供宝贵的见解和实用技巧。
|
11天前
|
Web App开发 JavaScript 中间件
构建高效后端服务:Node.js与Express框架的融合之道
【10月更文挑战第31天】在追求快速、灵活和高效的后端开发领域,Node.js与Express框架的结合如同咖啡遇见了奶油——完美融合。本文将带你探索这一组合如何让后端服务搭建变得既轻松又充满乐趣,同时确保你的应用能够以光速运行。
20 0
|
1月前
|
JSON JavaScript 前端开发
Node.js Express 框架
10月更文挑战第7天
27 2
|
1月前
|
JavaScript 前端开发 API