- 主题:现在做WEB的主流技术是哪些
没办法,谁让它非要蹭 java 的热度,连名字都使劲蹭,起点太低了
【 在 RuralHunter 的大作中提到: 】
: 你这个只是更加证明js设计垃圾的观点啊,连抄也不能找个好的抄,抄了个屎。
--
FROM 203.211.108.*
随便一搜就有官方的例子,你在那呵呵是因为你真不懂吗?
https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#d5e14764
【 在 slogan 的大作中提到: 】
: 会有什么问题,你能具体说说吗?呵呵
--
FROM 203.211.108.*
我不得不佩服这个逻辑,有个成语叫指鹿为马,今天我算是见识了啥叫指三为零
【 在 RuralHunter 的大作中提到: 】
: 这个例子根本没有任何问题,只是是在分析构造函数和变量初始化的顺序。
: #发自zSMTH@Fish Boat
--
FROM 203.211.108.*
这个世界除了 java 以外,还有种东西叫常识。
比如 php:
> $a = md5('hello'); print $a == 5 ? 'yes' : 'no';
< yes
因为 md5('hello') 的结果是 '5d41402abc4b2a76b9719d911017c592',而 == 运算符在比较字符串和数字时,会把字符串自动转成数字再进行比较
再比如 js:
> [10, 2, 1].sort()
< [1, 10, 2]
因为 js 里 Array.prototype.sort 默认会把元素按照转换成字符串做比较
系统设计方面有个概念,叫做最小惊讶原则。php、js 很多所谓烂的地方就在于,太让人惊讶了,上面两个就是例子。同理,看到 three = 3 之后,按照常识来说,three 的结果就应该是 3。如果不是的话,按照同样的道理,这个设计就跟 php、js 这俩反常识的设计一样烂。
c/c++ 有很多 undefined behavior,implementation-defined behavior,最经典的 ub 就是同一个表达式里多次自增,比如 ++a + ++a。这些都是非常失败的设计,这也是为啥上世纪90年代的 c-like 语言里,如果支持 ++/-- 表达式的话,都规定了多次出现的计算顺序,比如 java。那么我有个问题,你们公司的 java 代码,会允许 foo = ++i + i++ 这种表达式的存在吗?同理,你在每次使用 this.three 时,都会考虑是不是从 constructor 里面调用目前这个方法的问题吗?不要不承认,这个东西就跟 ub 一样是个坑,完全就是设计烂的表现之一。这就跟 js 为啥要抄 java.util.Date 一样,你一个带 gc 的语言,又不支持多继承,为啥非要抄 c++ 的实现?
【 在 RuralHunter 的大作中提到: 】
: 你这就是强词夺理了,理解了java构造函数和类属性初始化顺序根本不会觉得有什么问题,因为这个顺序完全合乎逻辑没有任何奇怪之处。
: 你是觉得子类的变量初始化应该早于父类构造函数还是觉得父类中调用被重载的方法不应该执行子类的方法?
: #发自zSMTH@Fish Boat
: ...................
--
修改:eGust FROM 203.211.108.*
FROM 203.211.108.*
c++ 支持多继承,所以我觉得需要一个一个初始化还有情可原。本来多继承就已经搞得很复杂了,一口气直接初始化难度太高了。
delphi 里不光 constructor 里可以调用 virtual method,而且连 constructor 本身都可以是虚的。并且在官方 vcl 库里属于标准操作,我记得当年李维的书还专门给起了个名字,叫汉堡包什么的,大概类似这样:
TFoo = class(TComponent)
construcor Create(parent: TComponent); override;
...
end;
constructor TFoo.Create(parent: TComponent)
begin
Self.Foo := 123;
Self.Bar();
inherited Create(parent);
Self.Baz();
end
inherited 相当于 super。delphi 里创建新 object 的时候,在分配好内存后,编译器直接把所有的 vmt(virtual method table)指针都设好,不光是 class 本身,还包括全部的 interface 指针,然后才调用 constructor。现在已经记不清是不是每个 class 其实都是静态数据,只要直接把 pointer[-1] 直接指向 class 这一个操作就完成了。另外,由于有些类型是 auto reference count 和 copy-on-write 的设计,所以对象初始化是有清零操作的。再加上
TFoo = class
private
FBar: Integer;
// ...
end;
是不支持 FBar: Integer = 42 这种语法的,所以压根就不存在类似问题。就算支持我觉得也不是啥问题,哪怕调用 class virtual method 来初始化,无非也就是清零对象、设好指针后,增加一个 method,然后再调用 constructor 而已。顺便一提,delphi 里 class 本身也是 object,所以 class method 也都可以 virtual/override。所以当年在看到号称非常 oo 的 java 居然连这都不支持的时候,我也是非常震惊的。delphi 里
type
TComponentClass = class of TComponent;
var
fooClass: TComponentClass;
fooInsance: TComponent;
begin
fooClass := bar(); // TFoo
fooInstance := fooClass.Create(parent);
这种常规操作跑到 java 里就非得靠 design pattern 才能完成
【 在 DoorWay 的大作中提到: 】
: 这就跟 js 为啥要抄 java.util.Date 一样,你一个带 gc 的语言,又不支持多继承,为啥非要抄 c++ 的实现?
: —— 这里是说java抄cpp吗?
: 基类构造函数里调虚函数,cpp调不到虚的,理由是没完成子类构造。是cpp著名的坑,还专门有个 two-phrase creation的idiom。基类构造内无法访问子类成员。
: ...................
--
修改:eGust FROM 203.184.25.*
FROM 203.184.25.*
一个语言特性能扯到多线程上,这思路也真是开阔到没谁了。java 做不到看到 a = 3,非得指三为零,不意味着别的语言也非得这样。比如 python,完全不存在这个问题。
我已经说了,这个世界上除了 java 以外,还有一种东西叫常识。因为只知道 java,理所当然的认为只有 java 世界里的知识是常识,其它语言只要跟 java 不一样就“奇葩之处多如牛毛”。这个问题纯粹是一个很简单的语言设计的问题,根本没有任何的复杂性。出于某种原因,java 选择直接抄了 c++ 的设计,而同期的其它语言(py、rb、delphi)根本就不存在这种问题。
我并不否认学编程是需要一定智商的,我个人觉得,如果连 js 里 this 这么简单的东西都搞不清楚的话,或者是理解不了 pure function、declarative ui 这些概念的话,智力水平是不太适合干这行的。js 因为历史包袱的原因,的确有很多坑存在,比如前面 sort 的例子,或者是 [...].map(parseInt) 这类东西。但是这些其实都是小问题,因为都是可以通过 linter 来解决的。靠 linter 解决不了的问题,除了 number 是 ieee-754 64位浮点数,而 json 标准又没规定 number 类型的精度这个坑以外,我还真想不出来什么。
顺便说一下,2010年后流行的新语言,除了历史原因需要 class 以外(kotlin、swift),几乎都不再选择 oop 的设计。java 设计的那么完美,为啥新语言都不再抄它了?
【 在 RuralHunter 的大作中提到: 】
: 设计要以最小惊讶原则我同意,可惜这只是理想,不是现实,计算机世界本来就不是直觉世界。我想现实中不存在任何这样一门语言靠常识就足够,要不然学习编程也太简单了。不要说计算机语言,连这样的自然语言都不存在。要论不违反直觉,java恰恰是违反直觉最少的语言之一。反而
: 琷s才是数一数二的违反这一原则的语言,里面奇葩之处多如牛毛,甚至还有人拿这些点专门出了本书。
: 至于什么看到a=3后面a就应该肯定等于3就是乱来了,照你这么说所有多线程的冲突都是违反直觉,或者多线程就不应该存在。这个世界上本来就是有复杂的东西,需要你花一定时间理解,不是你说我不想看到它它就不应该存在了。
: ...................
--
FROM 203.184.25.*
basic 里面 = 既是赋值运算符,又是比较运算符
pascal 里面 := 是赋值运算符,= 是比较运算符
都不是特别冷门的语言,这俩都不知道也敢说“所有的语言”
【 在 huaxinjuedui 的大作中提到: 】
: 要按常识的话,我觉得=号就是判断两边是否相等,然而所有的语言都是赋值(sql除外)
--
FROM 203.184.25.*
我觉得我举 php 和 js 的例子已经说的很清楚了。不管 php 的 md5、还是 js 的 sort,都跟 java 的例子一样,属于 domain-specific knowledge,而不是 common sense。我知道它们为什么是那个样子,不代表我认同它的设计,这件事很难理解么?
js 里面的坑很多,但我从没说过 this 是坑,同样基于 prototype 的 class 设计也再简单不过了,搞不清楚的话真的不适合干这行。
至于你贴的这个列表真的没啥意思,我说了,里面绝大多数问题都是上个 linter 就能解决的。解决不了的包括这种:
NaN === NaN
0.1 + 0.2 === 0.3
对不起这是 ieee 754 的标准实现,属于 common sense,放在你家 java 里也一个结果
比如 eslint airbnb 直接禁掉 bitwise operators,想写 foo | bar 这种表达式默认是通不过 build 的。我简单搜了一下没发现上面的帖子里提到,估计作者如果知道咋回事儿的话又要吃惊了吧。
【 在 RuralHunter 的大作中提到: 】
: 没有人在扯什么java完美,只是你说的根本就没有一个语言能做到,就是吹毛求疵,典
: 型双标。一会说学语言要有点智商,那理解一下构造函数的执行顺序又那么难反直觉反
: 人类了?
: ...................
--
修改:eGust FROM 203.184.25.*
FROM 203.184.25.*
发布在上个世纪的 es3 就已经有 === 运算符了,等于早就承认 == 是个失败的设计。20多年过去了,非要故意写糟糕的代码还怪得了谁
【 在 tgfbeta 的大作中提到: 】
: [] != '0'
: [] != '\t'
: '0' != '\t'
: ...................
--
FROM 203.211.109.*
说实话我是不太理解这是怎么一个心态,你们 java 要是轻到不需要用任何静态分析工具,嘲笑一下倒也没啥问题。偏偏是 ide or die 的 java,一个 idea 比 linter 重了无数倍,不知道是怎么做到心安理得一百步笑五十步的。
千万别误会啊,我可没说静态分析不对不该用,虽然我不爱用 ide 但不代表我不赞同使用。恰恰相反,能利用机器解决问题、而不是依赖人的工具都是好工具。rust 之所以现在这么被人爱,很大一部分原因,就是强大的静态分析能力,避免人一时考虑不周遗漏某些情况。据说 c++ 如果用 clang 的话,可以靠 lifetime annotation 实现几乎全部 rust 的功能,毕竟这俩都是 llvm 的后端。换句话说,虽然 c++ 也是历史问题一堆,当之无愧的最复杂的语言。但如果利用工具,让它一样能焕发新春,写起来跟 rust 一样轻松,那这个工具就是好工具。
【 在 RuralHunter 的大作中提到: 】
: 加个linter就解决。。。这个语言设计得真好
--
修改:eGust FROM 203.211.109.*
FROM 203.211.109.*