前言
本系列是之前的学习积累,主要针对JS教程入门时进行学习的记录整理。使用到的参考资料有菜鸟教程、阮一峰JS入门教程系列、网道等多个网站。内容主要基于 ECMAScript 5.1 版本,这是学习 JavaScript 语法的基础。
数据类型转换
JavaScript 是一种动态类型语言,变量没有类型限制,可以随时赋予任意值。
各种运算符对数据类型是有要求的。如果运算符发现,运算子的类型与预期不符,就会自动转换类型。
1. 强制转换
1.1 Number()
使用Number函数,可以将任意类型的值转化成数值。
- 原始类型值
// 数值:转换后还是原来的值
Number(324) // 324
// 字符串:如果可以被解析为数值,则转换为相应的数值
Number('324') // 324
// 字符串:如果不可以被解析为数值,返回 NaN
Number('324abc') // NaN
// 空字符串转为0
Number('') // 0
// 布尔值:true 转成 1,false 转成 0
Number(true) // 1
Number(false) // 0
// undefined:转成 NaN
Number(undefined) // NaN
// null:转成0
Number(null) // 0
Number函数将字符串转为数值,要比parseInt函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为NaN。
parseInt和Number函数都会自动过滤一个字符串前导和后缀的空格。
parseInt('\t\v\r12.34\n') // 12
Number('\t\v\r12.34\n') // 12.34
- 对象 Number方法的参数是对象时,将返回NaN,除非是包含单个数值的数组。
Number背后的转换规则如下:
-
调用对象自身的valueOf方法。如果返回原始类型的值,则直接对该值使用Number函数,不再进行后续步骤。
-
如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续步骤。
-
如果toString方法返回的是对象,就报错
valueOf和toString方法,都是可以自定义的。
Number({
valueOf: function () {
return 2;
}
})
// 2
Number({
toString: function () {
return 3;
}
})
// 3
Number({
valueOf: function () {
return 2;
},
toString: function () {
return 3;
}
})
// 2
1.2 String()
String函数可以将任意类型的值转化成字符串
- 原始类型值
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null
- 对象 String方法的参数如果是对象,返回一个类型字符串;如果是数组,返回该数组的字符串形式。
String方法背后的转换规则:
- 先调用对象自身的toString方法。如果返回原始类型的值,则对该值使用String函数,不再进行以下步骤。
- 如果toString方法返回的是对象,再调用原对象的valueOf方法。如果valueOf方法返回原始类型的值,则对该值使用String函数,不再进行以下步骤。
- 如果valueOf方法返回的是对象,就报错。
String({
toString: function () {
return 3;
}
})
// "3"
String({
valueOf: function () {
return 2;
}
})
// "[object Object]"
String({
valueOf: function () {
return 2;
},
toString: function () {
return 3;
}
})
// "3"
1.3 Boolean()
Boolean()函数可以将任意类型的值转为布尔值。
除了以下五个值的转换结果为false,其他的值全部为true。
undefined
null
0(包含-0和+0)
NaN
''(空字符串)
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true
为了保证性能,统一规定,对象的布尔值为true。
2. 自动转换
遇到以下三种情况时,JavaScript 会自动转换数据类型,即转换是自动完成的,用户不可见。
- 不同类型的数据互相运算。
- 对非布尔值类型的数据求布尔值
- 对非数值类型的值使用一元运算符(即+和-)。
自动转换的规则:
预期什么类型的值,就调用该类型的转换函数。比如,某个位置预期为字符串,就调用String函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认转为数值。
由于自动转换具有不确定性,且不易被发现,建议在预期为布尔值、数值、字符串的地方,全部使用Boolean、Number和String函数进行显式转换。
2.1 自动转换为布尔值
系统内部会自动调用Boolean函数。
因此除了以下五个值,其他都是自动转为true。
undefined
null
+0或-0
NaN
''(空字符串)
2.2 自动转换为字符串
具体规则是,先将复合类型的值转为原始类型的值,再将原始类型的值转为字符串。
字符串的自动转换,主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"
2.3 自动转换为数值
系统内部会自动调用Number函数。
除了加法运算符(+)有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值。
一元运算符也会把运算子转成数值。
错误处理机制
1. Error实例对象
JavaScript 解析或运行时,一旦发生错误,引擎就会抛出一个错误对象。JavaScript 原生提供Error构造函数,所有抛出的错误都是这个构造函数的实例。
var err = new Error('出错了');
err.message // "出错了"
- message:错误提示信息
- name:错误名称(非标准属性)
- stack:错误的堆栈(非标准属性)
function throwit() {
throw new Error('');
}
function catchit() {
try {
throwit();
} catch(e) {
console.log(e.stack); // print stack trace
}
}
catchit()
// Error
// at throwit (~/examples/throwcatch.js:9:11)
// at catchit (~/examples/throwcatch.js:3:9)
// at repl:1:5
2. 原生错误类型
Error实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他6种错误对象。也就是说,存在Error的6个派生对象。
2.1 SyntaxError 对象
解析代码时发生的语法错误。
// 变量名错误
var 1a;
// Uncaught SyntaxError: Invalid or unexpected token
// 缺少括号
console.log 'hello');
// Uncaught SyntaxError: Unexpected string
2.2 ReferenceError 对象
引用一个不存在的变量时发生的错误。
另一种触发场景是,将一个值分配给无法分配的对象,比如对函数的运行结果赋值。
// 使用一个不存在的变量
unknownVariable
// Uncaught ReferenceError: unknownVariable is not defined
// 等号左侧不是变量
console.log() = 1
// Uncaught ReferenceError: Invalid left-hand side in assignment
2.3 RangeError 对象
一个值超出有效范围时发生的错误.
主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。
2.4 TypeError 对象
变量或参数不是预期类型时发生的错误.
比如,对字符串、布尔值、数值等原始类型的值使用new命令,就会抛出这种错误,因为new命令的参数应该是一个构造函数。
调用对象不存在的方法,也会抛出TypeError错误。
2.5 URIError 对象
URI 相关函数的参数不正确时抛出的错误,主要涉及encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape()这六个函数。
2.6 EvalError 对象
eval函数没有被正确执行时,会抛出EvalError错误。
开发者可以使用它们,手动生成错误对象的实例。这些构造函数都接受一个参数,代表错误提示信息(message)。
var err1 = new Error('出错了!');
var err2 = new RangeError('出错了,变量超出有效范围!');
var err3 = new TypeError('出错了,变量类型无效!');
err1.message // "出错了!"
err2.message // "出错了,变量超出有效范围!"
err3.message // "出错了,变量类型无效!"
3. 自定义错误
function UserError(message) {
this.message = message || '默认信息';
this.name = 'UserError';
}
UserError.prototype = new Error();//继承Error对象
UserError.prototype.constructor = UserError;
new UserError('这是自定义的错误!');
4. throw语句
throw语句的作用是手动中断程序执行,抛出一个错误。
throw也可以抛出自定义错误
function UserError(message) {
this.message = message || '默认信息';
this.name = 'UserError';
}
throw new UserError('出错了!');
// Uncaught UserError {message: "出错了!", name: "UserError"}
throw可以抛出任何类型的值。也就是说,它的参数可以是任何值。
5.try...catch结构
JavaScript 提供了try...catch结构,允许对错误进行处理,选择是否往下执行。
catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。
try {
throw "出错了";
} catch (e) {
console.log(111);
}
console.log(222);
// 111
// 222
try...catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句。
return语句的执行是排在finally代码之前,只是等finally代码执行完毕后才返回
var count = 0;
function countUp() {
try {
return count;
} finally {
count++;
}
}
countUp()
// 0
count
// 1
经典使用场景
openFile();
try {
writeFile(Data);
} catch(e) {
handleError(e);
} finally {
closeFile();
}
catch代码块之中,触发转入finally代码块的标志,不仅有return语句,还有throw语句。
function f() {
try {
throw '出错了!';
} catch(e) {
console.log('捕捉到内部错误');
throw e; // 这句原本会等到finally结束再执行
} finally {
return false; // 直接返回
}
}
try {
f();
} catch(e) {
// 此处不会执行
console.log('caught outer "bogus"');
}
// 捕捉到内部错误
console对象
console对象是 JavaScript 的原生对象,它有点像 Unix 系统的标准输出stdout和标准错误stderr,可以输出各种信息到控制台,并且还提供了很多有用的辅助方法。
console的常见用途有两个。
调试程序,显示网页代码运行时的错误信息。 提供了一个命令行接口,用来与网页代码互动。
1. console对象的静态方法
1.1 console.log()
console.log方法用于在控制台输出信息。它可以接受一个或多个参数,将它们连接起来输出。
console.log方法会自动在每次输出的结尾,添加换行符
console.log(1);
console.log(2);
console.log(3);
// 1
// 2
// 3
console.log(' %s + %s = %s', 1, 1, 2)
// 1 + 1 = 2
console.log({foo: 'bar'})
// Object {foo: "bar"}
console.log(Date)
// function Date() { [native code] }
支持以下占位符,不同类型的数据必须使用对应的占位符。
%s 字符串
%d 整数
%i 整数
%f 浮点数
%o 对象的链接
%c CSS 格式字符串
console对象的所有方法,都可以被覆盖。因此,可以按照自己的需要,定义console.log方法。
使用自定义的console.log方法,可以在显示结果添加当前时间:
['log', 'info', 'warn', 'error'].forEach(function(method) {
console[method] = console[method].bind(
console,
new Date().toISOString()
);
});
console.log("出错了!");
// 2014-05-18T09:00.000Z 出错了!
1.2 console.info()、console.debug()
console.info是console.log方法的别名,用法完全一样。只不过console.info方法会在输出信息的前面,加上一个蓝色图标。
console.debug方法与console.log方法类似,会在控制台输出调试信息。但是,默认情况下,console.debug输出的信息不会显示,只有在打开显示级别在verbose的情况下,才会显示。
1.3 console.warn(), console.error()
//console这块我日后再补充学习吧,一般对我现在阶段的项目经历来说log就足够了,还有一些常用的API知道就好。