1.简介
JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有八种,但我们先只学习其中常见的的六种
- 数值
number
:整数和小数(比如1
和3.14
) - 字符串
string
:文本(比如"Hello World"
或'Hello World'
) - 布尔值
boolean
:表示真伪的两个特殊值,即true
(真)和false
(假) undefined
:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值(该类型的值唯一并且为其本身)null
:表示空值,即此处的值为空(该类型的值唯一并且为其本身)- 对象
object
:各种键值对组成的集合(此处指广义的对象)
// 函数返回”function” function f() {} typeof f // “function”
// undefined返回”undefined” typeof undefined // “undefined”
// 对象返回”object”({}为狭义对象的声明方式之一,[]为数组的声明方式之一) typeof {} // “object” typeof [] // “object”
```javascript
typeof null // "object"
null
的类型是object
,这是由于历史原因造成的。1995年的 JavaScript 语言第一版,只设计了五种数据类型(对象、整数、浮点数、字符串和布尔值),没考虑null
,只把它当作object
的一种特殊值。后来null
独立出来,作为一种单独的数据类型,为了兼容以前的代码,typeof null
返回object
就没法改变了
3.数值
3.1数值的表示方法
// 可以使用科学表示法
123000 === 123e3 // true
0.123 === 123e-3 // true
// 表示小数时可省略0
0.123 === .123 // true
3.2数值的进制
使用字面量(literal)直接表示一个数值时,JavaScript 对整数提供四种进制的表示方法:十进制、十六进制、八进制、二进制。
- 十进制:没有前导0的数值。
- 八进制:有前缀0o或0O的数值,或者有前导0、且只用到0-7的八个阿拉伯数字的数值。
- 十六进制:有前缀0x或0X的数值。
- 二进制:有前缀0b或0B的数值。
默认情况下,JavaScript 内部会自动将八进制、十六进制、二进制转为十进制。下面是一些例子。
0xff // 255
0o377 // 255
0b11 // 3
如果八进制、十六进制、二进制的数值里面,出现不属于该进制的数字,就会报错
0xzz // 报错
0o88 // 报错
0b22 // 报错
3.3NaN
NaN
是 JavaScript 的特殊值,表示“非数字”(Not a Number),主要出现在将字符串解析成数字出错的场合
5 - 'x' // NaN
需要注意的是,NaN
不是独立的数据类型,而是一个特殊数值,它的数据类型依然属于Number
,使用typeof
运算符可以看得很清楚
typeof NaN // 'number'
4.字符串
4.1字符串书写方式
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中
'abc'
"abc"
单引号字符串的内部,可以使用双引号。双引号字符串的内部,可以使用单引号
'key = "value"'
"It's a long journey"
字符串默认只能写在一行内,分成多行将会报错
'a
b
c'
// SyntaxError: Unexpected token ILLEGAL
如果长字符串必须分成多行,可以在每一行的尾部使用反斜杠或连接运算符+
'Long \
long \
long \
string'
'Long '
+ 'long '
+ 'long '
+ 'string'
4.2字符串遍历方式
var str='我是一个字符串';
// 读取方式(字符串与数组类似,可通过索引读取)
str[0] // '我'
str.length // 7
// 遍历方式
for(var i=0; i<str.length; i++){
console.log(str[i]);
}
5.对象
5.1对象生成方法
对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型
什么是对象?简单说,对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合
var obj = {
foo: 'Hello',
bar: 'World'
};
上面代码中,大括号就定义了一个对象,它被赋值给变量obj
,所以变量obj
就指向一个对象。该对象内部包含两个键值对(又称为两个“成员”),第一个键值对是foo: 'Hello'
,其中foo
是“键名”(成员的名称),字符串Hello是“键值”(成员的值)。键名与键值之间用冒号分隔。第二个键值对是bar: 'World'
,bar
是键名,World
是键值。两个键值对之间用逗号分隔
5.2对象属性的增删改查(新增、删除、修改、查询)
var obj = {
foo: 'Hello',
bar: 'World'
};
// 两种查询方式
obj.foo // 'Hello'
obj['bar'] // 'World'
// 通过赋值语句进行新增和修改
obj.a='你好';
obj.bar='世界';
obj.bar // '世界'
// delete删除命令
delete obj.bar
obj.bar // undefined
5.3对象的引用
var o1 = {};
var o2 = o1;
o1.a = 1;
o2.a // 1
o2.b = 2;
o1.b // 2
上面代码中,o1
和o2
指向同一个对象,因此为其中任何一个变量添加属性,另一个变量都可以读写该属性。
此时,如果取消某一个变量对于原对象的引用,不会影响到另一个变量
var o1 = {};
var o2 = o1;
o1 = 1;
o2 // {}
但是,这种引用只局限于对象,如果两个变量指向同一个原始类型的值。那么,变量这时都是值的拷贝
var x = 1;
var y = x;
x = 2;
y // 1
上面的代码中,当x
的值发生变化后,y
的值并不变,这就表示y
和x
并不是指向同一个内存地址
5.4对象属性的遍历
var obj = {
foo: 'Hello',
bar: 'World'
};
// 方式一:通过Object.keys(obj)获取所有键名数组,然后遍历数组来访问对象属性
var keys = Object.keys(obj)
keys // ['foo','bar']
for(var i=0; i<keys.length; i++){
console.log(obj[ keys[i] ]);
}
// 方式二:for...in循环
for(var key in obj){
console.log('键名',key);
console.log('键值',obj[key]);
}
6.数组
6.1数组生成方法
数组(array)是按次序排列的一组值。每个值的位置都有编号(从0开始),整个数组用方括号表示
var arr=['a','b','c'];
上面代码中的'a'
、'b'
、'c'
就构成一个数组,两端的方括号是数组的标志。'a'
是0
号位置,'b'
是1
号位置,'c'
是2
号位置
除了在定义时赋值,数组也可以先定义后赋值
var arr=[];
arr[0] = 'a';
arr[1] = 'b';
arr[2] = 'c';
6.2数组的本质
typeof [1, 2, 3] // "object"
上面代码表明,typeof
运算符认为数组的类型就是对象。
数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。
var arr = ['a', 'b', 'c'];
Object.keys(arr)
// ["0", "1", "2"]
6.3length
属性
数组的length
属性,返回数组的成员数量
['a', 'b', 'c'].length // 3
6.4数组的遍历方式
var arr=[1,2,3];
// 方式一:通过length确定长度,使用循环依次读取
for(var i=0; i<arr.length; i++){
console.log(arr[i]);
}
// 方式二:for...in循环
for(var i in arr){
console.log(arr[i]);
}
7.函数
7.1函数的声明
function
命令
function
命令声明的代码区块,就是一个函数。function
命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面
function print(s) {
console.log(s);
}
- 函数表达式
除了用function
命令声明函数,还可以采用变量赋值的写法
var print = function(s) {
console.log(s);
};
Function
构造函数
第三种声明函数的方式是Function
构造函数
var add = new Function(
'x',
'y',
'return x + y'
);
// 等同于
function add(x, y) {
return x + y;
}
7.2函数的重复声明
如果同一个函数被多次声明,后面的声明就会覆盖前面的声明
function f() {
console.log(1);
}
f() // 2
function f() {
console.log(2);
}
f() // 2
7.3圆括号运算符,return 语句和递归
function add(x, y) {
return x + y;
}
add(1, 1) // 2
上面代码中,函数名后面紧跟一对圆括号,就会调用这个函数。
函数体内部的return
语句,表示返回。JavaScript
引擎遇到return
语句,就直接返回return
后面的那个表达式的值,后面即使还有语句,也不会得到执行。也就是说,return
语句所带的那个表达式,就是函数的返回值。return
语句不是必需的,如果没有的话,该函数就不返回任何值,或者说返回undefined
。
函数可以调用自身,这就是递归(recursion)。下面就是通过递归,计算斐波那契数列的代码
function fib(num) {
if (num === 0) return 0;
if (num === 1) return 1;
return fib(num - 2) + fib(num - 1);
}
fib(6) // 8
7.4第一等公民
JavaScript 语言将函数看作一种值,与其它值(数值、字符串、布尔值等等)地位相同。凡是可以使用值的地方,就能使用函数。比如,可以把函数赋值给变量和对象的属性,也可以当作参数传入其他函数,或者作为函数的结果返回。函数只是一个可以执行的值,此外并无特殊之处
function add(x, y) {
return x + y;
}
// 将函数赋值给一个变量
var operator = add;
// 将函数作为参数和返回值
function a(op){
return op;
}
a(add)(1, 1)
// 2
7.5函数作用域
作用域(scope)指的是变量存在的范围。在 ES5 的规范中,JavaScript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域,变量只在函数内部存在。ES6 又新增了块级作用域,本教程不涉及
对于顶层函数来说,函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取
/* 全局作用域 */
var a = 1;
function f() {
/* 函数作用域 */
var b=2;
console.log(a);
}
f() // 1
console.log(b) // ReferenceError: b is not defined
函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关
var a = 1;
var x = function () {
console.log(a);
};
function f() {
var a = 2;
x();
}
f()