有的时候真的不知道 js 这些东西是怎么被设计成这样的....

2015-07-26 00:11:36 +08:00
 kamushin

比如obj的key只能是str....我想做个以对象为key的map还要自己调用hash
比如for(i in array)返回的是key的列表,喂,你是把自己当map了吗....for(i of array)才等同于Python里的for i in array...说实话以我的弱渣英语真不懂这里in和of都有啥能让人记住的区别
比如split()居然返回的是自己...靠..你默认\n或者空格都行啊..返回自己是个什么设计...

4355 次点击
所在节点    JavaScript
39 条回复
tushiner
2015-07-26 01:45:09 +08:00
@monnand 把js黑到极点了,笑cry
monnand
2015-07-26 02:20:29 +08:00
@tushiner 黑js的简直都快成一个产业了。比如还有这个: https://www.destroyallsoftware.com/talks/wat
w88975
2015-07-26 02:34:05 +08:00
我还以为是什么呢 黑都没黑到点子上 当初js设计是用来于DOM交互的,说白了 就是用来操作HTML页面的,根本没考虑过现在居然还能用来写后端.
kamushin
2015-07-26 02:51:33 +08:00
@Wangxf 原因是不爽,至于为什么不爽,就好像你学物理的时候感觉数学上的一些知识直接拿来用是可以的,但是学语文的时候数学的知识突然全没用了...
kamushin
2015-07-26 02:53:19 +08:00
@w88975 原来黑还要黑到点子上。不爽还要不爽到别人也不爽的地方?或者你觉得我说的这些其实挺爽的? 这位同学活着有点累吧。
FrankFang128
2015-07-26 02:57:27 +08:00
JS 符合摩尔定律,每过一段时间复杂性翻倍。
YuJianrong
2015-07-26 09:03:57 +08:00
@kamushin 你问第一个有什么解答我说了es6的map了。
我想说的是语言都有其特色,你不能学了其他语言再用C的时候抱怨C没有gc没有map甚至连链表都没有吧?要用什么东西就用那个东西的特色,单纯抱怨真的很没意思。
没有的东西自己创造就行了,都是程序员不是吗?
kamushin
2015-07-26 10:32:37 +08:00
@YuJianrong 恩。我说了是一大半人。另外,我之所以不会吐槽C没有map,是因为C真的没有map。而js有一个map<srting,Any>..也就是一个本来应该是泛型的东西弄了个偏特化出来了..这真的让我觉得有点接受不能,都已经帮忙实现了map了,为什么还要加上这个限制呢(我觉得是限制,而不是功能子集,也就是说实现一个泛型的和实现已经有的这个,代码没啥大区别,但是偏偏就是限制了只能用string)
realpg
2015-07-26 10:48:10 +08:00
我觉得你只是在吐槽js不符合你的python习惯
说实话,一个牛逼的JSer可能也对你提出这俩问题反过来吐槽python是谁设计的
YuJianrong
2015-07-26 11:05:46 +08:00
@kamushin 当你说范型偏特化的时候,已经是在以c++的角度来看待JS了。那是不是我用了es6的map之后,就可以抱怨C++ map的key必须固定类型不能像es6那样动态。你看都实现静态类型的map了,为什么不实现一个运行时动态类型作key和value的map呢?

回到JS,Js里面那个一直没说自己是map,只是object而已,key只是作为property name,对应到C++就是成员名,C++成员名为什么只能是一个symbol呢(连字符串都不是)?你看把它设计成一个map也未尝不可不是吗?

然而这有意思吗……你在学习的是JS而不是C++……
stranbird
2015-07-26 11:14:27 +08:00
1. key是uuid本来就是哈希表算法的基础,hash函数就应该是自己设计的。Java里边你要让一个对象是hashable的,也得写hash函数。

2. 和collection相关的处理统一用lodash或者underscore来处理。_.map(collection, function(value, key) {...} ) 一点问题没有。本来forIn就不在《the good parts》里边。

3. split提供默认值的话,你难道不会骂娘说为什么要默认成这样,我让你默认是逗号了么?在多数场景下反而会提高debug的难度。不指定separator就默认为undefined,字符串里没有undefined就分不开,返回自己有什么问题么。

4. 针对第一个需求,如果真的想优雅实现的话。可以自己将普通的hash封装一个hash类,要加入新的键值对时首先调用键的hash函数求出字符串型的uuid,再存入普通hash中,注意处理碰撞,因为js没有链表,应该只能用闭散列。取的时候也调用键的hash函数算一下,再找。

任何一项特性的引入都会伴随着复杂度的提升。我用python的时候就会觉得,卧槽干嘛简简单单一个字符串要搞这么多编码,卧槽干嘛数据库里边查出来一个数字序列化成json会报错(decimal is not serializable)。这些东西你想想都有道理,因为本来字符串就是bytes+encoding,默认采用utf8或者ascii都犯了过于主观的错误。decimal作为高精度数字类型确实和普通的float/int是不一样的。但是这些人为引入的复杂度对解决问题起到任何帮助了么?想想有多少时间是浪费在处理这种事情上,而不是真正的业务逻辑上了。

比方说泛型,你觉得map<string, Any>是一个特例,那其实根据scala的思想,没有对类型推演的逆变和协变,泛型也是不够完整的,即便是map<any, any>也是不够泛化的。(http://www.tuicool.com/articles/vaAnmq)

关于比较,我就问一声,各位大神什么时候会在自己的程序里边写出这样的代码?有多少时候是因为语言设计的缺陷导致自己调了几天bug的?

我个人的观点是:Javascript有很多傻逼的地方,但是只用到(http://book.douban.com/subject/2994925/)的话,它就已经是一门伟大的语言了。
sodatea
2015-07-26 11:20:02 +08:00
Object 本意并不是用作 hash,它的坑太多了,所以才会在 ES6 中引入 Map。
for in 也是,当初设计太不周到,所以引入 for of (for of 涉及到了 iterator,完全是另起炉灶的感觉,在概念上其实不能与 for in 类比了……)。现在一般用 for k of Object.keys(obj) 而不是 for in 了。

另外同意楼主说的,ES6 之前的 JS 真不好用……
kamushin
2015-07-26 16:26:10 +08:00
@YuJianrong 因为运行时动态类型的map在C++中实现要比实现一个静态类型的难。而Js里,原本的实现我觉得已经可以做到传个对象进去当key了。一个是还要很多的工作,一个是限制和不限制。所以我吐槽的是设计而不是实现。对,他本质是个obj。这是实现。但是设计上,他是个k,v map。

@stranbird > 在多数场景下反而会提高debug的难度。不指定separator就默认为undefined,字符串里没有undefined就分不开,返回自己有什么问题么。
我觉得挺有问题的,字符串里没有undefined应该告诉我不能对字符串找一个叫underfined的字符。
@stranbird 拉链法和链表没有什么卵关系。Scala那段没懂你想表达什么,map<string, V> 本来就是 map<K,V>的一个特例,和你后面说的没什么关系。
stranbird
2015-07-26 17:29:56 +08:00
其实是因为你没有告诉他,它没有义务给你一个它觉得是对的分隔符。

Scala那段是描述对于泛型还可以有泛型,我想表达的是,如果真的要引入泛型可以没有边界,这是一个设计选择,大多数场景下足够好用,你想要的那个需求要实现起来也很容易。

拉链法就是用链表来解决哈希值冲突的情况,在所有有指针的语言里用链表实现,在没有指针的语言里用数组模拟链表实现....

唉,不知道说什么了,对于一些人来说太阳大概是会从东边落下的吧。
YuJianrong
2015-07-26 23:44:00 +08:00
@kamushin 你这个能传对象做 key 也太想当然了吧……首先你觉得用对象做 key 容易?原本人家的对象只需要是个字符串做 key 的 hashmap,所以只要实现字符串有序比较就可以了,现在可好,什么类型都可以了,那你说boolean 的 true和字符串"true" 和 new String("true")要不要是同一个 key?不是的话谁大谁小?然后a[1]和 a["1"] 是不是就要分开了?要考虑的事情一大堆你就一句“原本就可以”啊,什么叫做限制……用 string 做 key 其实就是简单而且也够用而已,那个时候对 JS 没多少需求,有了需求才设计了 map 这东西,然后你可以去看看 Es6的 spec,这 map 根本连个 hashmap 都不是,性能完全不能和 object 比好吧……

说实话我觉得你这种抱着一种语言的观念去学另外语言的习惯非常不好,别的设计有别的设计的理由(虽然有些是失误比如 typeof null),抱着这种先入为主的观念不是一个学习其他语言的好态度。
kamushin
2015-07-27 09:10:25 +08:00
@YuJianrong 我可不觉得是字符串的有序比较。我传个长度为10000的字符串key他还真给我去比较了?我宁可相信内部是hash的。你在说到谁大谁小的时候已经默认是RB树实现的map了。可是我觉得这么应该是hashmap
@stranbird 但是它有义务Fail Fast。 那比map<K,V>更泛型的是? 直接数组实现就行了,何必数组模拟链表。
kamushin
2015-07-27 09:17:31 +08:00
@YuJianrong >那你说boolean 的 true和字符串"true" 和 new String("true")要不要是同一个 key?不是的话谁大谁小?然后a[1]和 a["1"] 是不是就要分开了?
===号返回true的,hash值相同,返回false的,hash值不同(先不去管冲突)。能做到判断===,也就能做到hash。
>说实话我觉得你这种抱着一种语言的观念去学另外语言的习惯非常不好,别的设计有别的设计的理由(虽然有些是失误比如 typeof null),抱着这种先入为主的观念不是一个学习其他语言的好态度。
这段我认同,只是coding的时候不能抱着先入为主的观念。但是在理解设计的时候,你无法不抱着先入为主的观念,不然如何去比较设计的思想呢。
YuJianrong
2015-07-27 11:39:36 +08:00
@kamushin 那同样问题就是怎么设计hash算法了。各种类型都要做hash和互相比较大小没有难度上的区别(都不容易)。
sodatea
2015-07-27 14:21:41 +08:00
@kamushin 今天仔细想了下这个问题,感觉 JS 的这种设计还是有道理的:
1. 非要说的话,object 其实可以用其他类型作为键值,只是在使用前会调用 toString 而已……可以理解为这里将 toString 作为一个最偷懒的 hash 方法来用了。要是有人愿意的话,重写一下 Object.prototype.toString 就能实现「任意类型作键值」的功能了嘛;
2. 考虑到 object literal 的写法,要是允许键值为任意类型,似乎会很脏……现在只允许 string 的话好看很多(可以参考 ES6 computed property names 的写法,真的挺难看的……而且不能用 JSON 表示了)。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/208367

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX