内容简介:数据类型可以说是编程语言的基石,重要性不言而喻。那么现在就从数据类型开始,打破你的思维认知,做一个充满想象力的好像,我这标题起的也太秀了,会不会被打:joy:。这篇可以算是 前端猎奇系列中的
数据类型可以说是编程语言的基石,重要性不言而喻。那么现在就从数据类型开始,打破你的思维认知,做一个充满想象力的 FEE
。针对上篇的一些偏激评论,我想强调的一点是: 我写的文章,并不是给那些偏激到说脏话的人看的,请尊重每一位为前端贡献微薄力量的 Blogger
。
好像,我这标题起的也太秀了,会不会被打:joy:。
多说一句
这篇可以算是 前端猎奇系列中的 探索 Python 来反补 JavaScript 的中篇。 如果没有看过上篇文章的,可以去我的专栏里读读上篇,在知识上没有啥关联的地方,相对独立。基本是我在学习 PY
的时候,学到某一个地方,突然会想到 JS
在这一方面是如何表现的,然后随着思考,真的会有不少收获吧。
关于数据类型
有句话说的好,掌握数据类型是学习一门语言的基础。我们从这句话中可以看出,掌握好数据类型是有多么重要。你曾经是不是有想过 JS
的数据类型为什么会是这样,为什么要有 null
、 undefined
。也许你有过疑问,但是疑问触发后,简简单单的探寻后,就把疑问扔到回调函数里了,这一扔就是到如今。现在我将从 PY
的角度来反补 JS
,通过 PY
去看清 JS
的数据类型,看清编程语言的一些规律。now go!
JS
的数据类型分为值类型和引用类型:
- 值类型有:数字、字符串、布尔、Null、Undefined、Symbol、
- 引用类型有:Array、Function、Set、Map
PY
的数据类型分为数值类型、序列类型、Set类型、字典类型:
JS JS
现在我们看一下 PY
和 JS
的数据类型,这里我不阐述具体是什么,我只是总结一下,当我学习到这的时候,我对JS的数据类型有了什么样新的理解。现在,你会发现几个很有趣的地方,请看如下:
关于 Set 和 Map
这和 PY
的 Set
、 Dictionary
不谋而合,但是 ES6
规范的制定者,没有选择使用 Dictionary
作为键值对的类名称,而选择了使用 Map
作为键值对的类名称。而 Map
正是 Java
的键值对的类名称。所以给我的感觉就是,JS在吸收很多语言的优秀的特性,我个人认为,命名成 Map
要比 Dictionary
好,毕竟少写 7
个字符呢:joy:。
关于 Array 和 List
就这样就结束了吗?No,我们再看上面两种类型,首先注意 PY
的 List
和 JS
的 Array
是相同的,都是可以动态进行修改的。但是很多 FEE
,因为掌握的知识不够宽泛,导致了对很多事情不能理解的很透彻。比如,我们的思维中就是这样一种固定的模式:数组是可以动态修改的,数组就是数组类型。。我个人建议, FEE
一定不能将自己的思维束缚在某个维度里。这真的会阻碍你 开启那种瞬间顿悟的能力。
如果你了解了 PY
或者其他语言,你会发现其实 JS
的数组,其在编程语言里面,只能算是 List
类型,属于序列类型的一种。而且很重要的是, JS
的 Array
是动态的,长度不固定,了解过 Java
的同学应该知道,在 Java
中,数组是分为 Array
和 ArrayList
, Aarry
是长度固定的, ArrayList
是长度可以动态扩展的。所以 JS
的 Array
其实只是编程语言 的 Array
中的一种。如果你知道这些,我觉得这对去深刻理解 JS
的数据类型将有很大的帮助。虽然 JS
对一些知识点进行了简化,但是作为一个合格的计算机工程师,我们不能习惯的接受简化的知识点,一定要去多维度理解和 掌握简化的知识点。了解其背后的世界,也是非常异彩纷呈的。
关于 JS 的 String 和 PY 的 String
你会发现 JS
的 String
是被归类为数值类型,而 PY
的 String
是被归类为序列类型。其实我个人更倾向于把 JS
的 String
归为序列类型,为什么这么说呢,因为 JS
的字符串本身就带有很多属性和方法,既然有方法和属性,也就意味着至少是个对象吧,也就是隐式执行了 new String
。字符串对象可以通过方法和属性来操作自己的字符序列。所以这被归类为数值类型的话,我个人认为是不科学的,而 PY
就分的很清楚。
关于 null 和 undefined
null 和 undefined 的争论就在此结束吧。
可能一开始会对 null
和 undefined
比较陌生,可能会有那么一刻,你怀疑过 JS
的 null
和 undfined
为什么会被单独作为数据类型,但是过了那一刻,你就默许其是一个语言设计规则了。但是我想说的是,语言设计规则也是人设计的,是人设计的就应该多一份怀疑,不必把设计语言的人看成神一样。编程语言那么多,哪有那么多神。网上有很多好文章介绍 JS
的 undefined
和 null
的,也都说了有多坑。想深入理解有多坑的可以自行百度谷歌。我也不重复造解释了,比如, undefined
居然不是保留字,也是够神奇的,看了下博客,有篇解释的很不错,可以瞅瞅 为什么undefined可以被赋值,而null不可以? 。写博客的时候,并不是一味的写自己的东西,有时候别人总结好的东西,在我写博客过程中,也能带给我很多灵感和收获。这也是算是和站在巨人的肩膀上是一个道理吧。
不过我还是有点个人独特的看法的。而且我认为我的看法要比网上绝大多数的见解要更加深刻(不要脸)。我不想说 undefined
有多坑,我只想去探究和理解 undefined
的本质。掌握了本质后,坑不坑也就不重要了。我个人认为, JS
的 undefined
是一种为了处理其他问题而强行做出的一种折中方案,且听我娓娓道来。
既然 PY
和 JS
都是解释性语言,那么为什么 PY
可以不依赖 undefined
,只需要使用 None
就可以了呢? 我写一个简单的例子,可以从我下面的分析中,找到一些更深层的真相,找到设计 undefined
真正的原因。代码如下:
let x console.log(x) 复制代码
# coding=utf-8 print(x) 复制代码
我们来看运行结果:
从图中会发现, JS
没有报错,但是 PY
报错了,究竟是什么原因? 这里中断一下,我们来看下面这个截图,是 java 的一段代码的运行结果:
图中可以看出,在Java中,可以声明变量,但不赋值,然后不去调用此变量,程序是不报错的,但是在PY中,请看下面截图:
我们发现,我们声明了,也没有去调用它,程序还是报错了。是为什么呢?
为什么在 Java
, C++
, C
语言中,可以声明变量,而不用赋值,并且不会报错。而在 PY
中会报错呢,而在 JS
中是 undefined
呢?其实仔细一想,会恍然大悟,一个非常关键的一点就是:
Java
、 C++
, C
是强类型语言,在声明的时候,就已经确定了数据类型。所以就算不去赋值, Java
、 C++
等也会根据声明的数据类型,设置一个默认的数据类型的值。但是这里注意一点,如果整个程序执行完,在只声明,却没有赋值的情况下,去输出或者调用该变量,程序会报错的。为什么会报错呢,是因为此变量的地址是系统随机生成的,并不在此程序内的地址范围内,也就是说此变量的地址可能是指向其他程序的地址,在这种情况下,如果去调用该地址,那么可能会出现很大的危险性,比如你调用了其它很重要的东西。这里我觉得可以把它理解为游离的指针,虽然这样形容不好,但是很形象,游离的指针是很危险的东西。有多危险,哈哈哈,自己体会✧(≖ ◡ ≖✿)。
中断结束,继续 PS
,从上面的叙述知道了 Java
等语言是强类型语言。但是我们知道而 PY
和 JS
是脚本语言,属于弱类型语言,而弱类型语言的特点就是:在声明变量的时候,不需要指定数据类型,这样的好处就是一个变量可以指向万物,缺点是性能差一些,需要让编译器在赋值的时候自己去做判断。请紧跟着我的脚步,我们来看下面这段代码:
let x console.log(x) 复制代码
可以看到, x
是 JS
声明的变量,由于脚本语言是动态的,所以这个变量 x
可以指向万物,那么如果直接使用 x
,而不让其报错的话,该怎么做呢。
一个原则一定不能忘,就是不赋值的话,调用一定会报错,OK,那就赋值,给一个默认值,那么这个默认值用什么来表示呢,指向万物的话,那这类型的可能性有好几种,如果使用 null
来表示的话,由于 null
代表空对象,这里说一个很关键的点,就是,为什么其他语言中比如 Java
, C++
,他们对于空,都是使用 null
来代表一个空对象的?
其实最本质的原因还是因为他们是强类型语言,必须在变量前面声明数据类型,对于值类型,他们系统可以自动给一个默认值。所以在强类型语言中的 null
,其作用只是给引用类型用的。而到了弱类型语言中,比如 PY
, JS
,我们看 PY
,由于 PY
老哥不想使用 undefied
,也只想用一个 null
。那么自然而然的结果就是:直接不允许在未赋值之前,直接调用 声明的变量
,只要调直接提示报错,那么你可能会有疑问了,为什么PY语言中,连只声明变量,不去调用它,程序都会报错呢。其实我个人觉得原因是因为弱类型语言的数据类型不确定导致的,编译器无法去给一个默认值,也就意味着不确定因素增加,既然不确定,那 PY
的做法就是直接使其报错。通过编译器报错来显式让开发者去遵循编码规则。
而小可爱 JS
就不一样了,由于设计者就是不想使其报错,想允许声明,并且可以在未赋值的时候还可以直接调用而不报错。所以也就意味着他要给声明的变量赋一个默认值,怎么赋值呢?这估计也是困扰了设计者良久,下面我举一个很简单易懂的例子,请看下面代码:
let x; let y = [1,2,3] console.log(x, y[3]) 复制代码
从代码可以看出,如果想不报错,有几种可能:
第一种:按照其他语言的规范,只保留一个空值 null
,ok,继续往下推导,由于 JS
是弱类型,变量指向万物,所以肯定只能给所有声明但未赋值的变量设置 null
为默认值了。但是这样的话,问题来了。
看第三行代码,其实 y[3]
也是声明未赋值的 变量
,是不是有点不相信,觉得超出认知了。没事,先继续往下看,既然 y[3]
也是未赋值的 变量
,那把 y[3]
的默认值也设置为 null
吗?很明显,不合理。
因为 y[3]
可能是各种类型,如果直接都设置为 null
。那用户直接打印 y[3]
,然后蹦出来一个 null
,还是 object
类型,岂不要炸?所以到这里,我会慢慢发现,其实 JS
中的 null
和 undefined
是完全不同的两码事,很容易去区分。
综上,我猜一下 JS
作者的脑洞应该是这样的,既然我想让调用声明未赋值的变量不报错,那 ojbk
。不是弱语言么,不是指向万物吗?那要来就来刺激点,我就单独设置一个数据类型,名为 undefined
。专门用来 counter
指向万物的声明却未赋值的变量。哈哈哈哈,是不是很刺激:joy:。
解决最后一公里的疑惑
看下面代码
let x let y = [1,2,3] console.log(x, y[3]) 复制代码
你会发现 x
和 y[3]
都是 undefined
。我们来透过现象看本质,本质上就是声明了,但是未赋值。为什么可以这么说,难道 y[3]
,也是声明了,但未赋值吗?我可以明确告诉你,是的,没毛病。你可能不相信我说的话,下面我在白板上画一个图就顿悟了。。请看图:
图中可以看到,其实数组的每一个下标也是在栈里进行声明的。和用 let x
进行声明的操作是一样的。 let x
的声明如下图:
所以是不是发现其实 undefined
也就那么回事吧。一般来说,如果某一个知识点越绕人,那我们就应该从更底层的角度去看清这个知识点。只要你真的是从一个更加深刻和底层的角度去看待 undefined
,其实 just so so 啦。对了, null
我也顺带解释了,只不过没有重点关注,但是整篇下来,其实 null
是什么,也差不多一清二楚了。总之 null
和 undefined
就是完全不同的两码事。
总结
从 JS
和 PY
的数据类型,我们可以看出, PY
在设计数据类型的时候,明显考虑的很多,或者说,PY语言在被创造的时候,其数据类型的设计是比较规范的。而我们去看 JS
,会发现,有很多坑,感觉是当初为了简化知识点难度,而留下了很多坑。虽然我没有经历过 IE
时代的前端,但现在也能深刻体会到前端工程师的不容易。以前还有同行说前端很简单啊,现在也有,我都遇到过好几次这种人了:
我:我是前端开发。
人家:噢,我知道了,就是写网页的对吧。。。
我心里os:对你个锤子。。
FEE
们都是从坑里一步步爬上来的,真的不容易。总之,现在的前端正在一步步走上规范,走上体面。。。
文末彩蛋一,动态参数
PY
中如何处理动态参数的呢,其实 PY
是通过元组或者字典来处理动态参数的,代码如下,这里只写使用 元组 实现动态参数的代码
# coding=utf-8 def add(x, *tupleName): print(x, tupleName) add('hello', 'godkun', '大王叫我来巡山') 复制代码
执行结果图如下:
我们再看 JS
是如何实现的
function fun(a, ...tupleName) { console.log(a, tupleName) } fun('hello', 'godkun', '大王叫我来巡山') 复制代码
执行结果图如下:
看上面两种方式,看完你应该就明白了, ES6
增加展开符的原因是什么,以及为什么要设计成这个样子。使用 ...
作为标记。同时为什么要将所有可变参数放在一个数组里面。
其实语言都是有相同性的,尤其对于 JS
语言来说,采纳了很多语言的优点,这对于我们前端来说,是一个很大的优势,如果平时善于去这样比较和反补,我个人觉得, FEE
去承担其他开发岗位,也是完全能 Hold
住的。
番外二,深夜写博客时的意外惊喜(意不意外,刺不刺激)
当我写下这段代码:
function a(a, b, c) { console.log(arguments); console.log({ 0: "1", 1: "2" }); console.log([1, 2, 3]); } a(1, 2, 3); 复制代码
第一种情况:我在 node.js
环境运行:结果如图所示:
第二种情况:我在 chrome
浏览器下执行这段代码,结果如图所示:
第三种情况:我在 IE
浏览器下执行这段代码,结果如图所示:
上面这个,你会发现在 chrome
浏览器下,输出的结果形式为:
Arguments(3) [1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ] 0: 1 1: 2 2: 3 callee: ƒ a(a,b,c) length: 3 Symbol(Symbol.iterator): ƒ values() __proto__: Object 复制代码
我靠,什么鬼。居然把 arguments
写成了数组的形式:
[1, 2, 3, callee: ƒ, Symbol(Symbol.iterator): ƒ]
但是 __proto__
还是 Object
。吓的我赶紧试了下面这段代码,代码如图所示:
靠,还果真返回了长度。。。但是为什么 __proto__
是 Object
。。。。
不行,我又看了IE浏览器和 node.js
环境下的结果,都是相同的结果,使用 {}
表示类对象数组
{0: 1, 1: 2, 2: 3, callee: function a(a,b,c){}, length: 3} 复制代码
我陷入了沉思。。。。
不知道是 chrome
开发者故意这样设计的,还是写错了。。小老弟,你怎么回事? chrome
会弄错? 本着上帝也不是万能的理念,我打开了我的脑洞。
chrome
浏览器既然不按照 {}
这种写法,直接将 arguments
写成 []
,使其直接支持数组操作,同时,其原型又继续是对象原型。仔细看会发现又加了一行
Symbol(Symbol.iterator): ƒ values()
。
这样做的目的是什么,为什么要这样设计?搜了 blog
,然而没搜到。。。这一连串的疑问,让我再次陷入了沉思。。。
思考了一会,动笔画了画,发现好像可以找到理由解释了。我觉得可以这么解释:
chrome
想让类数组对象这种不三不四的东西从谷歌浏览器中消失。所以下面这种输出结果
{0: 1, 1: 2, 2: 3, callee: function a(a,b,c){}, length: 3} 复制代码
就一去不复返了,那么如果不这样写,用什么方法去替代它呢。答案就是写一个原型链继承为对象类型的数组,同时给继承对象类型的数组(其还是对象,不是数组) 增加 Symbol.iterator
属性,使其可以 for of
。
为什么要这样做呢,因为一些内置类型自带迭代器行为,比如 String
、 Array
、 Set
、 Map
,但是 Object
是不带迭代器的,也就意味着我们可以推断出,如果从 chrome
浏览器的那种写法的表面上分析,假定 arguments
是 Array
,那么就完全没必要增加 Symbol.iterator
,所以矛盾,所以可以得出, arguments
还是对象,而对象是不带迭代器的。所以要给形式为 []
的 arguments
增加 Symbol.iterator
。使其具有迭代器功能。从而可以使用 for of
。从而完成了 [1,2,3]
到 {'0':1, '1':2, '2':3}
的转变
所以:上述答案被证明为正确。
当然,也可能是:
有理有据的胡诌。。。
备注:
- 我是根据学习PY来去思考JS的数据类型的,对于比如JS的Symbol,Set,Map,没有去说官方用法,我觉得没有必要吧。
- 我说的一些都是我个人出于一个心流状态下的一些思考。可能有点问题,但是都是吾之所感。
文末的可爱声明:如果转发或者引用,请贴上原文链接,尊重一下劳动成果:joy:。文章可能 (肯定) 有一些错误,欢迎评论指出,也欢迎一起讨论。文章可能写的不够好,还请多多包涵。人生苦短,我学前端,多一点贡献,多一分开心,欢迎关注,后续更加精彩哦~
小伙伴觉得我写得还不错的话,就点个赞 以兹鼓励 一下吧:blush:。
以上所述就是小编给大家介绍的《探索Python来反补JavaScript,带你 Cross Fire —— JS 数据类型的奥秘》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Base-x 编码的奥秘
- 蜻蜓点水说说Redis的String的奥秘
- 神经网络的奥秘之优化器的妙用
- 一文读懂网络界新贵Segment Routing技术化繁为简的奥秘
- 耗时2.5GPU年训练12800个模型,谷歌研究人员揭示非耦合表示的奥秘
- airflow探索篇
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Four
Scott Galloway / Portfolio / 2017-10-3 / USD 28.00
NEW YORK TIMES BESTSELLER USA TODAY BESTSELLER Amazon, Apple, Facebook, and Google are the four most influential companies on the planet. Just about everyone thinks they know how they got there.......一起来看看 《The Four》 这本书的介绍吧!