JavaScript 数据类型
JavaScript 中有五种可包含值的数据类型:
- 字符串(string)
- 数字(number)
- 布尔(boolean)
- 对象(object)
- 函数(function)
有三种对象类型:
- 对象(Object)
- 日期(Date)
- 数组(Array)
同时有两种不能包含值的数据类型:
-
null
-
undefined
使用 typeof 运算符来确定 JavaScript 变量的数据类型
JavaScript的数据类型分为两类:原始类型(primitive type)和对象类型(objeck type),也可以分为拥有方法的类型和不能拥有方法的类型,同样可以分为可变类型(mutable)和不可变类型(immutable)。JavaScript中的原始类型包括数字、字符串和布尔值
JavaScript中有两个特殊的原始值:null(空)和undefined(未定义),它们不是数字、字符串和布尔值
JavaScript中除了数字、字符串、布尔值、null和undefined之外的就是对象:(object)是属性(property)的集合
1.数字
JavaScript不区分整数型和浮点数值。JavaScript中的所有数字均用浮点数值表示
表示的整数范围(-2的53次方 ~ 2的53次方),包含边界值,超过界值,则无法保证数字精度,JavaScript中实际的操作则是基于32位整数
(1):整型直接量
尽量不使用八进制直接量,部分实现不支持
(2):浮点型直接量
传统写法或者指数计数法表示
(3):JavaScript中的算术运算
Math对象方法 | 结果 |
---|---|
Math.pow(2,53) | =>9007199254740992 2的53次幂 |
Math.round(.6) | =>1.0 四舍五入 |
Math.ceil(.6) | =>1.0 向上求整 |
Math.floor(.6) | =>0.0 向下求整 |
Math.abs(-5) | =>5 绝对值 |
Math.max(x,y,z) | 返回最大值 |
Math.min(x,y,z) | 返回最小值 |
Math.random() | 生成一个大于等于0小于1.0的伪随机数 |
Math.PI | Π:圆周率 |
Math.E | e:自然对数的底数 |
Math.sqrt(3) | 3的平方根 |
Math.pow(3,1/3) | 3的立方根 |
Math.sin(0) | 三角函数:还有Math.cos,Math.atan等 |
Math.log(10) | 10的自然对数 |
Math.log(100)/Math.LN10 | 以10为底100的对数 |
Math.log(512)/Math.LN2 | 以2为底512的对数 |
Math.exp(3) | e的3次幂 |
JavaScript中的算术运算在溢出(overflow)、下溢(underflow)或被零整除时不会报错,当数字运算结果超过了JavaScript所能表示的数字上限(溢出),结果为一个特殊的无穷大(infinity)值。正无穷大和负无穷大产生溢出时都用infinity表示(会保留正负符号)
被0整除在JavaScript中并不报错,它只是简单的返回无穷大(Infinity)或负无穷大(-Infinity),0除以0是没有意义的,这种整除运算结果也是一个非数字(not-a-number)值,用NaN表示。无穷大除以无穷大、给任意负数作开方运算或者算术运算符与不是数字或无法转换为数字的操作数一起使用时都将返回NaN。
JavaScript中预定义了全局变量infinity和NaN,用来表示正无穷大和非数字值。在ECMAScript3中是可读/写的,并可修改。在ECMAScript5中修正了这个错误,将其定义为只读的
JavaScript中的非数字值有一点特殊,它和任何值都不相等,包括自身。
不能通过X==NaN来判断变量x是否是NaN,应当使用x!=x来判断,而且仅当x为NaN时,表达式才为ture,函数isNaN()的作用与此类似
JavaScript中使用实数时,只能表示其中的有限个数,通常只是真实值的一个近似值表示
2.文本
字符串是一组由16位值组成的不可变的有序序列,每个字符通常来自于Unicode字符集。JavaScript通过字符串类型来表示文本
模式匹配(RegExp()构造函数->正则表达式)
3.布尔值
仅有两个值(true和false)
任意JavaScript的值都可以转换为布尔值 下面这些值会被转换成false undefined、null、0、-0、NaN、""(空字符集) 所有其他值都会转换成true
&& 》 逻辑与
|| 》 逻辑或
! 》 逻辑非
4.null和undefined
null常用来描述“空值”,也可以将null认为是一个特殊的对象值,含义是“非对象”。但实际上,通常认为null是它自有类型的唯一一个成员,它可以表示数字、字符串和对象是“无值”的。
undefined通常说明这个属性或元素不存在,如果函数没有返回任何值,则返回undefined。引用没有提供实参的函数形参的值也只会得到undefined。它的值就是“未定义”。在ECMAScript 3 中,undefined是可读/写的变量,在ECMAScript5中改为了是只读的。
null和undefined都表示“值的空缺”,两者往往 可以互换。判断相等运算符“”认为两者是相等的(要使用严格相等运算符“=”来区分它们)。在希望是布尔类型的地方它们的值都是假值,和false类似。null和undefined都不包含任何属性和方法。实际上,使用“.”和“[]”来存取两个值的成员或方法都会产出一个类型错误。
如果想将它们赋值给变量或者属性,或将它们作为参数传入函数,最佳选择是使用null
5.全局对象
全局对象的属性是全局定义的符号,JavaScript程序可以直接使用。
全局属性,比如undefined、Infinity和NaN 全局函数,比如isNaN()、parseInt()和eval() 构造函数,比如Date()、RegExp()、String()、Object()和Array() 全局对象,比如Math和JSON
全局对象的初始属性并不是保留字,但它们应该当做保留字来对待。
在代码的最顶级--不在任何函数类的JavaScript代码--可以使用JavaScript关键字this来引用全局对象;
var global = this; //定义一个引用全局对象的全局变量
Window对象定义了核心全局属性,但它也针对Web浏览器和客户端JavaScript定义了一少部分其他全局属性
6.包装对象
JavaScript对象是一种复合值,它是属性或已命名值的集合。通过“.”符合来引用属性值。当属性值是一个函数的时候,称其为方法。通过o.m()来调用对象o中的方法m。
存取字符串、数字或布尔值的属性时创建的临时对象称做包装对象,它只是偶尔用来区分字符串值和字符串对象、数字和数值对象以及布尔值和布尔对象。
通常,包装对象只是被看做是一种实现细节,而不用特别关注。由于字符串、数字和布尔值的属性都是只读的,并且不能给它们定义新属性,因此你需要明白它们是有别于对象的
JavaScript会在必要时将包装对象转换成原始值
7.不可变的原始值和可变的对象引用
JavaScript中的原始值(undefined、null、布尔值、数字和字符串)与对象(包括数组和函数)有着根本区别。原始值是不可更改的,任何方法都无法更改(或“突变”)一个原始值
原始值的比较是值的比较,只有在它们的值相等时他们才相等。
对象的比较均是引用的比较,当且仅当它们引用同一个基对象时,它们才相等
8.类型转换
JavaScript中将会根据需要进行类型转换;空单元格表示不必要也没有执行转换
值 | 转换为字符串 | 数字 | 布尔值 | 对象 |
---|---|---|---|---|
undefined | "undefined" | NaN | false | throws TypeError |
null | "null" | 0 | false | throws TypeError |
true | "true" | 1 | new Boolean(true) | |
false | "false" | 0 | new Boolean(false) | |
""(空字符串) | 0 | false | new String("") | |
"1.2"(非空,数字) | 1.2 | true | new String("1.2") | |
"one"(非空,非数字) | NaN | true | new String("one") | |
0 | "0" | false | new Number(0) | |
-0 | "0" | false | new Number(-0) | |
NaN | "NaN" | false | new Number(NaN) | |
Infinity | "Infinity" | true | new Number(Infinity) | |
-Infinity | "-Infinity" | true | new Number(-Infinity) | |
1(无穷大,非0) | "1" | true | new Number(1) | |
{}(任意对象) | true | |||
[] (任意数组) | "" | 0 | true | |
[0] (1个数字元素) | "9" | 9 | true | |
['a'] (其他数组) | s使用join()方法 | NaN | true | |
function(){}(任意函数) | NaN | true |
原始值到对象的转换也非常简单,原始值通过调用String()、Number()或Boolean()构造函数,转换为它们各自的包装对象
null和undefined属于意外,当将它们用在期望是一个对象的地方都会造成一个类型错误(TypeError)异常,而不会执行正常的转换
对象到原始值的转换:
8.1转换和相等性:
一个值转换为另一个值并不意味着两个值相等; 比如:如果在期望使用布尔值的地方使用了undefined,它将会转换为false,但并不表明undefined == false。JavaScript运算符和语句期望使用多样化的数据类型,并可以相互转换,if语句将undefined转换为false,但“==”运算符从不试图将其操作数转为布尔值
8.2显示类型转换
显示类型转换就是使用Boolean()、Number()、String()或ObJeck()函数
除了null或undefined之外的任何值都具有toString()方法,这个方法的执行结果通常和String()方法的返回结果一致
如果试图把null或undefined转换为对象,则会抛出(TypeError)类型错误;object()函数在这种情况下则不会抛出异常,仅简单的返回一个新创建的空对象
JavaScript中的某些运算符会做隐式的类型转换,有时用于类型转换
函数 作用 toFixed() 将小数点后的指定位数将数字转换为字符串,从不使用指数记数法 toExponential() 使用指数记数法将数字转换为指数形式的字符串,其中小数点前只有一位,小数点后的位数则由参数指定 toPrecision() 根据指定的有效数字位数将数字转换成字符串 如果通过Number()转换函数传入一个字符串,它将会试图将其转换为一个整数或浮点数直接量,这个方法只能基于十进制数进行转换,并且不能出现非法的尾随字符。
parseInt()只解析整数,并且可以接收第二个可选参数;
parseFloat()既可以解析整数又可以解析浮点数
8.3对象转换为原始值
对象到布尔值的转换: 所有的对象(包括数组和函数)都转换为true。对于包装对象亦是如此 -> new Boolean(false)是一个对象而不是原始值,将转换为true 对象到字符串和对象到数字: 通过调用待转换对象的一个方法来完成,但是JavaScript对象有两个不同的方法来执行转换,这里的字符串和数字的转换规则只适用于本地对象。宿主对象(web浏览器中定义的对象)根据各自的算法可以转换成字符串和数字
对象继承的两个转换方法toString()和valueOf()
toString(): 对象具有这个属性则可以调用此方法,如果返回一个原始值,则将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串的结果; 如果对象没有toString()方法,或者这个方法并不返回一个原始值,那么将会调用valueOf()方法,有toString()方法则会调用toString(),如果返回值是原始值,则转换为字符串 否则,JavaScript无法从toString()或valueOf()获得一个原始值,因此这时将会出现一个类型错误异常 **在对象到数字的转换过程中,JavaScript做了同样的事情,只是它会首先尝试使用valueOf()方法。** valueOf(): 如果对象具有valueOf()方法,后者返回一个原始值,则JavaScript将这个原始值转换为数字(如果需要的话),并返回这个数字; 否则,如果对象具有toString()方法,后者返回一个原始值,则JavaScript将其转换并返回; 否则,JavaScript抛出一个类型错误异常 数组继承了默认的valueOf()方法,这个方法返回一个对象而不是一个原始值。因此数组到数字的转换则调用toString()方法 数组->字符串->数字 注意: 要除去日期对象的特殊情形:任何对象都会首先尝试调用valueOf(),然后调用toString()。不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串
9.变量声明
声明:
var 关键字 [关键字1] [关键字2] ...;
var message = "hello"; var i = 0,j = 0,k = 0;
在for和for/in循环中同样可以使用var语句,以求得代码的简洁化
如果未在var声明语句中给变量指定初始值,那么虽然声明了这个变量,但在给它存入一个值之前,它的初始值就是undefined。
JavaScript变量可以是任意数据变量
重复声明和遗漏的声明: 使用var语句重复声明变量是合法且无害的,如果重复声明带有初始化器,那么这和一条简单的赋值语句没什么区别; 但在试图读取一个没有声明的变量赋值也会报错,在ECMAScript 5中,给一个没有声明的变量赋值也会报错; 在非严格模式下,如果给一个未声明的变量赋值,JavaScript实际上会给全局对象创建一个同名属性,并且它工作 起来像一个正确声明的全局变量 为了避免造成很多bug,因此应当始终使用var来声明变量
10.变量作用域
全局变量
JavaScript全局变量是全局对象的属性,这是在ECMAScript规范中强制规定的,对于局部变量没有此项规定
拥有全局作用域,在JavaScript的任何地方都是有定义的
局部变量
在函数内声明并在函数体内有定义,作用域是局部性的,函数参数也是局部变量,它们只在函数体内有定义
在函数体内,局部变量的优先级高于同名的全局变量,如果在函数内声明的一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所掩盖
在具有块级作用域的编程语言中,在狭小的作用域里让变量声明和使用变量的代码尽可能彼此靠近,由于JavaScript没有块级作用域,因此一些程序员特意将变量声明放在函数体顶部,而不是将声明靠近放在使用变量之处
作为属性的变量
在声明一个JavaScript全局变量时,实际上是定义了全局对象的一个属性。 当使用var声明一个变量时,创建的这个属性是不可配置的,也就是说这个变量无法通过delete运算符删除。
JavaScript可以允许使用this关键字来引用全局对象,却没有方法可以引用局部变量中存放的对象,这种存放局部变量的对象的特有性质,是一种对我们不可见的内部实现。然而,这些局部变量对象存在的观念是非常重要的。
作用域链
这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量,当JavaScript需要查找哦变量x的值的时候(这个过程称为“变量解析”),它会从链中的第一个对象开始查找,如果这个对象有一个名为x的属性,则会直接使用这个属性的值,如果第一个对象依然没有名为x的属性,则会继续查找下一个对象,以此类推。如果实在没有,则会抛出一个错误(ReferenceError)异常。