首页> 预测未来>正文

前端主流的 Javascript,缺失了哪些技能?

2019/2/23 17:30:49 来源:互联网

原标题:前端主流的 Javascript,缺失了哪些技能?

最近这几年,Java 的使用规模有了很大的增长。在这篇博文里,本文作者将和大家探讨现在 Java 还缺少的内容。


作者 | Axel Rauschmayer

译者 | 彼得

责编 | 屠敏

出品 | CSDN(ID:CSDNNews)

以下为译文:

注:

有关前两个问题的更多想法,请参阅语言设计部分(http://2ality.com/2019/01/future-js.html#language-design)。

数值

根据数值来比较对象

现在,Java 只是对元数据类型(比如,字符串)才使用数值进行比较。也就是对这些元数据类型,根据它们包含的内容进行比较:

> "abc"=== "abc"

true

在对象之间,是根据对象的引用进行比较的。即任何一个对象只能和它自己相同:

> {x: 1, y: 4} === {x: 1, y: 4}

false

如果我们能够创建可以通过数值进行比较的对象,这会将非常有帮助:

> #{x: 1, y: 4} === #{x: 1, y: 4}

true

另一个方法是引入一种新的类来表示(具体细节待定):

@[ValueType]

classPoint{

// ···

}

注:这种方法是通过修饰符来说明该类是基于数值来进行比较的类。该方法是根据这个建议草案提出的(https://github.com/littledan/proposal-reserved-decorator-like-syntax)。

将对象放入数据结构中

由于对象是按引用进行比较的,因此像下面这样将它们放入ECMA的数据结构(如Map)中是没有什么实际意义:

constm = newMap();

m. set({x: 1, y: 4}, 1);

m. set({x: 1, y: 4}, 2);

assert.equal(m.size, 2);

这个问题可以通过自定义值的类型来解决,也可以通过自定义Set元素和Map键值的管理方法来实现。例如:

大整数(BigInt)

Java 中的 Number 类型都是 64 位(双精度)的。对于整数来说,有53位来表示整数的数值还有1位的符号位来表示正负。也就是,只能精确表示53位以内的整数,对于超出53位的整数,没有办法精确区分它们:

> 2 ** 53

9007199254740992

> (2 ** 53) + 1 // can’t be represented

9007199254740992

> (2 ** 53) + 2

9007199254740994

在某些情况下,这是一个很大的限制。现在,有一个对于大整数(BigInt)的建议。根据该建议,整数的精度可以根据需要进行扩展:

> 2n ** 53n

9007199254740992n

> (2n ** 53n) + 1n

9007199254740993n

大整数(BigInt)也支持类型转换,这样就可以得到固定位数的整数:

constint64a = BigInt.asUintN( 64, 12345n);

constint64b = BigInt.asUintN( 64, 67890n);

constresult = BigInt.asUintN( 64, int64a * int64b);

十进制运算

基于 IEEE 754 的规范,Java 中的 Number 类型都是64位(双精度)的。因为这些数是以二进制来表示,所以在进行小数运算的时候,你不可避免地会遇到四舍五入的问题:

> 0 .1+ 0 .2

0 .30000000000000004

在科学计算和金融领域,这是一个比较突出的问题。现在,有一个正处在初始阶段的关于10进制数值的表示方法的提议。如果该提议获得通过,数值可能会以如下方式表示,请注意在小数后面的m用于表示十进制数值:

> 0 .1m+ 0 .2m

0 .3m

数值分类

现在,在 java 中,对数值进行分类是一件非常麻烦的事:

> typeofnull

"object"

> typeoffunction() {}

"function"

> typeof[]

"object"

对于上述的这些问题,可以通过创建特定的 Java 库来解决。以后,如果有时间,我自己会试着实现。

函数式编程

更多的表达式

和 C 语言风格类似的编程语言都对于表达式和程序语句做了明确的区分:

// Conditional expression

letstr1 = someBool ? "yes": "no";

// Conditional statement

letstr2;

if(someBool) {

str2 = "yes";

} else{

str2 = "no";

}

在函数式语言中,任何对象都是表达式。使用表达式将使你能在任何表达式的上下文中使用表达式:

letstr3 = do{

if(someBool) {

"yes"

} else{

"no"

}

};

以下的代码是一个更实际的例子。如果没有 do 的表达式,为了避免作用域内的变量 result,就需要立即调用 arrow 函数来实现:

constfunc = (() =>{

letresult; // cache

return()=>{

if(result === undefined) {

result = someComputation();

}

returnresult;

}

})();

有了 do 表达式,你的代码会更简洁:

constfunc = do{

letresult;

()=>{

if(result === undefined) {

result = someComputation();

}

returnresult;

};

};

匹配:析构 switch

在 Java 中,直接处理对象是件很容易的事。但是,它没有基于对象结构的切换方法。在建议中提供的事例如下:

constresource = awaitfetch(jsonService);

case(resource) {

when { status: 200, headers: { "Content-Length": s}} -> {

console.log( `size is ${s}`);

}

when { status: 404} -> {

console.log( "JSON not found");

}

when {status} if(status >= 400) -> {

thrownewRequestError(res);

}

}

如上可见,新的 case 语句在某些方面类似于 switch 语句,但使用析构函数来处理 case 命令。在使用嵌套数据结构时(例如在编译器中),这种功能都很有用。模式匹配方案现在处于第一阶段。

管道(Pipeline)操作

对于管道(pipeline)操作,有两个互相竞争的提案。现在,我们先看一下"智能管道"提案;另外一个提案是"F# 管道"。

管道(pipeline)操作的基本思想可以用下面的递归调用来说明:

consty = h(g(f(x)));

但是,管道的概念没有反映出来我们思考的逻辑顺序。我们可以把我们对于上面公式的思考逻辑归纳为下面几步:

使用管道操作,可以使我们更好地描述我们的思考逻辑:

consty = x |> f |> g |> h;

换而言之,下面两个表达式是一样的:

f(123)

123 |> f

另外,管道操作还支持部分应用的功能。该功能类似于 .bind()函 数,下面两个表达式是一样的:

123|> f( #)

123|> (x => f(x))

管道操作的一个重要优势在于你可以像使用方法一样使用函数,而不用进行类型转换:

import{ map} from "array-tools";

constresult = arr |> map(#, x => x * 2);

我们拿一个稍微长一点的例子来总结一下。这个例子来自于提议草案并稍作改动:

promise

|> await#

|> # || throw new TypeError(

`Invalid valuefrom${promise}`)

|> capitalize // function call

|> # + "!"

|> newUser.Message( #)

|> awaitstream.write( #)

|> console.log // method call

;

并发

Java 对于并发的支持一直比较有限。进程并发事实上的标准是 Worker API,它在 Web 浏览器和 node.js 中可用(在 v11.7 及更高版本中没有标志)。

在 Node.js 中,对于 Worker API 可以像下面这样使用:

const{

Worker, isMainThread, parentPort, workerData

} = require( "worker_threads");

if(isMainThread) {

constworker = newWorker(__filename, {

workerData: "the-data.json"

});

worker.on( "message", result => console.log(result));

worker.on( "error", err => console.error(err));

worker.on( "exit", code => {

if(code !== 0) {

console.error( "ERROR: "+ code);

}

});

} else{

const{readFileSync} = require( "fs");

constfileName = workerData;

consttext = readFileSync(fileName, { encoding: "utf8"});

constjson = JSON.parse(text);

parentPort.postMessage(json);

}

相对来讲,Worker 的方式是比较重量级的实现。每一种都需要有自己的领域(全局变量等)。我希望在将来能看到一个更量级的实现。

标准库

现在,Java 明显落后于其他语言的一个方面是它的标准库支持。最小的标准库支持确实有合理的一面,因为它们依赖的外部库会很快地发展和变化。但是,还是有一些非常有用的核心功能需要实现。

用模块替代命名空间(namespace)对象

Java 的标准库是在它支持模块之前创建的。因此,很多方法是被放在命名空间对象(例如 Object,Reflect,Math和JSON)中的:

如果能把这些方法放到特定的模块中,那就更好了。必须通过特殊的 URL 才能使用它们。比如可以使用 std 前缀:

// Old:

assert.deepEqual(

Object.keys({a: 1, b: 2}),

[ "a", "b"]);

// New:

import{keys} from "std:object";

assert.deepEqual(

keys({a: 1, b: 2}),

[ "a", "b"]);

使用这种方法的好处是:

支持 iterables(同步和异步)的工具函数(Helper)

iterables 能提供很多便利,包括只有在需要的时候才计算数值和支持许多数据源。但是,目前 Java 对 iterables 提供的工具函数却很少。比如,现在如果你要筛选、映射或减少 iterable,则只能将它转换为数组:

constiterable = newSet([ -1, 0, -2, 3]);

constfilteredArray = [...iterable].filter( x=>x >= 0);

assert.deepEqual(filteredArray, [ 0, 3]);

如果 Java 能有对 iterables 支持的工具函数,你就可以直接过滤 iterables:

constfilteredIterable = filter(iterable, x => x >= 0);

assert.deepEqual(

// We only convert the iterable to an Array, so we can

// check what’s in it:

[...filteredIterable], [ 0, 3]);

下面是更多可能的 iterables 工具函数的示例:

// Count elements in an iterable

assert.equal(count(iterable), 4);

// Create an iterable over a part of an existing iterable

assert.deepEqual(

[ ...slice(iterable, 2)],

[ -1, 0]);

// Number the elements of an iterable

// (producing another – possibly infinite – iterable)

for( const[i,x] of zip(range(0), iterable)) {

console.log(i, x);

}

// Output:

// 0, -1

// 1, 0

// 2, -2

// 3, 3

请注意:

不可改变的数据

希望 Java 最好能对非破坏性数据转换提供更多支持。两个相关的库是:

对于日期和时间的更好支持

Java 内置的对日期和时间的支持有许多奇怪的地方。也正因为如此,才建议大家在最基本的任务之外的其他任务中才使用系统的日期和时间库。

值得庆幸的是,现在人们正在研究日期和时间方面的更好的 API:

constdateTime = newCivilDateTime( 2000, 12, 31, 23, 59);

constinstantInChicago = dateTime.withZone( "America/Chicago");

可能不太需要的功能

可选链接(chaining)的优缺点

当前一个比较普遍的提议是对于可选链接的支持。根据该提议,以下两个表达式是等效的:

obj?.prop

(obj === undefined|| obj === null) ? undefined: obj.prop

这一功能尤其适用于属性链:

obj? .foo? .bar? .baz

但是,这个功能也有缺点:

可选链接的一个替代方案是在某个特定的位置提取一次信息:

无论采用以上哪种方法,您都能进行检查。早一点发现存在的问题。

更多资料:

我们需要运算符重载吗?

现在,有些人正在为运算符重载做前期的准备工作,但我觉得中缀函数应用程序可能已经足够了(尽管目前没有针对它的提议):

import{BigDecimal, plus} from "big-decimal";

constbd1 = newBigDecimal( "0.1");

constbd2 = newBigDecimal( "0.2");

constbd3 = bd1 @plusbd2; // plus(bd1, bd2)

中缀函数应用的好处是:

这是嵌套表达式的一个例子:

a @plus b @minus c @ timesd

times(minus(plus(a, b), c), d)

有趣的是,pipeline 操作符也有助于提高代码的可读性:

plus(a, b)

|> minus( #, c)

|> times( #, d)

其他内容

这些是我偶尔会错过的一些事情,我也不认为它们像我之前提到的内容那样重要:

newChainedError(msg, origError)

re `/^${RE_YEAR}-${RE_MONTH}-${RE_DAY}$/u`

> constre = newRegExp( RegExp.escape( ":-)"), "ug");

> ":-) :-) :-)".replace(re, "??")

"?? ?? ??"

> [ "a", "b"]. get( -1)

"b"

functionf(...[x, y] as args) {

if(args.length !== 2) {

thrownewError();

}

// ···

}

assert.equal(

{foo: [ "a", "b"]} === {foo: [ "a", "b"]},

false);

assert.equal(

deepEqual({foo: [ "a", "b"]}, {foo: [ "a", "b"]}),

true);

enumWeekendDay {

Saturday, Sunday

}

constday = WeekendDay.Sunday;

constmyMap = Map!{ 1: 2, three: 4, [[ 5]]: 6}

// new Map([1,2], ["three",4], [[5],6])

constmySet = Set![ "a", "b", "c"];

// new Set(["a", "b", "c"])

Java 的明天

Java 是否会支持静态类型?

近期不会!现在开发过程中的静态类型(通过 type 或 Flow)和运行时纯 Java 之间的分离做得比较好。所以没有立即需要进行改变的理由。

为什么我们不能通过去掉比较怪异的行为和和过时的特性来清理 Java?

对于 Web 的一个主要的要求就是永远不要破坏向后兼容性:

对语言设计的思考

作为一个编程语言设计师,无论你做什么,你总会让一些人高兴,让另外一些人不高兴。因此,设计未来的 Java 的主要挑战不是让每个人都高兴,而是尽可能地保持语言的一致性。

然而,人们对于这个所谓的“一致性”的理解也存在着分歧。所以,我们所能做的最好的事情就是建立一个一致的“风格”,由一小群人(最多三个人)来设想和执行。这并不妨碍他们得到其他人的建议和帮助,但他们自己应该确定总体的基调。

以下语句引用自 Fred Brooks:

如果我们做一个简单的回顾,就会发现:虽然很多优秀的、被人们广为使用的软件系统是由各自的技术委员会进行设计,并且作为复杂项目的一个子项目进行的开发,但是那些拥有众多热情粉丝的软件系统却只是一个或几个伟大的设计师的杰作。

这些核心设计师的一个重要职责是对某些功能说“不”,以防止 Java 变得太庞大。

他们本身还需要一个强大的支持系统,因为语言设计师往往会承受各种各样的压力(因为人们确实关心技术本身并且不喜欢听到“不”)。最近的一个例子是 Guido van Rossum 因为承受不了人们的压力而辞去了 Python 首席设计师的职位。

其他想法

我下面的这些想法也许会有助于设计未来的 Java:

原文:http://2ality.com/2019/01/future-js.html

作者简介:Axel Rauschmayer 专注于 Java 和 Web 开发。自 1995 年以来,他一直在开发 Web 应用程序。1999 年,他担任德国互联网初创公司(后来该公司变成跨国公司)的技术经理。2006 年,他首次就 Ajax 发表演讲。2010 年,他获得了慕尼黑大学的信息学博士学位。自 2011 年以来,他一直在 2ality.com 上写博客并撰写了几本关于 Java 的书籍。 他还经常举办有关网站开发的讲座和培训。他本人居住在德国慕尼黑,能说德语、英语、法语和西班牙语。


该文章来源互联网,如有侵权请联系删除

热门推荐

  • 社会图库
  • 幽默搞笑
  • 奇闻异事
  • 美女明星
  • 离奇事件
  • UFO
  • 考古发现
本站内容来自互联网,不提供任何保证,亦不承担任何法律责任.如有侵权请联系删除,QQ:759281825.
COPYRIGHT © 2014-2024 xiaoqiweb.com INC. ALL RIGHTS RESERVED. 版权所有 笑奇网粤ICP备17087216号