在编程语言中,能够表示并操作的值的类型称作数据类型(type),编程语言最基本的特性就是能够支持多种数据类型。
当程序需要将值保存起来以备将来使用,便将其赋值给一个变量。
JavaScript的数据类型分为两类:原始类型和对象类型
JavaScript中有两个特殊的原始值:null和undefined只有两个无法拥有方法
JavaScript变量是无类型的,变量可以被赋予任何类型的值,同样一个变量可以重新赋予不同类型的值。
整形直接量
和其他编程语言不同,JavaScript不区分整数值和浮点数值。JavaScript中的所有数字均用浮点数值表示
十进制
0
3
10000000
十六进制
0xff
0xCAFE911
八进制
0377 //在严格模式下,八进制是命令禁止的
浮点数直接量
3.14
2345.232
.323232323
6.02e23 //6.02 x 10^23
1.423232E-32 //1.423232 x 10^-23
JavaScript中的算术运算
Math.pow(2,53); //=> 2的53次幂
Math.round(.6); //=>1.0:四舍五入
Math.ceil(.6); //=> 1.0:向上求整
Math.floor(.6); //=>0.0:向下求整
Math.abs(-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,3); //3的立方根
Math.sin(0); Math.cos(0); Math.atan(0); //三角函数
Math.log(10); //10的自然对数
Math.log(100)/Math.LN10; //以10为底的100的对数
Math.log(512)/Math.LN2 ; //以2为底的100的对数
Math.exp(3); //e的三次幂
无穷大和非数字值
JavaScrip预定义了全局变量Infinity和NaN,用来表示正无穷大和非数字值
Infinity //将一个可读写的变量初始化为Infinity
Number.POSITIVE_INFINITY //同样的值
1 / 0; //也是同样的值
Number.MAX_VALUE + 1; //计算结果还是 Infinity
Number.NEGATIVE_INFINITY //该表达式表示了无穷大
- Infinity; //负无穷大
-1 / 0;
-Number.MAX_VALUE - 1;
NaN; //将一个可读写的变量初始化为NaN
Number.NaN; //同样的值
0 / 0; //计算结果为0
Number.MIN_VALUE / 2; //发生下溢:计算结果为0
-Number.MIN_VALUE / 2;
-1/Infinity; //同样是负零
-0
NaN和任何值都不相等。
也就是没办法使用x == x来判断
相反,应当用x!=x判断,当且仅当x为NaN的时候,表达式才为true
函数isNaN()于此类似
isFinite() //在参数不是NaN、Infinity或者-Infinity的时候返回true。
负零值同样有些特殊,它和正零值是相等的,这意味着这两个值几乎一模一样,除了作为除数之外
var zero = 0; //正常的零值
var negz = -0; //负零值
zero === negz; //true 正零值和-0值相等
1/zero === 1/negz; //false:正无穷大和负无穷大不等
二进制浮点数和四舍五入错误
实数有无数个,但是JavaScript通过浮点数形式只能表示其中有限的个数。也就是说,当在JavaScript使用实数的时候,常常只是真实值的一个近似表示
var x = .3 - .2; //30美分减去20美分
var y = .2 - .1; //20美分减去10美分
x == y; // => false :两值不相等
x == .1; // =>false
y == .1; // true .2-.1=.1
日期和时间
JavaScript语言核心包括Date()构造函数,用来创建表示日期和时间的对象。
var then = new Date(2018, 6, 17); //2018年6月17日
var later = new Date(2018, 6, 17, 17, 10, 30); //2018年6月17日17时10分30秒
var now = new Date(); //当前日期和 时间
var elapsed = now - then; //计算时间间隔的 毫秒数
now.getFullYear(); // => 201 8
now.getMonth(); // => 6:从零开始计数的月份
now.getDate(); // =>17:从1开始计数的天数
now.getDay(); //=> 得到星期几 0代表星期日,5代 表星期一
now.getHours(); //当地时间
now.getUTCHours(); //用UTC表 示小时时间基于时区
文本
字符串(string)是一组由16位值组成的不可变的有序序列,每个字符通常来自于Unicode字符集。
JavaScript采用UTF-16的编码的Unicode字符集。
var p = "π"; //π由16位内码表示
var e = "e"; //e由17位内码表示
p.length; // => 1;p包含一个16位的值
e.length; // => 2:e通过UTF-16编码后包含两个16位值
字符串直接量
在JavaScript程序中的字符串直接量,是由单引号或双引号括起来的字符序列。
""; //空字符串:它包含0个字符
'testing';
"3.14";
'name="myform"';
"wouldn't you prefer O'Reilly's book?";
"is the ratio of a circle's circumfernce" +
"to its diameter";
在ECMAScript3中,字符串直接量必须写在一行中,而在ECMAScript5中,字符串直接量可以拆分成数行,每行(\)结束(\n)另起一行
"two\nlines"; //这里定义了一个显示两行的字符串
"one\
long\
line"; // ECMAScript5 中可用
在客户端JavaScript程序设计中,JavaScript代码会夹杂HTML代码的字符串,HTML也会夹杂JavaScript代码。
<button onclick="alert('Thank you')">Click Me</button>
转义字符
在JavaScript字符串中,反斜杠(\)有这特殊的用途,反斜杠符号后加一个字符,就不再表示它们的字面含义了,比如\n就是一个转义字符,它是一个换行符。
反斜杠可以使我们避免使用常规方式解释单引号,但单引号不是用来标记字符串结尾时,它只是一个撇号:
'You \'re right,it can\' be a quote';
转义字符 | 含义 |
---|---|
\o | Null字符(\u0000) |
\b | 退格符(\u0008) |
\t | 水平制表符(\u0009) |
\n | 换行符(\u000A) |
\v | 垂直制表符(\u000B) |
\f | 换页符(\u000C) |
\” | 双引号(\u0022) |
\’ | 撇号或者单引号(\u0027) |
\ | 反斜线(\u005C) |
\r | 回车符(\u000D) |
\xXX | 由两位十六进制数XX指定的Latin-1字符 |
\uXXX | 由四位十六进制数XX指定的Unicode字符 |
字符串的使用
JavaScript的内置功能之一就是字符串连接,加号(+)负责把两个字符串拼接在一起:
msg = "Hello," + "world"; //生成字符串“Hello , world”
greeting = "Welcome to my blog,"
+ " " + msg;
要确定一个字符串的长度,比如要确定字符串s的长度
s.length
除了length属性,字符串还提供了许多可以调用的方法
var s = "Hello,World"; //定义一个字符串
s.charAt(0); //=> "h":第一个字符
s.charAt(s.length-1); //=>"d":最后一个字符
s.substring(1,4); //=> "ell":第二至四个字符
s.slice(1,4); //=>"ell":第二至四个字符
s.slice(-3); //=>"rld":最后三个字符
s.indexOf("l"); //=>2:字符l第一次出现的位置
s.lastIndexOf("l"); //=>10:字符最后一次出现的位置
s.indexOf("l",3); //=>3:在位置3及以后首次出现字符l的位置
s.split(","); //=>["Hello", "World"]:
s.replace("H","2"); //=>2ello,World :全文字符替换
s.toUpperCase(); //HELLO,WORLD:转成大写
记住,在JavaScript中字符串是固定不变的类似于replace()和toUpperCase()方法都返回新的字符串,原字符串本身并没有改变。
在ECMAScript5中,字符串可以当做只读数组,除了使用charAt()方法,也可以使用方括号来访问字符串中的单个字符串
s = "hello,world";
s[0] //=> "h"
s[s.length-1] //=> "d"
模式匹配
在两条斜线之间的文本构成了一个正则表达式直接量。第二条斜线之后也可以跟随一个或多个字母,用来修饰匹配模式的含义
/^HTML/ //匹配以HTML开始的字符串
/[1-9][0-9]*/ //匹配一个非零数字,后面是任意个数字
/\bjavascript\b/i //匹配单词'javascript'
RegExp对象定义了很多有用的方法,字符串同样具有可以接收饿RegExp参数的方法。
var text = "testing: 1 , 2,3";
var pattern = /\d+/g //匹配所有包含一个或多个数字的实例
console.log(pattern.test(text)); //匹配成功
console.log(text.search(pattern)) //首次匹配成功的位置
console.log(text.match(pattern)) //所有匹配组成的数组
console.log(text.replace(pattern,"#"))
console.log(text.split(/\D+/)) //非数字字符截取字符串
布尔值
布尔值代指真或假,开或关,是或否。
JavaScript程序中的比较语句的结果通常都是布尔值
布尔值通常用于JavaScript中的控制结构中
if (a == 4)
b = b + 1;
else
a = a + 1;
任意JavaScript的值都可以转换为布尔值,下面这些值都会被转为false
undefined
null
0
-0
NaN
"" //空字符串
null和undefined
null是JavaScript语言的关键字,它表示一个特殊值,常用来描述空
undefined是预定义的全局变量,它的值就是“未定义”
全局对象
全局对象在JavaScript中有着重要的用途,全局对象的属性是全局定义的符号,JavaScript程序可以直接使用。当JavaScript解释器启动时,它将创建一个新的全局对象,并给它一组定义的初始值
- 全局属性
undefined
Infinity
NaN
- 全局函数
isNaN()
parseInt()
eval()
- 构造函数
Date()
RegExp()
String()
Object()
Array()
在代码最顶级————不存任何函数内的JavaScript代码————可以使用JavaScript关键字this来引用全局对象:
var global = this; //定义一个引用全局对象的全局变量
包装对象
JavaScript对象时一种复合值:它的属性或已命名的集合。
var s = "hello world"; //一个字符串
var word = s.substring(s.indexOf(" ") + 1,s.length);//使用字符串属性
只要引用了字符串s的属性,JavaScript就会将字符串值通过调用new String(s)的方式传换成对象,这个对象继承了字符串的方法,并被用来处理属性的引用
var s = "test", n = 1, b = true; //一个字符串、数字和布尔值
var s = new String(s); //一个 字符串对象
var N = new Number(n) //一个数字对象
var B = new Boolean(b) //一个布尔地域性
“= =”等于运算符将原始值和其包装对象视为相等。但是“===”全等运算符将它们视为不等。通过typeof运算符可以看到原始值和其包装对象的不同。
不可变的原始值和可变的对象引用
字符串中所有的方法看上去返回了一个修改后的字符串,实际上返回的是一个新的字符串值。
var s = "hello"; //定义一个由小写字母 组成的文本
s.toUpperCase(); //返回“HELLO”,但是并没有改变s的值
console.log(s); //返回“hello”:原始字符串的值并没有改变
如果比较两个单独的字符串,当且仅当它们的长度相等且每个索引的字符都相等时,JavaScript才认为它们相等
var o = {x: 1}; //定义了一个对象
o.x = 2; //通过修改对象属性值来更改对象
o.y = 3; //更改对象
var a = [1, 2, 3]; //数组也是可修改的
a[0] = 0; //更改数组的一个元素
a[3] = 4;
console.log(a)
对象的比较并非值得比较:即使两个对象包含同样的值,它们也是不相等的,各个索引元素完全相等的两个数组也不相等。
var o = {x: 1}, p = {x: 1}; //具有相同属性的两个对象
console.log(o === p); // => false :单独两个对象永不相等
var a = [], b = []; //两个单独的空数组
console.log(a === b); //两个单独的数组永不相等
我们通常将对象称为引用类型,以此来和JavaScript的基本类型区分开来。依照术语的叫法,对象值都是引用,对象的比较均是引用的比较L当且仅当它们引用同一个基 对象时,它们才相等。
var a = [];
var b = a;
b[0] = 1;
a[0];
a === b;
复制数组
var a = ['a', 'b', 'c']; //待复制的数组
var b = []; //复制到的目标空数组
for (var i = 0; i < a.length; i++) {
b[i] = a[i];
}
console.log(b);
比较数组
function equalArrays(a, b) {
if (a.length != b.length) return false; //两个长度不同的数组不相等
for (var i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
equalArrays([1,3,4],[1,3,4])
类型转换
10 + " objects"; //=> "10 objects"数字10转换成字符串
"7" * "4"; // => 28:两个字符串均转换为数字
var n = 1 - "x"; //=> NaN:字符串“x”无法转换为数字
n + "object"; //=> "NaN object":NaN转换为字符串"NaN object "
值 | 字符串 | 数字 | 布尔值 | 对象 |
---|---|---|---|---|
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 | "-Infinty" | true | new Number(-Infinity) | |
1(无穷大,非零) | "1" | true | new Number(1) | |
{}(任意对象) | true | |||
[](任意数组) | "" | 0 | true | |
[9](一个数字元素) | "9" | 9 | true | |
['a'](其他数组) | 使用join()方法 | NaN | true | |
function(){}(任意函数) | NaN | true |
转换和相等性
由于JavaScript可以做灵活的类型转换,因此其“==”相等运算符也随相等的含义灵活多变。
null == undefined; //这两值被认为相等
"0" == 0; //在比较之前字符串转换成数字
0 == false; //在比较之前布尔值转换成数字
"0" == false; //在比较之前字符串和布尔值都转换成数字
显示类型转换
尽管JavaScript可以自动做许多类型转换,但有时仍需要做显示转换,或者为了使代码变得清晰易读而显示转换
Number("3"); //=>3
String(false); false.toString(); //=>"false"或者使用false.toString()
Boolean([]); //=> true
Object(3) //=》new Number(3)
x + ""; //等价于String(x)
+x; //等价于Number(x)
!!x; //等价于Boolean(x) 注意是双叹号
var n = 17;
binary_string = n.toString(2);
octal_string = "0" + n.toString(8);
hex_string = "0x" + n.toString(16);
var n = 123456.789;
n.toFixed(0); //123456
n.toFixed(2); //123456.79
n.toFixed(5);
n.toExponential(1); //"1.2e+5"
n.toExponential(3); //"1.235e+5"
n.toPrecision(4); //1.235e+5
n.toPrecision(7); //123456.8
parseInt("3 blind mice"); //=>3
parseFloat("3.14 meters") //=> 3.14
parseInt("-12.34"); //=>-12
parseInt("0xFF"); //=>255
parseInt("0xff"); //255
parseInt("-0XFF"); //-255
parseFloat(".1"); //0.1
parseInt("0.1"); //0
parseInt(".1"); //NaN
parseFloat("$72.47"); //NaN
parseInt("11", 2); // 3
parseInt("ff", 16); // 255
parseInt("zz", 36); // 1369
parseInt("077", 8); //63
parseInt("077", 10); //77
对象转换为原始值
var now = new Date();
typeof (now + 1) //=>"string"
typeof (now - 1) //=>"number"
now == now.toString() //true
now > (now - 1) //=>true 将日期转化为数字
变量声明
变量是使用关键字var来声明
var i;
var sum;
也可以通过一个var关键字来声明多个变量
var i, sum;
而且可以将变量的初始赋值和变量声明和写在一起
var message = "hello";
var i = 0, j = 0, k = 0;
如果未在var声明语句中给定变量指定初始值,那么虽然声明了这个变量,但是在给他存入一个值之前,它的初始值就是undefined
在for和for/in循环中同样可以使用var语句。
for (var i = 0; i < 10; i++) {
console.log(i)
}
for (var i = 0, j = 10; i < 10; i++, j++) {
console.log(i * j);
}
for (var p in "nihao") {
console.log(p);
}
在JavaScript中首先将数字赋值给一个变量,随后再讲字符串赋值给这个变量,这完全合法的
var i = 10;
i = "ten";
变量的作用域
在函数体内,局部变量的优先级高于同名的全局变量。如果在函数内声明的一个局部变量或者函数参数中带有的变量和全局变量重名,那么全局变量就被局部变量所覆盖。
var scope = "global"; //声明一个全局变量
function checkscope() {
var scope = "local"; //声明一个同名的局部变量
return scope; //返回局部变量的值,而不是全局变量的值
}
checkscope(); //=>"local"
尽管在全局作用域编写代码是可以不写var语句,但是声明局部变量的时候则必须使用var语句,
scope = "global"; //声明一个全局变量,甚至不同var来声明
function checkscope(){
scope = "local";
myscope = "local"; //糟糕!我们声明了一个全新的全局变量
return [scope , myscope]; //返回这两个值
}
console.log(checkscope()) //["local","local"]
函数定义是可以嵌套的,由于每个函数都有它自己的作用域,因此会出现几个局部作用域嵌套的情况
var scope = "global scope"; //全局变量
function checkscope() {
var scope = "local scope";
function nested() {
var scope = "nested scope";
return scope;
}
return nested();
}
console.log(checkscope());
函数作用域和声明提前
变量在声明它们的函数体以及这个函数体镶嵌的任意函数体内都是有定义的
function test(o) {
var i = 0;
if ( o == "object") {
var j = 0;
for (var k = 0; k < 10; k++) {
console.log(k);
}
console.log(k)
}
console.log(j)
}
test("object")
JavaScript函数里声明的所有变量都被“提前”至函数体的顶部
var scope = "global";
function f() {
console.log(scope);
var scope = "local";
console.log(scope);
}
f();
将函数内的变量声明“提前”至函数体顶部,同时变量初始化留在原来的位置
作为属性的变量
var truevar = 1; //声明一个不可删除的全局变量
falevar = 2; //创建全局变量的一个可删除属性
this.falevar2 = 3; //同上
console.log(delete falevar) //删除
console.log(delete this.falevar2) //删除
无穷大和非数字值
JavaScrip预定义了全局变量Infinity和NaN,用来表示正无穷大和非数字值
Infinity //将一个可读写的变量初始化为Infinity
Number.POSITIVE_INFINITY //同样的值
1 / 0; //也是同样的值
Number.MAX_VALUE + 1; //计算结果还是 Infinity
Number.NEGATIVE_INFINITY //该表达式表示了无穷大
- Infinity; //负无穷大
-1 / 0;
-Number.MAX_VALUE - 1;
NaN; //将一个可读写的变量初始化为NaN
Number.NaN; //同样的值
0 / 0; //计算结果为0
Number.MIN_VALUE / 2; //发生下溢:计算结果为0
-Number.MIN_VALUE / 2;
-1/Infinity; //同样是负零
-0
NaN和任何值都不相等。
也就是没办法使用x == x来判断
相反,应当用x!=x判断,当且仅当x为NaN的时候,表达式才为true
函数isNaN()于此类似
isFinite() //在参数不是NaN、Infinity或者-Infinity的时候返回true。
负零除数之外
var zero = 0; //正常的零值
var negz = -0; //负零值
zero === negz; //true 正零值和-0值相等
1/zero === 1/negz; //false:正无穷大和负无穷大不等