放在前面的问题
第三章:类型、值和变量
JavaScript是一门弱类型语言,其变量是无类型的,可以被赋予任意类型的值,可以自由地进行数据转换而无需显式声明。
3.1 数字
JavaScirpt不区分整数值和浮点数值,所有数字均用浮点数值表示。
在数字直接量前添加负号可以得到其负值,但负号是一元求反运算符,并不是数字直接量语法的组成部分。
整型直接量
十六进制的整数直接量以‘0x’或‘0X’作为前缀。某些JavaScript的实现支持使用八进制(前缀为‘0’),严格模式下是禁止的,不推荐使用。
浮点型直接量
除了一般的写法,还可以用指数记数法来表示浮点型直接量,即在实数后跟字母e或E,其后再加一个整型的指数,可带负号。
算术运算
JavaScript中的算术运算在溢出、下溢或被零整除时不会报错。
console.log(1 / 0);
console.log(-1 / 0);
console.log(0 / 0);
Infinity
-Infinity
NaN
非数字值NaN有点特殊,它和任何值都不相等,包括自身。x!=x === true当且仅当x为NaN时成立。
所谓下溢,就是当运算结果无限接近于零并比JavaScript能表示的最小值还小的时候发生的一种情形。在这种情况下会返回0,若负数发生下溢则返回-0,0与-0相等。
舍入误差
var x = .3- .2;
var y = .2 - .1;
console.info(x == y);
false
x = 0.09999999999999998
y = 0.1
3.3 布尔值
以下直接量可转化成false
undefined
null
''
0
-0
NaN
3.4 null与undefined
null是JavaScript里的一个关键字,而undefined是一个预定义的全局变量。
typeof null
typeof undefined
null == undefined
null === undefined
"object"
"undefined"
true
false
3.5 全局对象
当JavaScript解释器启动后,它将创建一个新的全局对象,并给它一组定义的初始属性。在浏览器中,Window对象充当了这个全局对象,可以在全局域里用this获得其引用。
var a = 3;
b = 4;
console.log(this.a + this.b);
7
全局变量实际上是作为全局对象的一个属性而存在的。
3.6 包装对象
存取字符串、数字或布尔值的属性时创建的临时对象称作包装对象。
null、undefined没有包装对象,访问它们的属性会造成一个类型错误。
var s = 'test';
s.len = 4;
console.info(s.len);
包装对象的显式创建
var s = 'test';
var so1 = new String(s); //从对应类型变量上创建
var so2 = new String('test'); //从直接量上创建
var so3 = new String(s);
so3.len = 4;
console.info(so1 == s); //原始值变量与其对应的包装对象
console.info(so1 === s);
console.info(so1 == so3); // 同一原始值变量的两个包装对象之间
console.info(so3.len); //自建包装对象不会被自动销毁了,自然也能添加新属性了
typeof s;
typeof so1;
true
false
false
4
"string"
"object"
3.7 不可变的原始值
JavaScript中的原始值是不可改变的。 字符串的一些方法看似改变了原始值,但实际上只是返回了一个新的原始值。
3.8 类型转换
undefind * 1;
null * 1;
"1.2" * 1;
[] * 1;
[9] * 1;
[9, 8] * 1;
f * 1; //f为任意函数
NaN
0
1.2
0
9
NaN
NaN
显式类型转换
number-to-string
函数 | 参数 | 说明 |
---|---|---|
Number.toString | radix(default: 10) | 指定进制输出字符串 |
Number.toFixed | n(default: 0) | 指定小数位数输出字符串 |
Number.toExponential | n(default: 数字有效位数 - 1) | 使用指数记数法(小数点前只有一位),指定小数位数输出字符串 |
Number.toPrecision | n(default: 数字有效位数) | 指定有效数字位数输出字符串,若有效数字位数少于数字整数部分位数,则转为指数记数法 |
string-to-number
函数 | 参数 | 说明 |
---|---|---|
parseInt | str, radix(default: 10) | 指定进制解析输出整数 |
paresFloat | str | 解析输出浮点数 |
parseInt(' 3.5 kilometers'); //可跳过任意数量的前导空格,并略过后面的非法尾随字符
parseInt('0xFF'); //遇到'0x'或'0X'前缀会将其解析为十六进制数
parseInt('0.1');
parseInt('.1');
parseFloat('.1');
3
255
0
NaN
0.1
对象转换为原始值
介绍转换之前,先了解一下两个相关函数。
Object.toString(): 默认情况下,只会返回“[object Object]”。然而很多类重写了这个方法,返回了有意义的值。
Object.valueOf(): 默认情况下简单地返回对象本身,包装对象调用会返回相应的原始值。
object-to-boolean
所有对象都转换为true,包括new Boolean(false)。
object-to-string
- 如果对象的toString()方法返回了一个原始值则将其转为字符串并返回。
- 否则,换用对象的valueOf()方法,处理流程同上。
- 如果对象没有toString()以及valueOf()方法,或者两个方法都没有返回原始值,则抛出一个类型错误异常。
object-to-number
与上面的流程相似,只不过valueOf优先级大于toString,将得到的原始值转为数字返回。
3.9 变量声明
使用var语句重复声明变量是合法且无害的。
变量声明后的初始值为undefined。
3.10 变量作用域
先抛开ES6不谈,JavaScript没有类C语言的块级作用域,取而代之使用了函数作用域: 变量在声明它们的函数体内以及这个函数体嵌套的任意函数体内都是有定义的。
var scope = 'global';
function f() {
console.log(scope);
var scope = 'local';
console.log(scope);
}
一个作用域里面所有的变量声明都会被提前至函数顶部,但赋值操作并不会被提前。
undefined
local
回到ES6上思考一下(嗯,真香!),如果将var换成let结果如何呢?
作为属性的变量
var truevar = 1;
fakevar = 2;
this.fakevar2 = 3;
delete truevar;
delete fakevar
delete this.fakevar
可配置也就代表能被delete成功,上述代码只有truevar是delete失败的。
作用域链
全局作用域有全局对象存放全局变量,函数作用域也有存放存放局部变量的对象,只是这个对象不能通过this来引用。
每一段JavaScript代码都有一个与之关联的由一组对象组成的作用域链,这组对象定义了这段代码“作用域中”的变量。当JavaScript需要查找变量x的值的时候(变量解析),它会从链中的第一个对象开始依次往下查找,若有则使用,若无则抛出了一个引用错误。
JavaScript的最顶层代码也就是全局代码的作用域链就只用一个全局对象。任意一个不包含嵌套的全局方法的作用域链由两个对象组成,第一个是定义函数参数和局部变量的对象,第二个才是全局对象。在一个嵌套的函数体内,作用域链上至少有三个对象。
当定义一个函数时,它实际上保存了一个作用域链。当调用这个函数的时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的作用域链上。并创建了一个新的更长的表示函数调用作用域的链。