Javascript的数据类型分为两类:原始类型(primitive type)和对象类型(object type).原始类型,包括数字、字符串、布尔值、空(null)、未定义(undifined)。对象类型,是属性的集合,每个属性都由"名/值对"构成。数组和函数,是JavaScript特殊的对象,除此之外,它还定义了三种:日期类、正则表达式和错误类。
JavaScript的类型也可以分为可以拥有方法的类型和不能拥有方法的类型,同样也可以分为可变(mutable)类型和不可变(immutable)类型。
JavaScript解释器有自己的内存管理机制,可以自动对内存进行垃圾回收(garbage collection)。这意味着程序可以按需创建对象,程序员则不必担心这些对象的销毁和内存回收。当不再有任何引用指向一个对象,解释器就会知道这个对象没用了,然后自动回收它所占用的内存资源。
JavaScript变量是无类型的(untype),变量可以赋予任何类型的值,同样一个变量也可以重新赋予不同类型的值。使用var关键字来声明变量。
JavaScript采用词法作用域(lexical scoping)来区分变量的作用域。不在任何函数内声明的变量称作全局变量(global variable),它在JavaScript程序中的任何地方都是可见的。在函数内声明的变量具有函数作用域(function scoping),并且只在函数内可见。
3.1、数字
JavaScript不区分整数值和浮点数值,所有数字均用浮点数值表示,采用IEEE 754标准定义的64位浮点格式表示数字。在实际操作中,数组则是基于32位整数。
3.1.1、整数直接值
十进制:直接使用0-9组成的数字序列;
十六进制:以"0x"或"0X"为前缀,其后跟随十六进制数串;
八进制:以"0"前缀,其后跟随一个由0-7之间的数字组成的序列。
3.1.2、浮点型直接量
浮点型直接值可以包含有小数,它采用传统的实数写法。一个实数由整数部分、小数点和小数部分组成。
此外,还可以使用指数计数法表示。
3.1.3、算术运算
A、基本运算符:加(+),减(-),乘(*),除(/),求余(%)
B、Math对象定义的函数和常量
Month.pow(2,53) //2的53次幂
Math.round(.6) //=>1:四舍五入
Math.ceil(.6) //=>1:向上取整
Math.floor(.6) //=>0.00:向下求整
Math.abs(-5) //=>5:绝对值
Math.max(x,y,z) //返回最大值
Math.min(x,y,z) //返回最小值
Math.random() //生成一个大于0小于1.0的为随机数
Math.PI //圆周率
Math.E //自然对数的底值
Math.sqrt(3) //3的平方根
Math.pow(3,1/3) //3的立方根
Math.sin(0) //三角函数,还有Math.cos,Math.tan等
Math.log(10) //10的自然对数
Math.log(100)/Math.LN10 //以10为底100的对数
Math.log(512)/Math.LN2 //以2为底512的对数
Math.exp(3) //e的三次幂
C、JavaScript中的算术运算在溢出、下溢或被零整除时不会报错。
溢出:正数,结果为一个特殊的无穷大(Infinity)值;负数,为-Infinity表示。
下溢:返回0。
被零整除:返回无穷大(Infinity)或负无穷大(-Infinity)。零除于零,用NaN(非数字值)表示。
无穷大除于无穷大、负数开方运算、不是数字或无法转换为数字的操作数做运算,都返回NaN。
isNaN():判断是否非数字值,在参数为非数字值时返回true。
isFinity():在参数不是NaN、Infinity或_Infinity的时候返回true。
3.1.4、二进制浮点数和四舍五入错误
JavaScript通过浮点数的形式只能表示有限的个数数值,在使用实数的时候,只是真实值的一个近似表示,因此JavaScript比较实数相等没有任何意义。
3.1.5、日期和时间
var then=new Date(2011,0,1); //2011年1月1日
var later=new Date(2011,0,1,17,10,30); //2011年1月1日 17:10:30
var now=new Date(); //当前时间
var elpsed=now-then; //日期减法,计算时间间隔的毫秒数
later.getFullYear() //=>2011
later.getMonth() //=>0:从0开始计数的月数
latger.getDate() //=>1:从1开始计数的天数
later.getDay() //=>5:得到星期几,0代表星期日,5代表星期五
later.getHours() //=>17
later.getUTCHours() //使用UTC表示小时的时间,基于时区
3.2、文本
JavaScript采用UTF-16编码的Unicode字符集,JavaScript字符串是由一组无符号的16位值组成的序列。最常用的Unicode字符都是通过16位的内码表示,并代表字符串中的单个字符,那些不能表示为16位的Unicode字符则遵守UTF-16编码规则--用两个16位值组成的一个序列表示。
3.2.1、字符串直接值
在JavaScript程序中的字符串直接值,是由单引号或双引号括起来的字符序列。
在客户端JavaScript程序设计中,JavaScript代码会夹杂HTML代码的字符串,HTML也会夹杂JavaScript代码,最好在JavaScipt和HTML代码各自使用独立的引号风格。例如,在JavaScript表达式中使用单引号表示字符串,而在HTML事件处理程序属性中则使用双引号表示字符串。
3.2.2、转义字符
转义字符 含义
\0 null字符(\u0000)
\b 退格符(\u0008)
\t 水平制表符(\u0009)
\n 换行符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)
\" 双引号(\u0022)
\' 撇号或单引号(\u0027)
\\ 反斜线(\u005C)
\xXX 由两位十六进制数XX指定的Latin-1字符
\uXXXX 由4位十六进制数XXXX指定的Unicode字符
3.2.3、字符串的使用
A、字符串连接 用加号(+)进行处理
B、字符长度 length
C、实例
var s="hello,world"; //定义一个字符串
s.charAt(0) //=>"h":第一个字符
s.charAt(s.length-1) //=>"d":最后一个字符
s.substring(1,4) //=>"ell":第2~4个字符
s.slice(1,4) //=>"ell":第2~4个字符
s.slice(-3) //=>"rld":最后三个字符
s.indexof("l") //=>2:字符l首次出现的位置
s.lastIndexof("l") //=>10:字符l最后出现的位置
s.indexof("l",3) //=>3:在位置3及以后首次出现字符l的位置
s.split(",") //=>["hello","world"]分割成字串数组
s.replace("h","H") //=>"Hello,world":全文字符替换
s.toUppercase() //=>"HELLO,WORLD"
3.2.4模式匹配
JavaScript定义了RegExp()构造函数,用来创建表示文本匹配模式的对象。这些模式称为”正则表达式“(regular expression),JavaScript采用Perl中的正则表达式语法。
var text="testing:1,2,3"; //文本示例
var pattern=/\d+/g; //匹配所有包含一个或多个数字的实例
text.test(pattern) //=>true:匹配成功返回
text.search(pattern) //=>9:首次匹配成功的位置
text.match(pattern) //=>["1",:2",:3"]:所有匹配组成的数组
text.replace(pattern,"#"); //=>"testing,#,#,#"
text.split(/\D+/); //=>["","1","2","3"]:用非数字字符截取字符串
3.3、布尔值
布尔值指代真或假,开或关、是或否。这个类型只有两个值,保留字true和false。
JavaScript程序中的比较语句的结果通常都是布尔值。
3.4、null和undefined
3.5、全局对象
A、全局对象(global object)在JavaScript中有着重要的用途:全局对象的属性是全局定义的符号,JavaScript程序可以直接使用。当JavaScript解释器启动时(或者任何Web浏览器加载新页面的时候),它将创建一个新的全局对象,并给它一组定义的初始属性:
.全局属性,比如undefined、Infinity和Nan
.全局函数,比如isNaN()、parseInt()(见3.8.2)和eval()(见4.12)
.构造函数,比如Date()、RegExp()、String()、Object()和Array(见3.8.2)
.全局对象,比如Math和JSON(见6.9节)
B、全局对象的初始属性并不是保留字,但它们应该当做保留字来对待。
C、在代码的最顶级------不存在任何函数内的JavaScript代码------可以使用JavaScript关键字this来引用全局对象:
var global=this; //定义一个引用全局对象的全局变量
D、在客户端JavaScript中,在其表示的浏览器窗口中的所有JavaScript代码中,Window对象充当了全局对象。这个全局Window对象有一个属性window引用其自身,它可可以代替this来引用全局对象。Window对象定义了核心全局属性,但它也针对Web浏览器和客户端JavaScript定义了一少部分其他全局属性。
E、当初次创建的时候,全局对象定义了JavaScript中所有的预定义全局值。这个特殊对象同样包含了位程序定义的全局值。如果代码声明了一个全局变量,这个全局变量就是全局对象的一个属性。
3.6、包装对象
A、方法
JavaScript对象是一种复合值:它是属性或已命名值的集合。通过”.“符号来引用属性值。当属性值是一个函数的时候,称其为方法,通过o.m()来调用对象o中的方法。
B、原始类型直接值的临时对象
只要引用了字符串的属性,JavaScript就会将字符串值通过调用new String(s)的方式转化成对象,这个对象继承了字符串的方法,并被用来处理属性的引用。一旦属性引用结束,这个新创建的对象就会销毁(其实在实现上并不一定创建或销毁这个临时对象,然而整个过程看起来是这样)。
同样,数字和布尔值也具有各自的方法:通过Number()和Boolean()构造函数创建一个临时对象,这些方法的调用均是来自于这个临时对象。
null和undefined没有包装对象,访问它们的属性会造成一个类型错误。
C、包装对象
存取字符串、数字或布尔值的属性时创建的临时对象称作包装对象,它只是偶尔用来区分字符串值和字符串对象、数字和数值对象以及布尔值和布尔对象。通常,包装对象只是被看做是一种实现细节,而不是特别关注。由于字符串、数字、布尔值的属性都是只读的,并且不能给它们定义新属性,因此需要明白它们是有别于对象的。
可以通过String()、Number()、Boolean()构造函数来显示创建包装对象:
var s="test",n=1,b=true; //定义一个字符串、数字和布尔值
var S=new String(s); //定义一个字符串对象
var N=new Number(n); //定义一个数值对象
var B=new Boolean(b); //定义一个布尔对象
JavaScript会在必要时将包装对象转换成原始值,因此上段代码中的对象S、N和B常常------但不总是---------表现的和值s、n和b一样。”==“等于运算符将原始值和其包装对象是为相等,但”===“全等运算符将它们视为不等,通过typeof运算符可以看到原始值和其包装对象的不同。
3.7、不可变的原始值和可变的对象引用
A、原始值是不可更改的:任何方法都无法更改(或突变)一个原始值。
对数字和布尔值来说,显然改变数字的值本身就说不通,而对字符串来说就不那么明显了,因为字符串看起来就像由字符组成的数组,但JavaScript禁止通过指定索引来修改字符串中的字符。字符串所有的方法看上去返回一个修改后的字符串,实际上返回的是一个新的字符串值。
原始值的比较是值的比较:只有它们的值相等时它们才相等。
B、对象是可变的,它们的值是可以修改的。
对象的比较并不是值的比较:即使两个对象包含同样的属性及相同的值,它们也是不等的。各个索引元素完全相等的两个数组也不相等。
我们通常将对象称为引用类型(reference type),以此来和JavaScript的基本类型区分开来。对象的比较均是引用的比较:当且仅当它们引用同一个基对象时,它们才相等。
C、复制 深度复制 比较
得到一个对象或数组的副本,必须显示式复制对象的每一个属性或数组的每一个元素。
比较,另建立一个函数给予处理。
3.8、类型转换
值 | 字符串 | 数字 | 布尔值 | 对象 |
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无穷大,非零 | "1" | true | new Number(1) | |
{}任意对象 | 参见3.8.3节 | 参见3.8.3节 | true | |
[]任意数组 | ”“ | 0 | true | |
[9]一个数字元素 | "9" | 9 | true | |
['a']其他数组 | 使用join()方法 | NaN | true | |
function(){}任意函数 | 参见3.8.3节 | NaN | true |
3.8.1、转换和相等
由于JavaScript可以做灵活的类型转换,因此其"=="相等运算符也随相等的含义灵活多变。
注:一个值转换为另一个值并不意味着两个值相等。
3.8.2、显示类型转换
A、String()、Number()、Boolean()不通过呢为运算符调用时,它们会作为类型转换函数并按照规则做类型转换。
B、除了null和undefined之外的任何值都具有toString方法,这个方法的执行结果通常和String()方法的返回结果一致。
C、某些运算符会做隐式转换,有时用于类型转换。
x+"" //等价于String(x)
+x //等价于Number(x),也可以写成x-0
!!x //等价于Boolean(x).注意是双叹号
D、数字转字符串
toString()
var n=17;
binary_string=n.toString(2); //转换为二进制字符串,转换为"10001"
octal_string=n.toString(8); //装换为八进制字符串,转换为"021"
hex_string=n.toString(16); //转换为十六进制字符串,转换为"0x11"
toFixed()根据小数点后的指定位数将数字转换为字符串,它从不使用指数计数法
toExponential()使用指数计数法将数字转换为字符串
toPercision()根据指定的有效数字位数将数字转换成字符串,如果有效数字的位数少于数字整数部分的位数,则转换成指数形式。
这三个方法都会适当地进行四舍五入或填充0.
var n=123456.789;
n.toFixed(0); //"123457"
n.toFixed(2); //"123456.79
n.toFixed(5); //"123456.78900"
n.toExponential(1); //"1.2e+5"
n.toExponential(3); //"1.23e+5"
n.toPrecision(4); //"1.235e+5"
n.toPrecision(7); //"123456.8"
n.toPrecision(10); //"123456.7890"
E、字符转数字
Number()转换函数传入一个字符串,他试图将其转换为一个整数或浮点数直接量,这个方法只能基于十进制数进行转换,并且不能出现非法的尾随字符。
parseInt()只解析整数,parseFloat()则可以解析整数和浮点数。
parseInt("3 bind mice") //=>3
parseFloat("3.14 meters") //=>3.14
parseInt("-12.34") //=>-12
parseInt("oxFF") //=>255
parseInt("-oxff") //=>-255
parseFloat(".1") //=>0.1
parseInt("0.1") //=>0
parseInt(".1") //=>NaN:整数不能以"."开始
parseFloat("$72.47") //=>NaN:数字不能以"$"开始
parseInt()可以接收第二个参数,这个参数指定数字转换的基数,合法的取值范围是2~36,例如
parseInt("11",2); //=>3(1*2+1):二进制的"11"转换成十进制的整数
parseInt("ff",16); //=>255(15*16+15):十六进制的"ff"转换成十进制的整数
parseInt("zz",36);//=>1295
parseInt("077",8);//=>63
parseInt("077",10);//=>77
3.8.3、对象转原始值
A、所有对象转布尔值,都转换成true。
B、对象到符串和对象到数字的转换是通过调用待转换对象的一个方法来完成。
C、toString()方法
对象的toString()。 ({x:1,y:2}).toString() //=>"[object object]"
数组的toString(),将每个数组元素转换为一个字符串,并在元素之间添加逗号后合并成结果字符串。
函数类的toString方法返回这个函数的实现定义的表示字符串。
日期类定义的toString()方法返回了一个可读的日期和时间字符串。
RegExp类定义的toString()方法将RegExp对象转换为表示正则表达式直接量的字符串:
[1,2,3].toString() //=>"1,2,3"
(function(x) { f(x)}).toString() //=>"function(x) {\n f(x);\n}"
/\d+/g.toString() //=>"/\\d+/g"
new Date(2010,0,1).toString() //Fri Jan 01 2010 00:00:00 GMT-0800(PST)"
D、valueof()
这个方法的任务并未详细定义:如果存在任意原始值,它就默认将对象转换为表示它的原始值。对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueof()方法简单返回对象本身,而不是返回一个原始值。
数组、函数和正则表达式简单继承了这个默认方法,调用这些类型的实例的valueof()方法只是简单返回对象本身。
日期类定义的valueof()方法返回它的一个内部表示:时间戳,1970年1月1日以来的毫秒数。
var d=new Date(2010,0,1);
d.valueof() //=>1262332800000
E、对象到字符串的转换步骤:
第一种情况,如果对象具有toString()方法,则调用这个方法。如果它返回一个原始值,JavaScript将这个值转换为字符串(如果它本身不是字符串的话),并返回这个字符串。
第二种情况,如果对象没有toString()方法,或者这个方法并不能返回一个原始值,那么JavaScript会调用valueof()方法。如果存在这个方法,则JavaScript会调用它。如果它返回一个原始值,JavaScript将这个值转换为字符串(如果它本身不是字符串的话),并返回这个字符串。
第三种情况,对象无法从toString()或valueof()获得一个原始值,因此这时它将抛出一个类型错误异常。
F、对象数字的装换步骤:
如果对象具有valueof()方法,则调用这个方法。如果它返回一个原始值,JavaScript将这个值转换为数字(如果它本身不是数字的话),并返回这个数字。
否则,如果具有toString()方法,,则调用这个方法。如果它返回一个原始值,JavaScript将这个值转换为数字(如果它本身不是数字的话),并返回这个数字。
否则,JavaScript抛出一个类型错误异常。
G、运算符转换
3.9、变量声明
在JavaScript中,使用变量之前应当先声明。变量是使用关键字var来声明的,如下所示:
var i; //声明一个变量 i
var sum; //声明一个变量sum
var i,sum; //声明两个变量
var message="hello"; //声明一个变量并赋予初始值
var i=0,j=0,k=0; //声明三个变量并分别赋予初始值
for(var i=0;i<10;i++) console.log(i); //for循环声明一个变量
for(var i=0,j=10;i<10;i++,j--) console.log(i*j);//for循环声明两个变量
for(var p in o) console.log(p); //for循环声明一个对象
A、JavaScript通过值来确定类型,因此一个变量可以先后赋予不同类型的值。
B、重复的声明是合法且无害的。
C、如果试图读取一个没有声明的变量,JavaScript会报错。
3.10、变量作用域
A、全局变量。
B、局部变量(函数参数,函数内的变量,都是局部变量)
C、同名的全局变量和局部变量
D、变量的声明,全局变量不需要声明,局部变量必须声明。
E、函数嵌套的变量作用域
3.10.1 函数作用域和声明提前
A、JavaScript没有块级作用域,使用函数作用域。变量在声明它们的函数体以及这个函数体嵌套内都是有定义的。
function test(o){
var i=0;
if (typeof o=="object"){
var j=0;
for(var k=0;k<10;k++){
console.log(k);
}
console.log(k);
}
console.log(j);
}
JavaScript的函数作用域是指在函数内声明的所有变量在函数体内始终是可见的。
B、将函数内变量的声明”提前“至函数体顶部,同时变量初始值留在原来的位置。
C、真实的反映变量的作用域。将变量声明放在函数体顶部,而不是声明靠近放在使用变量之处。
3.10.2、作为属性的变量
3.10.3、作用域链