一、数据类型
基本类型
- number
- string
- boolean
- object
- undefined
- null
通常,数值、字符串、布尔值这三种类型被称为不可再分的原始类型;对象称为合成类型,它往往由多个原始类型的值构成,可以看作是一种容器;undefined和null看成两种特殊值。
二、对象
对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型。
生成
简单来说,对象是一种无序的数据集合,这种数据的单位是一一对应的”键值对“(key-value)。
var person = {
name: 'Ming',
age: 18,
isMale: true
};
在上述例子中,使用大括号为标志定义了一个对象并赋值给person,以name-'Ming’这一组为例,name为该对象一个属性的键,'Ming’为其对应的值。冒号左边为字符串(加不加引号都可以),右边为任意类型。
对象的引用
如果不同的变量名都指向同一个对象,那么它们可以称为对象的别名,指向同一个内存地址。修改其中任何一个变量,对象的值都发生改变,其他变量也随之改变。
var o1 = {};
var o2 = o1;
o1.a = 1;
console.log(o1.a); // -> 1
o2.b = 2;
console.log(o1.a); // -> 2
三、函数
概览
函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
在JavaScript中,函数被看作是一种值,与其他基本类型值地位相同。因此函数可以当作普通的值来进行传递或者使用。
### 声明与使用
以下三种方式都可以对函数进行声明:
1.function关键字
使用function
命令声明一段代码块,就是一个函数。如
function print(s) {
console.log(s);
}
2.函数表达式
采用变量赋值的方式声明一个匿名函数(此时这个函数也称为“函数表达式”)。
var print = function(s) {
console.log(s);
};
使用此方法声明函数时,可以加上函数名,但是只能在内部使用这个名称。
3.Function构造函数(不推荐使用)
使用Function构造函数,填入任意数量的参数,最后一个参数会被视为函数体。可以不使用new命令,返回的结果完全一致。
var add = new Function(
'x',
'y',
'return x + y'
);
console.log(add(1, 2)); // -> 3
使用圆括号运算符调用一个函数。
作用域
在ES5中,JavaScript只有两种作用域:全局作用域,变量在程序中一直存在且可随时读取;函数作用域,变量只在函数体内部使用。
var a = 1;
function print(){
var b = 3;
console.log(a);
console.log(b);
}
print(); // -> 1 -> 3
console.log(a); // -> 1
console.log(b); // ReferenceError: b is not defined
在上述例子中,先调用print()函数方法中,打印输出两个只ab,其中a属于全局作用域;之后在函数外部再次打印输出a、b,因为此时b的作用域(函数内部可用)已失效,因此解释器报错。
对于函数自身来说,由于自己也是一个值,因此它的定义域就是声明时的定义域,与运行时的定义域无关
闭包
闭包就是函数内部的函数,其作用是为了方便外部读取函数内部的变量。
通过闭包,可以让函数内部的变量一直存在于内存中。
function createIncrementor(start) {
return function () {
return start++;
};
}
var inc = createIncrementor(5);
console.log(inc()); // 5
console.log(inc()); // 6
console.log(inc()); // 7
在上面的例子中,可以看到通过闭包使得createIncrementor的内部环境一直存在,从而start的状态被保留。
通过闭包也可以封装对象的私有属性和私有方法。
function Person(name) {
var _age;
function setAge(n) {
_age = n;
}
function getAge() {
return _age;
}
return {
name: name,
getAge: getAge,
setAge: setAge
};
}
var p1 = Person('张三');
p1.setAge(25);
console.log(p1.getAge()); // -> 25
上面的例子通过闭包getAge
和setAge
,将函数内部的_age
变成了私有变量。
三、运算
参数传递
对于函数的参数,如果是原始类型的值,使用传值传递。函数体内部的改变不会影响变量本身。
var p = 2;
function f(p) {
p = 3;
}
console.log(p); // -> 2
如果是复合类型的值,使用按址传递。在函数内部改变会影响到原始值。
var obj = {
p: 1
};
function f(o) {
o.p = 2;
}
f(obj);
console.log(obj.p); // -> 2
类型转换
JavaScript是一种动态类型语言,变量没有类型限制,可以随时赋值修改。
例如以下代码在实际使用中完全可行。
var a = 1;
console.log(a); // -> 1
a = 'hello';
console.log(a); // -> hello
a = true;
console.log(a); // -> true
1.强制转换
使用Number()、String()和Boolean()三个函数将各种类型的值转化为对应类型的值。
1.Number()
将任意类型的值转化为数值。
(1)原始类型值:
- 数值:返回原数值
- 布尔值:true为1,false为0
- 字符串:全为数值返回数值,有非数值字符返回NaN
- undefined:返回NaN
- null:返回0
(2)对象
- 单个数值的数组或者空数组:返回数值
- 多个数值的数组:返回NaN
- 其他对象:返回NaN
2.String()
将任意类型的值转化为数值。
(1)原始类型值:(""引起一个字符串类型的值)
- 数值:返回相应的字符串
- 字符串:返回原字符串
- 布尔值:true为“true”,false为“false”
- undefined:返回"undefined"
- null:返回"null"
(2)对象
String
方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。
String({a: 1}) // -> "[object Object]"
String([]) // -> ""
String([1, 2, 3]) // -> "1,2,3"
3.Boolean()
将任意类型的值转化为布尔值。
以下五个值的转化结果为false,其他全为true。
- undefined
- null
- 0(包含±号)
- NaN
- 空字符串
2.自动转换
自动转换将会使用预判需要得类型,然后调用对应的类型转换函数。具有一定的不确定性。
-
自动转化为字符串
遇到预期为字符串的地方自动转化为字符串,但需要先将复合类型的值转化为原始类型,然后再转化为字符串。对于加法运算,当第一个值为字符串时,另一个值为非字符串,会将后一个值转化为字符串。
console.log('abc' + [1]); // -> 11
console.log('abc' + {p: 1}); // -> abc[object Object]
console.log([] + 'abc'); // -> 1
console.log([] + {}); // -> [object Object]
-
自动转换为布尔值
遇到预期为布尔值的地方自动转化为布尔值(如
if
语句的条件)将会调用Boolean
函数进行类型转换,因此遵循Boolean()的类型转换规则。if([]){ console.log('a'); // -> a }; if(undefined){ console.log('b'); }
-
自动转化为数值
遇到预期为数值的地方自动转化为数值,除了加法运算可能运算子转化为字符串,其他运算符都会把运算子自动转化为数值。
console.log('2' - '1'); // -> 1 console.log(true + 1); // -> 2 console.log([] * 1); // -> 0 console.log(null / 1); // -> 0 console.log(undefined + 1); // NaN
另外,一元运算符也会把运算子转化为字符,遵循
Number
函数的类型转化规则。