一、常见数据类型
JavaScript中可以用typeof获取某个变量的数据类型,常见的数据类型有:number,string,boolean,object,function,undefined,直接看代码:
1 | let a = 1; |
二、类型转换
#####1. 显式类型转换
通过全局函数parseInt,parseFloat进行转换,如下:
1 | let a = '123' |
parseInt会从左到右扫描,直到遇到无法解析字符为止,如果第一个字符就无法解析,那么就返回NaN,如下:
1 | let b = '123hello' |
注意NaN不能用==进行判断相等,需要用isNaN函数进行判断。
#####2. 隐式类型转换
某些情况下,JavaScript会自动进行类型转换,比如在使用==时:
1 | let a = 123; |
这里b会被先转换成number类型123,然后再与a进行比较,结果返回true,而c就不会,所以返回false,如果需要判断类型可以改为用===,这时123就不会和’123’相等了。
在使用+,-等数学运算符时也可能存在隐式类型转换:
1 | let a = '10'; |
对于能直接字符串连接的就直接连接,否则就尝试转换成number再运算,对于无法转换的返回NaN。
三、变量作用域
子函数可以使用父函数定义的局部变量。
四、数组
JavaScript中定义数组有两种方式:
1 | let arr1 = [1, 2, 3, 4]; |
而且同个数组可以存放不同类型数据:
1 | let arr3 = [1, 'hello', 2]; |
数组有个length属性,表示数组的长度,而且该属性值还可以修改:
1 | let arr1 = [1, 2, 3, 4]; |
数组本身就是对象,有一系列的函数可以调用,比如在数组尾部添加和删除元素用push和pop:
1 | let arr1 = [1, 2, 3, 4]; |
相对应的,在数组头添加和删除元素用unshift和shift:
1 | let arr1 = [1, 2, 3, 4]; |
另外还有个splice函数,用于在指定位置删除和添加元素:
1 | let arr1 = [1, 2, 3, 4]; |
concat函数用于连接多个数组,join函数用于数组转字符串:
1 | let arr1 = [1, 2, 3, 4]; |
最后一个是数组排序函数sort,注意它默认都是按照字符串进行排序的,即使数组中的元素都是number类型:
1 | let arr = [8, 9, 10, 11, 3, 2]; |
如果要按照数值大小进行排序,需要传入比较函数:
1 | let arr = [8, 9, 10, 11, 3, 2]; |
五、条件和循环
这两个和C++中的类似,都是if,else,switch,for,while,break,continue这些,另外JavaScript也有三目表达式。需要注意的就是JavaScript中可以用for…in进行循环遍历:
1 | let arr = [1, 2, 3]; |
这里需要注意条件语句中的判断条件为false的情况:
1 | let a; |
也就是说,这四种情况下都是判断为false,其它情况判断为true。
六、Json
JavaScript中经常会使用到json对象,比如请求接口时后端的返回结果等,访问json中的值可以用.或者[]:
1 | let json = {a: 1, b: 2, c: 3}; |
遍历json:
1 | let json = {a: 1, b: 2, c: 3}; |
七、函数
JavaScript中没有真正意义上的函数重载,但对于某个函数,参数个数是不固定的,可以通过arguments获取到:
1 | let fun = function() { |
也就是说,调用函数时不能看函数参数签名,参数签名列表可以是空,但外部还是可以传参数进去的,内部也可以通过arguments获取到对于的参数,不过为了可读性,一般都会写上参数列表:
1 | let fun = function(a, b, c) { |
八、事件队列
JavaScript只有一个线程在干活,不支持多线程,但它又是非阻塞的,其内部使用了事件队列。
JavaScript中有两个事件队列:宏任务队列和微任务队列,setTimeout和setInterval等任务会被加到宏任务队列中,Promise等任务会被加到微任务队列中,在优先级上:主线程>微任务队列>宏任务队列。可以通过下面的示例代码理解这个机制:
console.log('start');
setTimeout(function() {
console.log('222');
},0)
new Promise((resolve, reject) => {
console.log('333');
resolve();
console.log('444');
}).then(value => {
console.log('success');
}, reason => {
console.log('fail');
});
console.log('111');
上面代码被执行,首先肯定是先输出start,然后执行了setTimeout函数,这时会把任务加到宏任务队列中,接着又创建了一个Promise对象然后执行其任务,输出333,回调resolve,这时会把任务加到微任务队列中,然后输出444,继续往下执行,输出111,这时主线程的代码都执行完了,就开始轮询事件队列,先取出微任务队列中的所有任务,这里面有刚才的resolve回调,开始执行,输出success,微任务队列的任务都执行完了,继续取宏任务队列中的队头任务,是刚才setTimeout的任务,因此输出222。
所以输出的日志为:start–>333–>444->111->success–>222