内置原子类型
数字
Integer Literals
除了以10为基数的整数字面量之外,JavaScript还可以识别十六进制(以16为基数)的值。以0x或0x开头的十六进制文字,后面跟着一串十六进制数字。16进制数字是数字0到9或字母A(或A)到f(或f)中的一个,表示值10到15。以下是十六进制整数字面量的例子:
0xff // => 255: (15*16 + 15)
0xBADCAFE // => 195939070
在ES6及后续版本中,还可以使用前缀0b和0o(或0b和0o)来表示二进制(以2为基数)或八进制(以8为基数)的整数,而不是0x:
0b10101 // => 21: (1*16 + 0*8 + 1*4 + 0*2 + 1*1)
0o377 // => 255: (3*64 + 7*8 + 7*1)
Floating-Point Literals
表示浮点数的语法:
[digits][.digits][(E|e)[(+|-)]digits]
代码示例:
3.14
2345.6789
.333333333333333333
6.02e23 // 6.02 × 10²³
1.4738223E-32 // 1.4738223 × 10⁻³²
你可以在数字字面值中使用下划线将长字面值分解成更容易阅读的块:
let billion = 1_000_000_000; // Underscore as a thousands separator.
let bytes = 0x89_AB_CD_EF; // As a bytes separator.
let bits = 0b0001_1101_0111; // As a nibble separator.
let fraction = 0.123_456_789; // Works in the fractional part, too.
在2020年初,数字字面值中的下划线还没有作为JavaScript的一部分正式标准化。但是它们处于标准化过程的高级阶段,所有主要浏览器和节点都实现了它们。
算术运算
除了加、减、乘、除、取模这些基本的算术运算符,JavaScript还通过定义为Math对象属性的一组函数和常量支持更复杂的数学运算:
Math.pow(2,53) // => 9007199254740992: 2 to the power 53
Math.round(.6) // => 1.0: round to the nearest integer
Math.ceil(.6) // => 1.0: round up to an integer
Math.floor(.6) // => 0.0: round down to an integer
Math.abs(-5) // => 5: absolute value
Math.max(x,y,z) // Return the largest argument
Math.min(x,y,z) // Return the smallest argument
Math.random() // Pseudo-random number x where 0 <= x < 1.0
Math.PI // π: circumference of a circle / diameter
Math.E // e: The base of the natural logarithm
Math.sqrt(3) // => 3**0.5: the square root of 3
Math.pow(3, 1/3) // => 3**(1/3): the cube root of 3
Math.sin(0) // Trigonometry: also Math.cos, Math.atan, etc.
Math.log(10) // Natural logarithm of 10
Math.log(100)/Math.LN10 // Base 10 logarithm of 100
Math.log(512)/Math.LN2 // Base 2 logarithm of 512
Math.exp(3) // Math.E cubed
ES6在Math对象上定义了更多的函数:
Math.cbrt(27) // => 3: cube root
Math.hypot(3, 4) // => 5: square root of sum of squares of all arguments
Math.log10(100) // => 2: Base-10 logarithm
Math.log2(1024) // => 10: Base-2 logarithm
Math.log1p(x) // Natural log of (1+x); accurate for very small x
Math.expm1(x) // Math.exp(x)-1; the inverse of Math.log1p()
Math.sign(x) // -1, 0, or 1 for arguments <, ==, or > 0
Math.imul(2,3) // => 6: optimized multiplication of 32-bit integers
Math.clz32(0xf) // => 28: number of leading zero bits in a 32-bit integer
Math.trunc(3.9) // => 3: convert to an integer by truncating fractional part
Math.fround(x) // Round to nearest 32-bit float number
Math.sinh(x) // Hyperbolic sine. Also Math.cosh(), Math.tanh()
Math.asinh(x) // Hyperbolic arcsine. Also Math.acosh(), Math.atanh()
非数字的数字值
JavaScript 中的算术在溢出、下溢或除以0的情况下不会引发错误。当数值操作的结果大于最大可表示数(溢出)时,结果是一个特殊的无穷值,即无穷。同样,当一个负数的绝对值大于最大可表示负数的绝对值时,结果是负无穷,负无穷。无穷值的行为与您预期的一样:加、减、乘或除任何值都会产生无穷值(可能符号颠倒)。
当数值操作的结果比最小的可表示数字更接近于零时,就会发生下溢。在本例中,JavaScript返回0。如果下溢发生在负数,JavaScript将返回一个特殊的值,称为“负零”。这个值与普通的0几乎没有区别,JavaScript程序员几乎不需要检测它。
在 JavaScript 中除以0不是错误:它只是返回无穷大或负无穷大。然而,有一个例外:0除以0没有一个定义良好的值,这个操作的结果是一个特殊的非数字值NaN
。如果您试图将无穷除以无穷,取负数的平方根,或使用带有不能转换为数字的非数字操作数的算术操作符,则还会出现NaN
。
JavaScript 预先定义了全局常量 Infinity
和 NaN
来保存正的 Infinity
和非数字值,这些值也可以作为Number对象的属性:
Infinity // A positive number too big to represent
Number.POSITIVE_INFINITY // Same value
1/0 // => Infinity
Number.MAX_VALUE * 2 // => Infinity; overflow
-Infinity // A negative number too big to represent
Number.NEGATIVE_INFINITY // The same value
-1/0 // => -Infinity
-Number.MAX_VALUE * 2 // => -Infinity
NaN // The not-a-number value
Number.NaN // The same value, written another way
0/0 // => NaN
Infinity/Infinity // => NaN
Number.MIN_VALUE/2 // => 0: underflow
-Number.MIN_VALUE/2 // => -0: negative zero
-1/Infinity // -> -0: also negative 0
-0
// The following Number properties are defined in ES6
Number.parseInt() // Same as the global parseInt() function
Number.parseFloat() // Same as the global parseFloat() function
Number.isNaN(x) // Is x the NaN value?
Number.isFinite(x) // Is x a number and finite?
Number.isInteger(x) // Is x an integer?
Number.isSafeInteger(x) // Is x an integer -(2**53) < x < 2**53?
Number.MIN_SAFE_INTEGER // => -(2**53 - 1)
Number.MAX_SAFE_INTEGER // => 2**53 - 1
Number.EPSILON // => 2**-52: smallest difference between numbers
not-a-number 值在 JavaScript 中有一个不同寻常的特性: 它不等于任何其他值,包括它自己,这与Python一致。
这意味着您不能编写x === NaN
来确定变量x的值是否为NaN
。相反,你必须写x != x
或Number.isNaN(x)
。当且仅当x
具有与全局常量NaN
相同的值时,这些表达式将为真。
全局函数isNaN()
类似于Number.isNaN()
。如果它的参数是NaN
,或者该参数是一个不能转换为数字的非数字值,则返回true。相关函数number . isfinite()
如果参数不是NaN
、Infinity
或-Infinity
,则返回true
。全局的isFinite()
函数如果它的参数是一个有限数,或者可以转换为一个有限数,则返回true
。
负零值也有些不寻常。它等于正0(即使使用===
进行比较),这意味着这两个值几乎无法区分,除非用作除数:
let zero = 0; // Regular zero
let negz = -0; // Negative zero
zero === negz // => true: zero and negative zero are equal
1/zero === 1/negz // => false: Infinity and -Infinity are not equal
Date
类
JavaScript定义了一个简单的Date类,用于表示和操作表示日期和时间的数字。JavaScript的日期是对象,但它们也有一个数字表示形式的时间戳,指定了自1970年1月1日以来经过的毫秒数:
let timestamp = Date.now(); // The current time as a timestamp (a number).
let now = new Date(); // The current time as a Date object.
let ms = now.getTime(); // Convert to a millisecond timestamp.
let iso = now.toISOString(); // Convert to a string in standard format.
字符串
字符串在 JavaScript 中是不可变的,这与 C 和 Python 一致。像replace()
和toUpperCase()
这样的方法返回新的字符串:它们不会修改调用它们的字符串。
在ES6及以后的版本中,字符串文字可以用反引号分隔:
let s = `hello world`;
JavaScript使用Unicode字符集的UTF-16编码,JavaScript字符串是无符号的16位值序列。最常用的Unicode字符(来自“基本多语言平面”的字符)具有适合16位的代码点,可以由字符串的一个元素表示。编码点不适合16位的Unicode字符将使用UTF-16规则作为两个16位值的序列(称为“代理对”)进行编码。这意味着一个长度为2的JavaScript字符串(两个16位值)可能只代表一个Unicode字符:
let euro = "€";
let love = "❤";
euro.length // => 1: this character has one 16-bit element
love.length // => 2: UTF-16 encoding of ❤ is "\ud83d\udc99"
JavaScript定义的大多数字符串操作方法操作的是16位值,而不是字符。它们没有特别对待代理对,它们没有对字符串执行规范化,甚至不确保字符串是格式良好的UTF-16。
然而,在ES6中,字符串是可迭代的,如果你使用for/of循环或…操作符,它将迭代字符串的实际字符,而不是16位值。
字符串续行
// A string representing 2 lines written on one line:
'two\nlines'
// A one-line string written on 3 lines:
"one\
long\
line"
// A two-line string written on two lines:
`the newline character at the end of this line
is included literally in this string`
字符串API
let s = "Hello, world"; // Start with some text.
s.length
// Obtaining portions of a string
s.substring(1,4) // => "ell": the 2nd, 3rd, and 4th characters.
s.slice(1,4) // => "ell": same thing
s.slice(-3) // => "rld": last 3 characters
s.split(", ") // => ["Hello", "world"]: split at delimiter string
// Searching a string
s.indexOf("l") // => 2: position of first letter l
s.indexOf("l", 3) // => 3: position of first "l" at or after 3
s.indexOf("zz") // => -1: s does not include the substring "zz"
s.lastIndexOf("l") // => 10: position of last letter l
// Boolean searching functions in ES6 and later
s.startsWith("Hell") // => true: the string starts with these
s.endsWith("!") // => false: s does not end with that
s.includes("or") // => true: s includes substring "or"
// Creating modified versions of a string
s.replace("llo", "ya") // => "Heya, world"
s.toLowerCase() // => "hello, world"
s.toUpperCase() // => "HELLO, WORLD"
s.normalize() // Unicode NFC normalization: ES6
s.normalize("NFD") // NFD normalization. Also "NFKC", "NFKD"
// Inspecting individual (16-bit) characters of a string
s.charAt(0) // => "H": the first character
s.charAt(s.length-1) // => "d": the last character
s.charCodeAt(0) // => 72: 16-bit number at the specified position
s.codePointAt(0) // => 72: ES6, works for codepoints > 16 bits
// String padding functions in ES2017
"x".padStart(3) // => " x": add spaces on the left to a length of 3
"x".padEnd(3) // => "x ": add spaces on the right to a length of 3
"x".padStart(3, "*") // => "**x": add stars on the left to a length of 3
"x".padEnd(3, "-") // => "x--": add dashes on the right to a length of 3
// Space trimming functions. trim() is ES5; others ES2019
" test ".trim() // => "test": remove spaces at start and end
" test ".trimStart() // => "test ": remove spaces on left. Also trimLeft
" test ".trimEnd() // => " test": remove spaces at right. Also trimRight
// Miscellaneous string methods
s.concat("!") // => "Hello, world!": just use + operator instead
"<>".repeat(5) // => "<><><><><>": concatenate n copies. ES6
字符串也可以像只读数组一样处理,你可以使用方括号而不是charAt()
方法从字符串中访问单个字符(16位值):
模板字符串
在ES6及以后的版本中,字符串文字可以用反引号分隔:
let s = `hello world`;
然而,这不仅仅是另一种字符串字面量语法,因为这些模板字面量可以包含任意的JavaScript表达式。反撇号中的字符串字面值的最终值是通过计算包含的任何表达式来计算的,将这些表达式的值转换为字符串,并将这些计算出来的字符串与反撇号中的字面值字符组合起来:
let name = "Bill";
let greeting = `Hello ${ name }.`; // greeting == "Hello Bill."
${ and the matching }
之间的所有内容都被解释为JavaScript表达式。大括号之外的都是普通的字符串文本。括号内的表达式被求值,然后转换为字符串并插入到模板中,替换美元符号、花括号以及它们之间的所有内容。
模板字面量可以包含任意数量的表达式。它可以使用普通字符串可以使用的任何转义字符,并且可以跨任意数量的行,不需要特殊转义。下面的模板文字包含四个JavaScript表达式,一个Unicode转义序列,以及至少四个换行符(表达式值也可以包含换行符):
let errorMessage = `\
\u2718 Test failure at ${filename}:${linenumber}:
${exception.message}
Stack trace:
${exception.stack}
`;
正则匹配
一对斜杠之间的文本构成了正则表达式字面量。对中的第二个斜杠还可以后跟一个或多个字母,它们修改了模式的含义。例如:
/^HTML/; // Match the letters H T M L at the start of a string
/[1-9][0-9]*/; // Match a nonzero digit, followed by any # of digits
/\bjavascript\b/i; // Match "javascript" as a word, case-insensitive
RegExp 对象定义了许多有用的方法,字符串也有接受 RegExp 参数的方法。例如:
let text = "testing: 1, 2, 3"; // Sample text
let pattern = /\d+/g; // Matches all instances of one or more digits
pattern.test(text) // => true: a match exists
text.search(pattern) // => 9: position of first match
text.match(pattern) // => ["1", "2", "3"]: array of all matches
text.replace(pattern, "#") // => "testing: #, #, #"
text.split(/\D+/) // => ["","1","2","3"]: split on nondigits
布尔类型
JavaScript 和 Python 一样,在必要时候,非布尔类型的值可以隐式地转换为布尔值,当然你也可以使用Boolean()
进行显式转换。
undefined
和null
会被转换为false
。- 空字符串会被转换为
false
;非空字符串会被转换为true
。 - 数字正0和负0会被转换为
false
;其他数字会被转换为true
。 NaN
会被转换为false
;Infinity
和-Infinity
会被转换为true
。- 所有 object 类型会被转换为
true
,即使是空的object{}
或[]
。 - 所有函数会被转换为
true
。
以上转换的规则和 Python 几乎都是一样的,除了注意一点,JavaScript 会将空的对象类型 {}
和 []
转换为 true
,而 Python 会将空字典和空列表转换为false
。