一、JavaScript基础
1、基本数据类型介绍
所有的编程语言都有数据类型的概念。
在JavaScript中,数据类型可以分为基本数据类型和引用数据类型。其中基本数据类型包括Undefined,Null,Boolean,Number,String5种类型。在ES6中新增了一种基本的数据类型Symbol.
引用类型有Object,Function,Array,Date等。
问题:两种类型有什么区别?
存储位置不同
| 区别 | 基本数据类型 | 引用数据类型 |
|---|---|---|
| 存储位置 | 栈(stack) | 堆(heap) |
| 占据空间 | 小,大小固定 | 大,大小不固定 |
引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
下面我们先来回顾基本数据类型的内容,后面再复习引用类型的内容,以及看一下对应的常见的面试题。
1.1 Undefined类型
Undefined类型只有一个唯一的字面值undefined,表示的含义是一个变量不存在。
问题:哪些场景中会出现undefined?
第一:使用只声明而未初始化的变量时,会返回undefined
var a
console.log(a) //undefined
第二:获取一个对象的某个不存在的属性时,会返回undefined
var obj={
userName:'zhangsan'
}
console.log(obj.age)//undefined
第三:函数没有明确的返回值,却对函数的调用结果进行打印
function fn(){}
console.log(fn()) //undefined
第四:函数定义的时候,使用了多个形参,但是在调用的时候传递的参数的数量少于形参数量,那么没有匹配上的参数就为undefined
function fn(p1,p2,p3){
console.log(p3) //undefined
}
fn(1,2)
1.2 Null类型
Null类型只有一个唯一的字面值null,表示一个空指针的对象,这也是在使用typeof运行符检测null值时会返回object的原因。
问题:哪些场景中会出现null?
第一:一般情况下,如果声明的变量是为了以后保存某个值,则应该在声明时就将其赋值为null
var obj=null
function foo(){
return {
userName:'zhangsan'
}
}
obj=foo();
第二:JavaScript在获取DOM元素时,如果没有获取到指定的元素对象,就会返回null
document.querySelector('#id') //null
第三:在使用正则表达式进行匹配的时候,如果没有匹配的结果,就会返回null
'test'.match(/a/);// null
1.3 Undefined与null比较
Undefined和Null虽然是两种不同的基本数据类型,但是在某些情况也存在相同之处,下面看一下它们两者相同点和不同点。
(1)相同点
第一:Undefined和Null两种数据类型都只有一个字面值,分别是undefined和null.
第二:Undefined和Null类型在转换为Boolean类型的值时,都会转换为false.
第三:在需要将两者转换成对象的时候,都会抛出一个TypeError的异常。
var a;
var b=null;
cosnole.log(a.name);//Cannot read property 'name' of undefined
cosnole.log(b.name);//Cannot read property 'name' of undefined
第四:Undefined类型派生自Null类型,所以在非严格相等的比较下,两者是相等的。如下面代码所示:
null==undefined //true
(2)不同点
第一:null是JavaScript的关键字,而undefined是JavaScript的一个全局变量,也就是挂载在window对象上的一个变量,并不是关键字。
第二:在使用typeof运算符进行检测时,Undefined类型的值会返回undefined.而Null类型的值返回为object
typeof undefined ;//undefined
typeof null ;//object
第三:在需要进行字符串类型的转换时,null会转换成字符串null,而undefined会转换字符串undefined.
undefined+" abc" //"undefined abc"
null+" abc" //"null abc"
第四:在进行数值类型的转换时,undefined会转换为NaN,无法参与计算,而null会转换为0,可以参与计算。
undefined +0;// NaN
null+0 ;// 0
第五:建议:无论在什么情况下都没有必要将一个变量显示的赋值为undefined。如果需要定义某个变量来保存将来要使用的对象,应该将其初始化为null.
1.4 Boolean类型
Boolean类型(布尔类型)的字面量只有两个,分别是true和false,它们是区分大小写的。
Boolean类型使用最多的场景就是用于if语句的判断。在JavaScript中,if语句可以接受任何类型的表达式,即if(a)语句中的a,可以是Boolean,Number,String,Object,Null,Undefined等类型。
如果a不是Boolean类型的值,那么JavaScript解析器会自动调用Boolean( )函数对a进行类型的转换,返回最终符合if语句判断的true或者是false值。
不同类型与Boolean类型的值的转换是Boolean类型的重点。
第一:String类型转换为Boolean类型
空字符都会转换成false,而任何非空字符串都会转换为true
第二:Number类型转换为Boolean类型
0和NaN都会转换为false.而除了0和NaN以外都会转换true.
第三:Object类型转换Boolean类型
如果object为null时,会转换为false,如果object不为null,则都会转换成true.
var obj={}
Boolean(obj) //true
var obj=null
Boolean(obj)//false
第四:Function类型转换Boolean类型
任何Function类型都会转换为true
var fn=function(){
}
Boolean(fn)//true
第五:Null类型转换为Boolean类型,我们知道Null类型只有一个null值,会转换为false.
第六:Undefined类型转换Boolean类型,我们知道Undefined类型只有一个undefined值,会转换为false.
1.5 Number类型
在JavaScript中,Number类型的数据包括了整型数据,也包括了浮点型数据。
我们先来看一下整型的处理。整型可以是十进制,也可以通过八进制或者是十六进制来表示。
第一:八进制:如果想要用八进制来表示一个数值,那么首位必须是0,其它位必须是0--7的数字,如果后面的数字大于7,则破坏了八进制的规则,这时会被当作十进制数来处理。
var num1=024
console.log(num1) //20
var num2=079
console.log(num2) //79
num1第一位是0表示八进制,后面每位数字都是在0--7之间的,所以符合八进制规则,最终转换为十进制为20
num2的第一位也是0,但是最后一位已经超过了7,所以不属于八进制,这里直接作为十进制来处理,最终输出的结果为79.
第二:十六进制:
如果想用十六进制表示一个数值,那么前面两位必须是0x,其它的位必须是(0--9,a--f或者A--F).如果超出了这个范围,则会抛出异常。
var num1=0x5f //95
var num2=Ox5h //Uncaught SyntaxError: Invalid or unexpected token
与Boolean类型一样,当其它类型在与Number类型进行数据转换时,也会遵守一定的规则。
1.5.1 Number类型转换
在实际开发中,我们经常会遇到将其他类型的值转换为Number类型的情况。在JavaScript中,一共有3个函数可以完成这种转换,分别是Number()函数,parseInt( )函数,parseFloat( )函数。下面我们看一下这些函数需要注意的事项。
Number( )函数
Number( )函数可以用于将任何类型转换为Number类型,它在转换时遵循如下规则:
第一:如果是数字,会按照对应的进制数据格式,统一转换为十进制返回。
Number(10) //10
Number(010) // 8, 010是八进制的数据,转换成十进制是8
Number(0x10) // 16,0x10是十六进制的数据,转换成十进制是16
第二:如果是Boolean类型的值,true返回1,false返回是的0
Number(true) //1
Number(false) //0
第三:如果值为null,则返回0
Number(null) //0
第四:如果值为undefined,则返回NaN
Number(undefined) //NaN
第五:如果值为字符串类型,需要遵循如下规则
(1)如果该字符串只包含了数字,则会直接转换成十进制数;如果数字前面有0,则会直接忽略掉这个0。
Number('21') //21
Number('012') //12
(2) 如果字符串是有效的浮点数形式,则会直接转成对应的浮点数,前置的多个重复的0会被删除,只保留一个。
Number('0.12') //0.12
Number('00.12') //0.12
(3)如果字符串是有效的十六进制形式,则会转换为对应的十进制数值
Number('0x12') //18
(4) 如果字符串是有效的八进制,则不会按照八进制转换,而是直接按照十进制转换并输出,因为前置的0会被直接忽略掉。
Number('010') //10
Number('0020') //20
(5)如果字符串为空,即字符串不包含任何字符,或为连续多个空格,则会转换为0.
Number('') //0
Number(' ')//0
(6)如果字符串中包含了任何不适以上5种情况的其它格式内容,则会返回NaN
Number('123a') //NaN
Number('abc') //NaN
第六:如果是对象类型,则会调用对象的valueOf( )函数获取返回值,并且判断返回值能否转换为Number类型,如果不能,会调用对象的toString( )函数获取返回值,并且判断是否能够转换为Number类型。如果也不满足,则返回NaN.
以下是通过valueOf( )函数将对象转换成Number类型。
var obj={
age:'12',
valueOf:function(){
return this.age
},
}
Number(obj) //12
以下是通过toString( )函数将对象转换成Number类型。
var obj={
age:'21',
toString:function(){
return this.age
}
}
Number(obj)
parseInt( )函数
parseInt()函数用于解析一个字符串,并返回指定的基数对应的整数值。
语法格式:
parseInt(string,radix)
其中string参数表示要被解析的值,如果该参数不是一个字符串,那么会使用toString( )函数将其转换成字符串。并且字符串前面的空白符会被忽略。
radix表示的是进制转换的基数,可以是二进制,十进制,八进制和十六进制。默认值为10.
因为对相同的数采用不同进制进行处理时可能会得到不同的结果,所以在任何情况下使用parseInt函数时,建议都手动补充第二个参数。
parseInt( )函数会返回字符串解析后的整数值,如果该字符串无法转换成Number类型,则会返回NaN.
parseInt('aaa')//NaN
在使用parseInt函数将字符串转换成整数时,需要注意的问题:
第一:如果遇到传入的参数是非字符串类型的情况,则需要将其优先转换成字符串类型。即使传入的是整型数据。
第二:parseInt( )函数在做转换时,对于传入的字符串会采用前置匹配的原则。
parseInt("fg123",16)
对于字符串fg123,首先从第一个字符开始,f是满足十六进制的数据的,因为十六进制数据的范围是0--9,a--f,所以保留f,然后是第二个字符g,它不满足十六进制数据范围,因此从第二个字符都最后一个字符全部舍弃,最终字符串只保留了字符f,然后将字符f转换成十六进制的数据,为15,因此最终返回的结果为15.
还要注意的一点就是,如果传入的字符串中涉及到了算术运算,则不会执行,算术符号会被当作字符处理。
parseInt('16*2')// 16,这里直接当作字符串处理,并不会进行乘法的运算
parseInt(16*2) // 32
第三:对浮点数的处理
如果传入的值是浮点数,则会忽略小数点以及后面的数,直接取整。
parseInt(12.98) //12
第四:map( )函数与parseInt( )函数的问题
我们这里假设有一个场景,存在一个数组,数组中的每个元素都是数字字符串,['1','2','3','4'],如果将这个数组中的元素全部转换成整数,应该怎样处理呢?
这里我们可能会想到使用map( )函数,然后在该函数中调用parseInt( )函数来完成转换。所以代码如下:
<script>
var arr = ["1", "2", "3", "4"];
var result = arr.map(parseInt);
console.log(result);
</script>
执行上面程序得到的结果是:[1,NaN,NaN,NaN]
为什么会出现这样的问题呢?
上面的代码等效如下的代码
var arr = ["1", "2", "3", "4"];
// var result = arr.map(parseInt);
var result = arr.map(function (val, index) {
return parseInt(val, index);
});
console.log(result);
通过以上的代码,可以发现,parseInt函数第二个参数实际上就是数组的索引值。所以,整体的形式如下所示:
parseInt('1',0) // 任何整数以0为基数取整时,都会返回本身,所以这里返回的是1
parseInt('2',1) //注意parseInt第二个参数的取值范围为2--36,所以不满足条件,这里只能返回NaN
parseInt('3',2) // 表示将3作为二进制来进行处理,但是二进制只有0和1,所以3超出了范围,无法转换,返回`NaN`
parseInt('4',3) //将4作为三进制来处理,但是4无法用三进制的数据表示,返回NaN
所以当我们在map( )函数中使用parseInt( )函数时,不能直接将parseInt( )函数作为map( )函数的参数,而是需要在map( )函数的回调函数中使用,并尽量指定基数。代码如下所示:
var arr = ["1", "2", "3", "4"];
var result = arr.map(function (val) {
return parseInt(val, 10);
});
console.log(result);