黑马程序员技术交流社区

标题: 【成都校区】-JavaScript 的未来之值和函数式编程 [打印本页]

作者: 小刀葛小伦    时间: 2019-5-30 15:56
标题: 【成都校区】-JavaScript 的未来之值和函数式编程
本帖最后由 小刀葛小伦 于 2019-5-30 15:56 编辑

一. 值
1.按值比较对象
目前,JavaScript 只能对原始值(value)进行比较,例如字符串的值(通过查看其内容):
[JavaScript] 纯文本查看 复制代码
1> 'abc' === 'abc'
2true

相反,对象则通过身份ID(identity)进行比较(对象仅严格等于自身):
[JavaScript] 纯文本查看 复制代码
1> {x: 1, y: 4} === {x: 1, y: 4}
2false
如果有一种能够创建按值进行比较对象的方法,那将是很不错的:
[JavaScript] 纯文本查看 复制代码
1> #{x: 1, y: 4} === #{x: 1, y: 4}
2true
另一种可能性是引入一种新的类(确切的细节还有待确定):
[JavaScript] 纯文本查看 复制代码
1@[ValueType]
2class Point {
3  // ···
4}
旁注:这种类似装饰器的将类标记为值类型的的语法基于草案提案。
2.将对象放入数据结构中
如果对象通过身份ID进行比较,将它们放入 ECMAScript  数据结构(如Maps)中并没有太大意义:
[JavaScript] 纯文本查看 复制代码
1const m = new Map();
2m.set({x: 1, y: 4}, 1);
3m.set({x: 1, y: 4}, 2);
4assert.equal(m.size, 2);
可以通过自定义值类型修复此问题。 或者通过自定义 Set 元素和 Map keys 的管理。 例如:
  • 通过哈希表映射:需要一个操作来检查值是否相等,另一个操作用于创建哈希码。 如果使用哈希码,则对象应该是不可变的。 否则破坏数据结构就太容易了。
  • 通过排序树映射:需要一个比较值的操作用来管理它存储的值

3.大整数JavaScript 的数字总是64位的(双精度),它能为整数提供53位二进制宽度。这意味着如果超过53位,就不好使了:
[JavaScript] 纯文本查看 复制代码
1> 2 ** 53
29007199254740992
3> (2 ** 53) + 1  // can’t be represented
49007199254740992
5> (2 ** 53) + 2
69007199254740994

对于某些场景,这是一个相当大的限制。现在有[BigInts提案](http://2ality.com/2017/03/es-integer.html),这是真正的整数,其精度可以随着需要而增长:
[JavaScript] 纯文本查看 复制代码
1> 2n ** 53n
29007199254740992n
3> (2n ** 53n) + 1n
49007199254740993n

BigInts还支持 casting,它为你提供固定位数的值:
[JavaScript] 纯文本查看 复制代码
1const int64a = BigInt.asUintN(64, 12345n);
2const int64b = BigInt.asUintN(64, 67890n);
3const result = BigInt.asUintN(64, int64a * int64b);

4.小数计算
JavaScript 的数字是基于 IEEE 754 标准的64位浮点数(双精度数)。鉴于它们的表示形式是基于二进制的,在处理小数部分时可能会出现舍入误差:
[JavaScript] 纯文本查看 复制代码
1> 0.1 + 0.2
20.30000000000000004

这在科学计算和金融技术(金融科技)中尤其成问题。基于十进制运算的提案目前处于阶段0。它们可能最终被这样使用(注意十进制数的后缀 m):
[JavaScript] 纯文本查看 复制代码
1> 0.1m + 0.2m
20.3m

5.对值进行分类
目前,在 JavaScript 中对值进行分类非常麻烦:

[JavaScript] 纯文本查看 复制代码
1> typeof null
2'object'
3> typeof function () {}
4'function'
5> typeof []
6'object'
第三,instanceof不适用于来自其他realm(框架等)的对象。

也许可能通过库来解决这个问题(如果我有时间,就会实现一个概念性的验证)。
二、函数式编程
1.更多表达式
[JavaScript] 纯文本查看 复制代码
 1// 条件表达式
2let str1 = someBool ? 'yes' : 'no';
3
4// 条件声明
5let str2;
6if (someBool) {
7  str2 = 'yes';
8} else {
9  str2 = 'no';
10}

特别是在函数式语言中,一切都是表达式。 Do-expressions 允许你在所有表达式上下文中使用语句:
[JavaScript] 纯文本查看 复制代码
1let str3 = do {
2  if (someBool) {
3    'yes'
4  } else {
5    'no'
6  }
7};

下面的代码是一个更加现实的例子。如果没有 do-expression,你需要一个立即调用的箭头函数来隐藏范围内的变量 result :
[JavaScript] 纯文本查看 复制代码
1const func = (() => {
2  let result; // cache
3  return () => {
4    if (result === undefined) {
5      result = someComputation();
6    }
7    return result;
8  }
9})();

使用 do-expression,你可以更优雅地编写这段代码:
[JavaScript] 纯文本查看 复制代码
1const func = do {
2  let result;
3  () => {
4    if (result === undefined) {
5      result = someComputation();
6    }
7    return result;
8  };
9};

2.匹配:结构switch
JavaScript 使直接使用对象变得容易。但是根据对象的结构,没有内置的切换 case 分支的方法。看起来是这样的(来自提案的例子):
[JavaScript] 纯文本查看 复制代码
 1const resource = await fetch(jsonService);
2case (resource) {
3  when {status: 200, headers: {'Content-Length': s}} -> {
4    console.log(`size is ${s}`);
5  }
6  when {status: 404} -> {
7    console.log('JSON not found');
8  }
9  when {status} if (status >= 400) -> {
10    throw new RequestError(res);
11  }
12}

正如你所看到的那样,新的 case 语句在某些方面类似于 switch,不过它使用解构来挑选分支。当人们使用嵌套数据结构(例如在编译器中)时,这种功能非常有用。 模式匹配提案【https://github.com/tc39/proposal-pattern-matching】目前处于第1阶段。
3.管道操作
管道操作目前有两个竞争提案 。在本文,我们研究其中的 智能管道(另一个提议被称为 F# Pipelines)。
管道操作的基本思想如下。请考虑代码中的嵌套函数调用。
[JavaScript] 纯文本查看 复制代码
1const y = h(g(f(x)));
但是,这种表示方法通常不能体现我们对计算步骤的看法。在直觉上,我们将它们描述为:
管道运算符能让我们更好地表达这种直觉:
[JavaScript] 纯文本查看 复制代码
1const y = x |> f |> g |> h;
换句话说,以下两个表达式是等价的。
[JavaScript] 纯文本查看 复制代码
1f(123)
2123 |> f
另外,管道运算符支持部分应用程序(类似函数的 .bind() 方法):以下两个表达式是等价的。
[JavaScript] 纯文本查看 复制代码
1123 |> f(#)
2123 |> (x => f(x))
使用管道运算符一个最大的好处是,你可以像使用方法一样使用函数——而无需更改任何原型:
[JavaScript] 纯文本查看 复制代码
1import {map} from 'array-tools';
2const result = arr |> map(#, x => x * 2);
最后,让我们看一个长一点的例子(取自提案并稍作编辑):
[JavaScript] 纯文本查看 复制代码
 1promise
2|> await #
3|> # || throw new TypeError(
4  `Invalid value from ${promise}`)
5|> capitalize // function call
6|> # + '!'
7|> new User.Message(#)
8|> await stream.write(#)
9|> console.log // method call
10;











欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2