众所周知javaScript是一门“极像java的语言”,既然与java那么像,甚至可以说就是套用了java的语法,我在上篇文章《javaScript的基本语法大全》中也列出了很多例子,许多语法和java的一模一样。然而,比较java主要作用于后台开发,而javaScript主要作用于前端开发,其应用场景不一致,所面临的问题也不一样,这也就导致了javaScript的发展历史中又衍生出了许多属于自己的个性。
目前JavaScript 的数据类型,共有七种。分别是:
“Hello World”
)。true
(真)和false
(假)。null
:表示空值。undefined
:表示“未定义”或不存在,常用于区分“未申明”的变量;虽然javaScript定义了这7种数据类型,但是申明时都是统一用var表示的,所以无法区分变量具体是什么类型的。而实际开发中有时候却需要判断数据类型,所以javaScript也提供了判断数据类型的方法。以下是几种判断方法
typeof
运算符 ,返回一个值的数据类型。instanceof
运算符,返回一个值的数据类型,并且可以区分数组和普通对象。Object.prototype.toString
方法。a.typeof
运算符
typeof运算符能判断数据的类型,但不能明细的区分对象中的Date,Array类型。
上面可以看出typeof运算符不仅可以判定基本数据类型,还可以判定函数。利用这写特性,可用于判定一个值是否是有效值,从而避免报错。
b.instanceof
运算符
instanceof
运算符返回一个布尔值,表示对象是否为某个构造函数的实例。
instanceof
运算符的左边是实例对象,右边是构造函数。它会检查右边构建函数的原型对象(prototype),是否在左边对象的原型链上。因此,下面两种写法是等价的。
由于instanceof
检查整个原型链,因此同一个实例对象,可能会对多个构造函数都返回true
。
上面代码中,d
同时是Date
和Object
的实例,因此对这两个构造函数都返回true
。你可以这么理解Date也是一个对象,也属性Object类型。
instanceof
的原理是检查右边构造函数的prototype
属性,是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null
对象。这时,instanceof
判断会失真。
上面代码中,Object.create(null)
返回一个新对象obj
,它的原型是null
(Object.create
的详细介绍见本平台后续文章)。右边的构造函数Object
的prototype
属性,不在左边的原型链上,因此instanceof
就认为obj
不是Object
的实例。但是,只要一个对象的原型不是null
,instanceof
运算符的判断就不会失真。
因为instanceof
是通过构造函数来比较的,因此它可以区分数组和对象。
注意,instanceof
运算符只能用于对象,不适用原始类型的值。
c.Object.prototype.toString
方法。
Object.prototype.toString
能够打印出变量或者数据类型,并且能返回这个类型。
下面我为大家逐一介绍以上的七种数据类型:
JavaScript 内部,所有数字都是以64位浮点数形式储存,所以JavaScript 语言的底层是没有整数的。需要注意的是某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,先转成32位整数,然后再参与运算。
由于浮点数存在不精确的问题,所以在javaScript小数的比较和运算时会存在误差,这点需要特别小心留意。
1.1数值精度问题:
根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-9007199254740992到9007199254740992,都可以精确表示。超过这个范围就无法精确表示了。
上面代码中,大于2的53次方以后,整数运算的结果开始出现错误。所以,大于2的53次方的数值,都无法保持精度。由于2的53次方是一个16位的十进制数值,所以简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。
上面示例表明,大于2的53次方以后,多出来的有效数字(最后三位的111
)都会无法保存,变成0。
1.2数值范围
根据国际标准所定制的二进制规则, JavaScript 能够表示的数值范围为正负2的1024次方(开区间),超出这个范围的数无法表示。如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity
。
Math.pow(2, 1024) // Infinity
如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。
Math.pow(2, -1075) // 0
JavaScript 提供Number
对象的MAX_VALUE
和MIN_VALUE
属性,返回可以表示的具体的最大值和最小值。
1.3数据的全局方法:
parseInt
方法还可以接受第二个参数(2到 36之间),表示被解析的值的进制,返回该值对应的十进制数。parseInt
的第二个参数默认为10,即默认是十进制转十进制。parseFloat
():将一个字符串转为浮点数。isNaN():
判断一个值是否为NaN
字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。字符串可以被视为字符数组,因此可以使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始),也可以使用length属性。
从上面可以看出,字符串取坐标跟数组一样,也能使用length得出长度,但是不可以改变它的长度值。通过这个特征便可以使用for循环遍历字符串了。
null表示不存在,与java中的null如出一辙,本身就是引用了java中null的规则。
var a = null;
a //null
根据C语言传传统规则,null在参与数字运算时可以转为0。
Number(null) // 0
5 + null // 5
我们知道在java中null可能是情况是调用方法传参数的时候传的值是空值,也可能是申明了值,却并未赋值,因此null可以表示为一个空对象。但还有一种情况,就是并非申明的值,在java中对未申明的值编译的时候就会报错,但如果是创建了一个空对象就不会报错。如何去区分这两种不同的情况呢,况且null还可以转成0,可以回干扰误导计算。这时候就需要用到“undefined”了。
undefined和null
一样都可以表示“没有”,含义非常相似。将一个变量赋值为undefined
或null
,老实说,语法效果几乎没区别,几乎相等。
从上面可以看出null与undefined相等,但用===比较又不相等,说明他们值相等,但类型不一致。
既然含义与用法都差不多,为什么要同时设置两个这样的数据类型,这不是无端增加复杂度,令初学者困扰吗?说到这里这就与历史原因有关了。
1995年 JavaScript 诞生时,最初像 Java 一样,只设置了null
表示"无"。但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果null
自动转为0,很不容易发现错误。
因此,他又设计了一个undefined
。区别是这样的:null
是一个表示“空”的对象,转为数值时为0
;undefined
是一个表示"此处无定义"的原始值,转为数值时为NaN
。
Number(undefined) // NaN
5 + undefined // NaN
对于null
和undefined
,大致可以像下面这样理解。
null
表示空值,即该处的值现在为空。调用函数时,某个参数未设置任何值,这时就可以传入null
,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null
,表示未发生错误。
undefined
表示“未定义”,下面是返回undefined
的典型场景。
5.布尔值 Boolean 布尔值代表“真”和“假”两个状态。“真”用关键字true表示,“假”用关键字false表示。布尔值只有这两个值。 下列运算符会返回布尔值: 前置逻辑运算符: ! (Not) 相等运算符:===,!==,==,!= 比较运算符:>,>=,<,<= 并且,或运算:&&,|| (这两个运算符一般搭配前面的运算符一起参与运算) 如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为false,其他值都视为true。 undefined null false 0 NaN ""或''(空字符串) 在实际开发中可利用值转布尔值的规则,结合三元运算符一起使用。例如:当值为空串时显示空,不为空串时再判断类型,取对象中的属性。
上面的代码中,函数add接收一个参数x,如果x是'',那么!x就会转成 true,就会显示'',如果不是空串,就会继续运行后面的三元运算符。
注意,空数组([]
)和空对象({}
)对应的布尔值,都是true
。
6.对象Object 对象(object)是 JavaScript 语言的核心概念,也是最重要的数据类型。对象是一种无序的复合数据集合,通过“键值对”(key-value)的来表达具体的数据类型。
var obj = {
foo: 'Hello',
bar: 'World'
};
上面代码中,大括号就定义了一个对象,它被赋值给变量obj,所以变量obj就指向一个对象。该对象内部包含两个键值对(又称为两个“成员”),第一个键值对是foo: 'Hello',其中foo是“键名”(成员的名称),字符串Hello是“键值”(成员的值)。键名与键值之间用冒号分隔。第二个键值对是bar: 'World',bar是键名,World是键值。两个键值对之间用逗号分隔。 注意:对象的键名只能是字符串,默认就是字符串,所以申明的时候可以省略引号(如果键名保护不符合规范的字符还是需要加引号的),而值可以是任意的数据类型,甚至是函数都可以。 对象的每一个键名又称为“属性”(property),它的“键值”可以是任何数据类型。如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
var obj = {
p: function (x) {
return 2 * x;
}
};
obj.p(1) // 2
6.1属性的操作 6.1.1.读取: 读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。
var obj = {
p: 'Hello World'
};
obj.p // "Hello World"
obj['p'] // "Hello World"
注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。 6.1.2.属性的赋值: 点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。
var obj = {};
obj.foo = 'Hello';
obj['bar'] = 'World';
上面代码中,分别使用点运算符和方括号运算符,对属性赋值。 JavaScript 允许属性的“后绑定”,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。 6.1.3.属性的查询与遍历 查看一个对象本身的所有属性,可以使用Object.keys方法,或者for in循环
var obj = {
key1: 1,
key2: 2
};
Object.keys(obj);
// ['key1', 'key2']
for...in循环用来遍历一个对象的全部属性。
var obj = {a: 1, b: 2, c: 3};
for (var i in obj) {
console.log('键名:', i);
console.log('键值:', obj[i]);
}
// 键名: a
// 键值: 1
// 键名: b
// 键值: 2
// 键名: c
// 键值: 3
for...in循环有两个使用注意点。 它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。 它不仅遍历对象自身的属性,还遍历继承的属性,但如果改属性设置为了不可遍历,就不会被遍历到。 举例来说,对象都继承了toString属性,但是for...in循环不会遍历到这个属性。
var obj = {};
// toString 属性是存在的
obj.toString // toString() { [native code] }
for (var p in obj) {
console.log(p);
} // 没有任何输出
如果继承的属性是可遍历的,那么就会被for...in循环遍历到。但是,一般情况下,都是只想遍历对象自身的属性,所以使用for...in的时候,应该结合使用hasOwnProperty方法,在循环内部判断一下,某个属性是否为对象自身的属性。
var person = { name: '老张' };
for (var key in person) {
if (person.hasOwnProperty(key)) {
console.log(key);
}
}
// name