重学前端

此文章为《JavaScript重难点实例精讲》的笔记,记录下以往没注意过的一些js小细节。

JavaScript的基本数据类型

Undefined类型

Undefined类型只有一个唯一的字面值undefined,表示的是一个变量不存在。下面是4种常见的出现undefined的场景。

  1. 使用只声明而未初始化的变量时,会返回“undefined”。
1
2
var a;
console.log(a); // undefined
  1. 获取一个对象的某个不存在的属性时,会返回“undefined”。
1
2
3
4
var obj = {
name: 'jack'
}
console.log(obj.age); // undefined
  1. 函数没有明确的返回值时,却在其他地方使用了返回值,会返回“undefined”。
1
2
3
function foo() {
}
console.log(foo()); // undefined
  1. 函数定义时使用了多个形式参数,而在调用时传递的参数的数量少于形参数量,那么未匹配上的参数就为“undefined”。
1
2
3
4
function foo(params, params1, params2) {
console.log(params2); // undefined
}
foo(1, 2)

Null类型

Null类型只有一个唯一的字面值null,表示一个空指针对象,这也是在使用typeof运算符检测null值时会返回“object”的原因。

下面是3种常见的出现null的场景。

  1. 一般情况下,如果声明的变量是为了以后保存某个值,则应该在声明时就将其赋值为“null”。
1
2
3
4
5
6
7
var returnObj = null;
function foo() {
return {
name: 'kingx'
};
}
returnObj = foo();
  1. JavaScript在获取DOM元素时,如果没有获取到指定的元素对象,就会返回“null”。
1
document.querySelector('#id');  // null
  1. 在使用正则表达式进行捕获时,如果没有捕获结果,就会返回“null”。
1
'test'.match(/a/);  // null

Boolean类型

一些隐式转换情况

Object类型转换为Boolean类型

· 当object为null时,会转换为false。
· 如果object不为null,则都会转换为true,包括空对象{}。

Number类型转换为Boolean类型

· 0和NaN会转换为false。
· 除了0和NaN以外,都会转换为true,包括表示无穷大和无穷小的Infinity和-Infinity。

Function类型转换为Boolean类型

任何Function类型的值都会转换为true。

Number类型

一些隐式转换情况

Undefined类型转换为Number类型

Undefined类型只有一个字面值undefined,直接转换为NaN。

String类型转换为Number类型
  1. 只包含数字则会转换为十进制数,如 “0123”转为123
  2. 如果字符串中包含的是有效的浮点数,则同样按照十进制转换,“1.23”转为1.23
  3. 如果字符串中包含有效的十六进制格式,则会按照十进制转换,如“0x3f”会转换为63
  4. 如果是空字符串,则转换为0
  5. 如果字符串中包含了除上述格式以外的字符串,则会直接转换为NaN
Object类型转换为Number类型

如果值为对象类型,则会先调用对象的valueOf()函数获取返回值,并将返回值按照上述步骤重新判断能否转换为Number类型。如果都不满足,则会调用对象的toString()函数获取返回值,并将返回值重新按照步骤判断能否转换成Number类型。如果也不满足,则返回“NaN”。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 以下是通过valueOf()函数将对象正确转换成Number类型的示例
var obj = {
age: 21,
valueOf: function () {
return this.age;
},
toString: function () {
return 'good';
}
};
Number(obj); // 21


// 以下是通过toString()函数将对象正确转换成Number类型的示例
var obj = {
age: '21',
valueOf: function () {
return [];
},
toString: function () {
return this.age;
}
};

Number(obj); // 21
关于Number类型经常遇到的一个面试题

设想这样一个场景,存在一个数组,数组中的每个元素都是Number类型的字符串[‘1’,’2’, ‘3’, ‘4’],如果我们想要将数组中的元素全部转换为整数,我们该怎么做呢?

下意识的是不是想到这样的代码

1
2
3
var arr = ['1', '2', '3', '4'];
var result = arr.map(parseInt);
console.log(result); //  [1, NaN, NaN, NaN]

其实这就是一个藏在map()函数与parseInt()函数中的隐形坑。

1
2
3
4
// 上面的代码等同于如下代码
arr.map(function (val, index) {
return parseInt(val, index);
});

parseInt()函数接收的第二个参数实际为数组的索引值,所以实际处理的过程如下所示

1
2
3
4
parseInt('1', 0);  // 1
parseInt('2', 1); // NaN
parseInt('3', 2); // NaN
parseInt('4', 3); // NaN

任何整数以0为基数取整时,都会返回本身,所以第一行代码会返回“1”。
第二行代码parseInt(‘2’, 1),因为parseInt()函数对应的基数只能为2~36,不满足基数的整数在处理后会返回“NaN”;
第三行代码parseInt(‘3’, 2),表示的是将3处理为二进制表示,实际上二进制时只有0和1,3超出了二进制的表示范围,无法转换,返回“NaN”;
第四行代码parseInt(‘4’, 3),与第三行类似,4无法用三进制的数据表示,返回“NaN”。

1
2
3
4
5
6
// 正确代码
var arr = ['1', '2', '3', '4'];
var result = arr.map(function (val) {
return parseInt(val, 10);
});
console.log(result); // [1, 2, 3, 4]
isNaN()函数与Number.isNaN()函数对比

在判断NaN时,ES5提供了isNaN()函数,ECMAScript 6(后续简称ES6)为Number类型增加了静态函数isNaN()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 使用isNan函数时会进行隐式类型转换
isNaN(NaN); // true
isNaN(undened); // true
isNaN({}); // true
isNaN(true); // false,Number(true)会转换成数字1
isNaN(null); // false,Number(null)会转换成数字0
isNaN(1); // false
isNaN(''); // false,Number('')会转换为成数字0
isNaN("1"); // false,字符串"1"可以转换成数字1
isNaN("JavaScript"); // true,字符串"JavaScript"无法转换成数字
isNaN(new Date()); // false
isNaN(new Date().toString()); // true

// ES6中的Number.isNaN()函数会在真正意义上去判断变量是否为NaN,不会做数据类型转换
Number.isNaN(NaN); // true
Number.isNaN(undened); // false
Number.isNaN(null); // false
Number.isNaN(true); // false
Number.isNaN(''); // false
Number.isNaN(123); // false

String类型

定义字符串有三种方式

  1. 字符串字面量方式,var a = ‘string’
  2. 直接调用String()函数,var a = String(‘hello’)
  3. new String()构造函数,var a = new String(‘hello’)。ps:new运算符生成的字符串是字符串对象。
1
2
3
4
5
6
7
8
9
10
11
12
var str = 'hello';
var str2 = String(str);
var str3 = String('hello');
var str4 = new String(str);
var str5 = new String(str);
var str6 = new String('hello');

str === str2; // true
str2 === str3; // true
str3 === str4; // false
str4 === str5; // false
str5 === str6; // false

基本字符串在作比较时,只需要比较字符串的值即可;而在比较字符串对象时,比较的是对象所在的地址。
str4、str5和str6,因为是使用new运算符生成的String类型的实例,所以在比较时需要判断变量是否指向同一个对象,即内存地址是否相同,很明显str4、str5、str6都是在内存中新生成的地址,彼此各不相同。

为什么采用字面量方式定义的字符串也可以使用indexOf()、substring()、slice()等函数呢?

实际上基本字符串本身是没有字符串对象的函数,而在基本字符串调用字符串对象才有的函数时,JavaScript会自动将基本字符串转换为字符串对象,形成一种包装类型,这样基本字符串就可以正常调用字符串对象的方法了。

引用数据类型

引用数据类型有不同于基本数据类型的特点,具体如下所示:

  1. 引用数据类型的实例需要通过new操作符生成,有的是显式调用,有的是隐式调用
  2. 引用数据类型变量赋值传递的是内存地址
  3. 引用数据类型的比较是对内存地址的比较,而基本数据类型的比较是对值的比较

重学前端
https://xypecho.github.io/2022/11/21/重学前端/
作者
很青的青蛙
发布于
2022年11月21日
许可协议