把之前写的笔记整理了一下,重新拾起JS
基本数据类型
JS | Java |
---|---|
number | double |
boolean | boolean |
string | String |
null(Object类型的null引用) | null |
undefined(未定义类型) | null |
Symbol(ES6标准新增类型) | enum |
js中除了Object意外所有类型都是不可变的(immutable):
1、JS中的number和Java中的double一样,都是IEEE754 64位双精度浮点型。JS中所有的数值类型全部都是用双精度浮点型表示,不像其他编程语言拥有丰富的数值类型。和Java中的double一样,JS的number也有对应的包装类Number,所以使用Number构造函数new出来的对象是object类型的:
1 | typeof 1; // number |
和Java中的Double类一样,Number中也定义了64位浮点数的一些常量:
Number常量 | 其他语言中的等价物 | 16进制表示 |
---|---|---|
Number.NaN | double NaN = 0.0d / 0.0; | 0x7FF8000000000000L0x7ff0000000000001L 到 0x7fffffffffffffffL 以及 0xfff0000000000001L 到 0xffffffffffffffffL 的值都是NaN:阶码全1,尾数存在一个或多个1。 |
Number.POSITIVE_INFINITY | double POSITIVE_INFINITY = 1.0d / 0.0; 任意正数除以0都为正无穷 | 0x7FF0000000000000L 符号位为0阶码全1 |
Number.NEGATIVE_INFINITY | double NEGATIVE_INFINITY = -1.0d / 0.0; 任意负数除以0都为负无穷 | 0xFFF0000000000000L 符号位为1阶码全1 |
Number.MAX_VALUE | double MAX_VALUE = 2.2250738585072014e-308; Java中的16进制写法:0x1.fffffffffffffp+1023 (即 | 0x7FEFFFFFFFFFFFFFL |
Number.MIN_VALUE | double MIN_VALUE = 4.9e-324; Java中的16进制科学计数法表示:0x1.0p-1022 (即 | 0x0000000000000001L |
Number.MAX_SAFE_INTEGER | double MAX_SAFE_INTEGER = 9007199254740991; Java中的16进制科学计数法表示:0x1.fffffffffffffp+52 (即 | 0x433FFFFFFFFFFFFF |
Number.MIN_SAFE_INTEGER | double MAX_SAFE_INTEGER = -9007199254740991; Java中的16进制科学计数法表示:-0x1.fffffffffffffp+52 (即 | 0xC33FFFFFFFFFFFFF |
如果对浮点算法不熟悉可参考wikipedia
2、 boolean和Java中的boolean一样,只有两个取值:true和false。 同样地,boolean也有对应的包装类Boolean
1 | typeof true; // boolean |
3、JS中的字符串和Java中的字符串一样都是不可变的:所有对字符串的操作都会返回一个新字符串,原始字符串对象并没有改变。和其他C系列编程语言一样字符串索引都是从0开始。和前面两种基本数据类型一样string也有自己的包装类String。
4、Null和Undefined本质上都是指“空”。它们都只有一个取值:Null只有一个取值null,Undefined也只有一个取值undefined。
但是在JS中null并不等同于undefined。
ES规范中定义:
- null表示Object类型的引用为空(已确定是对象类型的引用);
- undefined表示任意变量未赋值(尚未确定类型的变量);
从代码上比较主要有以下区别:
1 | typeof null // object (因为一些历史原因而不是'null') |
对象类型–Object
JS | Java |
---|---|
Object | Map |
JS中的Object与Java中的Object不同,而与Java中的Map类型类似:
一个 Javascript 对象就是键和值之间的映射,键是字符串类型(也可以是Symbol类型),值可以是任意类型。JS中的Object类型非常符合哈希表的数据结构。
1 | var o = new Object(); |
输出结果:
1 | {name: "C", age: 18} |
还有一种方式构造字面量对象:
1 | var p = { |
JSON数据格式就是从Javascript语言中出来的。
其他内置对象
除了前面介绍的Object以及基本数据类型的包装类型JS还提供了一些其他的内置对象。
下面介绍的对象本质上都是基于JS中的Object,所以和Object一样都是键值对映射。
1 | typeof Math; // object |
1. Math
和绝大多数语言一样,JS也提供了数学计算的API——Math对象,Math对象有常见的数学常量和函数。但是和下面介绍的其他内置对象不同,Math对象不是function对象,也就是说Math不是构造函数,所以你不能使用new Math()
或Math()
的方式来创建Math对象。JS中的Math对象可以看做java中的Math.class。
1 | Math { |
2. Date
和大多数编程语言一样,JS中也有基于计算机纪元(1970年1月1日)的日期类Date。
构造函数如下:
1 | new Date(); |
示例:
1 | var d = new Date(); |
运行结果:
1 | VM546:1 Mon Sep 11 2017 19:42:48 GMT+0800 (中国标准时间) |
3. RegExp
尽管Java也有Pattern和Matcher两个类来提供正则表达式的支持,但相对于JS和Python这类脚本语言,Java的正则用起来相当麻烦。JS中提供的正则很强大,使用也相当便捷。
构造正则的方法:
1 | /pattern/flags |
其中flags用于指定正则表达式匹配的一些选项:
标志位 | 对应的RegExp对象属性 | 解释 |
---|---|---|
g | regexObj.global | 全局匹配,找到所有匹配项,而不是在第一个匹配后停止 |
i | regexObj.ignoreCase | 忽略大小写 |
m | regexObj.multiline | 匹配多行,将^和$作为多行文本的开始于结束。 |
u | regexObj.unicode | 将正则表达式Unicode码点 |
y | regexObj.sticky | 粘性匹配,只从lastIndex属性指定的位置开始匹配(并且不再尝试后续的匹配)。 |
RegExp主要有两个常用方法:
1 | // exec() 对指定字符串进行匹配 |
示例:
1 | var regex = /\d+/; // 一个或以上的数字 |
有关正则表达式的基础内容可以参考这篇文章
4. Array数组
Array数组是一种使用整数作为键同时具有长度属性(length)的常规对象,数组对象还继承了Array.prototype的一些函数用于操作数组对象。
示例:
1 | var arr = [6,7,8]; |
上面例子中的Array数组底层是以这种方式存储的:
1 | 0: 6 |
所以如果出现:
1 | var arr = [6, 7, 8]; |
此时的arr数组底层存储情况如下:
1 | 0: 6 |
push|pop 和 unshift|shift
Array.prototype中提供了很多函数用于操作,比如这两对:unshift|shift 和 push|pop。从这两对函数上看JS中的数组倒有点像双端队列
push/pop示例:
1 | var arr = [6,7,8]; |
unshift/shift示例:
1 | var arr = Array.of(6,7,8); // ES6中定义的另一种创建数组的方式(注意兼容性) |
keys(), values(), entries()
这三个方法和Java中Map类型的三个类似方法功能一样,都是用于遍历Array对象的。这也从另一方面验证了前面所说的:JS中的Array本质上仍然是一个Map。但是需要注意这三个函数都是ES6中新定义的,所以还存在很多兼容性问题。
函数式编程
JS是一门函数式语言,Java8中提供的Stream API功能也是学习了这一类语言。而且ES6开始支持Lambda表达式,这使得JS的功能更强大。但是和Java8中的Stream不同的是:JS中的这些操作都不是惰性的,不会进行优化,也就是说任何一个方法都会立即返回一个新生成的数组。作为解释性的脚本语言,JS也没必要进行优化,毕竟JS设计这些API和Java的Stream目的性不同。
Lambda表达式在JS中被叫做Arrow Functions,可能是因为运算符是“=>”的原因。
这里有篇文章介绍了JS中的Lambda表达式:https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/
如果把JS和Java类比的话,也可以将Array提供的函数划分为以下几类:
Array函数分类 | ||
中间操作(Intermediate operations) | 无状态(Stateless) | filter(), map() |
有状态(Stateful) | sort(), reverse() slice() | |
终断操作(Terminal operations) | 非短路操作 | forEach() reduce(), reduceRight() |
短路操作(short-circuiting) | every(), some() find(), findIndex() |
map()
1 | // 提供一个函数将源Array中的元素按函数定义的规则映射成新的元素,最终返回新元素的数组。 |
filter()
1 | var newArray = arr.filter(function callback(element,index,array){ |
sort()
1 | // sort方法使用的排序算法不一定稳定, |
reverse()
数组逆序。这个很简单,而且也没什么参数。
slice()
1 | // slice用于截取数组的一部分,包含begin位置,不包含end位置 |
forEach()
1 | // forEach用于遍历数组中的元素 |
reduce()与reduceRight()
1 | // 提供一个函数将源Array中的元素按函数定义的规则进行累积。 |
every(),some()
1 | // every函数表示数组中的每个元素都符合callback函数中指定的条件 |
find(),findIndex()
1 | // find函数用于从数组中查找符合callback函数中指定条件的元素 |
5. ArrayBuffer,DataView
如果说JS中的Array是Java中的List(容量可变),那么JS中的ArrayBuffer才是Java中真正的数组(容量不可变)。
随着浏览器技术的发展,JS不再甘心于操作BOM和DOM了,JS标准的制定者把目标定的更远。H5中2D(Canvas)和3D(WebGL)绘图以及音视频的API也呼之欲出,这些API避免不了要直接操作内存,所以ArrayBuffer也随之诞生。
也就是说JS中的ArrayBuffer就是用来申请一段内存的,但是JS不允许我们直接使用ArrayBuffer这段内存,而是把对内存的操作封装成了视图,也就是DataView
。
1 | // 申请16字节的内存 |
DataView类提供了下面16种操作内存的方法,如果把getter/setter看成一个整体,应该算8种。
8种操作分别对应8种数据类型,这倒和标准C中提供的数据支持有点类似。
DataView.prototype.getFloat32()
DataView.prototype.getFloat64()
DataView.prototype.getInt16()
DataView.prototype.getInt32()
DataView.prototype.getInt8()
DataView.prototype.getUint16()
DataView.prototype.getUint32()
DataView.prototype.getUint8()
DataView.prototype.setFloat32()
DataView.prototype.setFloat64()
DataView.prototype.setInt16()
DataView.prototype.setInt32()
DataView.prototype.setInt8()
DataView.prototype.setUint16()
DataView.prototype.setUint32()
DataView.prototype.setUint8()
6. TypedArray
尽管DataView能操作各种数据类型,但是如果我在一段内存中只操作一种数据类型,那DataView就显得有些多余。所以JS还提供了用于操作单一数据类型的视图类 —— TypedArray。TypedArray主要有以下几种类型,它们的在使用上都是一样的。
类 | 单位元素的字节数 | 描述 | Web IDL类型 | C语言等价类型 |
---|---|---|---|---|
Int8Array | 1 | 8位有符号整形 | byte | int8_t |
Uint8Array | 1 | 8位无符号整形 | octet | uint8_t |
Uint8ClampedArray | 1 | 8位无符号整形(clamped) | octet | uint8_t |
Int16Array | 2 | 16位有符号整形 | short | int16_t |
Uint16Array | 2 | 16位无符号整形 | unsigned short | uint16_t |
Int32Array | 4 | 32位有符号整形 | long | int32_t |
Uint32Array | 4 | 32位无符号整形 | unsigned long | uint32_t |
Float32Array | 4 | 32位单精度浮点型 | unrestricted float | float |
Float64Array | 8 | 64位双精度浮点型 | unrestricted double | double |
Mozilla的rhino引擎(Java实现):https://github.com/mozilla/rhino
微软Edge浏览器中的ChakraCore引擎(C++实现):https://github.com/Microsoft/ChakraCore
谷歌Chrome浏览器中的v8引擎(C++实现):https://github.com/v8/v8
参考: