原文来自阮一峰的博客
六种数据类型:
undefined
null
通常,数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值,即它们是最基本的数据类型,不能再细分了。
对象则称为合成类型(complex type)的值,因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。
至于 undefined
和 null
,一般将它们看成两个特殊值。
对象是最复杂的数据类型,又可以分成三个子类型:
后面说的对象一般指狭义的对象。
JavaScript 内部,所有数字都是以 64 位浮点数形式储存,即使整数也是如此。所以,1 与 1.0 是相同的,是同一个数。
JavaScript 语言的底层根本没有整数,所有数字都是小数( 64 位浮点数)。容易造成混淆的是,某些运算只有整数才能完成,此时 JavaScript 会自动把 64 位浮点数,转成 32 位整数,然后再进行运算。
根据国际标准 IEEE 754,JavaScript 浮点数的 64 个二进制位,从最左边开始,是这样组成的。
JavaScript 的64位浮点数之中,有一个二进制位是符号位。这意味着,任何一个数都有一个对应的负值,就连 0
也不例外。
JavaScript 内部实际上存在 2 个 0
:一个是 +0
,一个是 -0
,区别就是64位浮点数表示法的符号位不同。
NaN
是 JavaScript 的特殊值,表示「非数字」(Not a Number),主要出现在将字符串解析成数字出错的场合。
Infinity
表示「无穷」,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非 0 数值除以 0 ,得到Infinity。
与数值相关的全局方法:
parseInt()
用于将字符串转为整数parseFloat()
用于将一个字符串转为浮点数isNaN()
用来判断一个值是否为 NaN
isFinite()
返回一个布尔值,表示某个值是否为正常的数值字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。
字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从 0 开始)。
JavaScript 使用 Unicode 字符集。JavaScript 引擎内部,所有字符都用 Unicode 表示。JavaScript 不仅以 Unicode 储存字符,还允许直接在程序中使用 Unicode 码点表示字符,即将字符写成 \uxxxx
的形式,其中 xxxx
代表该字符的 Unicode 码点。
与字符串相关的属性和方法:
length
属性返回字符串的长度btoa()
任意值转为 Base64 编码atob()
Base64 编码转为原来的值对象就是一组「键值对」(key-value)的集合,是一种无序的复合数据集合。
对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。如果键名是数值,会被自动转为字符串。
对象的每一个键名又称为「属性」(property),它的「键值」可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为「方法」,它可以像函数那样调用。
对象采用大括号表示,这导致了一个问题:如果行首是一个大括号,它到底是表达式还是语句?为了避免这种歧义,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。
如果要解释为对象,最好在大括号前加上圆括号。因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。
与对象相关的全局方法和语法糖:
Object.keys()
查看一个对象本身的所有属性in
运算符用于检查对象是否包含某个属性for...in
循环用来遍历一个对象的全部属性with
语句作用是操作同一个对象的多个属性时,提供一些书写的方便JavaScript 中声明函数的方法:
function
命令声明的代码区块,就是一个函数。还有通过 Function
构造函数声明函数,不直观,几乎没人用。
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明。
JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。
JavaScript 引擎将函数名视同变量名,所以采用 function
命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:
ES6 又新增了块级作用域。
对于顶层函数来说,函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。
在函数内部定义的变量,外部无法读取,称为局部变量(local variable)。
与全局作用域一样,函数作用域内部也会产生「变量提升」现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
函数参数不是必需的,JavaScript 允许省略参数。
函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。
如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。
由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。arguments
对象包含了函数运行时的所有参数,arguments[0]
就是第一个参数,arguments[1]
就是第二个参数,以此类推。这个对象只有在函数体内部,才可以使用。
JavaScript 规定,如果 function
关键字出现在行首,一律解释成语句。因此,引擎看到行首是 function
关键字之后,认为这一段都是函数的定义,不应该以圆括号结尾,所以就报错了。
函数定义后立即调用的解决方法,就是不要让 function
出现在行首,让引擎将其理解成一个表达式。最简单的处理,就是将其放在一个圆括号里面。这就叫做「立即调用的函数表达式」(Immediately-Invoked Function Expression),简称 IIFE。
eval
命令接受一个字符串作为参数,并将这个字符串当作语句执行。
eval
的本质是在当前作用域之中,注入代码。由于安全风险和不利于 JavaScript 引擎优化执行速度,一般不推荐使用。
函数的全局属性和方法:
name
属性返回函数名字length
属性返回函数预期传入的参数个数toString()
方法返回一个字符串,内容是函数的源码数组(array)是按次序排列的一组值。每个值的位置都有编号(从 0 开始),整个数组用方括号表示。
数组属于一种特殊的对象。typeof
运算符会返回数组的类型是 object
。
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。
JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串。之所以可以用数值读取,是因为非字符串的键名会被转为字符串。
数组的全局属性和方法:
length
属性,返回数组的成员数量in
运算符,检查某个键名是否存在for...in
循环和数组的遍历阮一峰 JavaScript 教程
阮一峰 ES6 教程