从本篇开始记录《Javascript重难点实例精讲》,关于Javascript系列预计从这本书出发,接着再通过《Javascript高等程序设计》和阮一峰老师的ES6教程进行完善
本篇为第1章 Javascript重点概念
Javascript数据类型分为基本数据类型和引用数据类型
基本数据类型:
引用数据类型(在第2和第3章再展开):
只有唯一字面值undefined
,表示一个变量不存在
常见场景:
只有唯一字面值null
,表示一个空指针对象,因此使用typeof
检测null
时会返回object
常见场景:
null
null
null
相同点:
boolean
类型时都转为false
TypeError
的异常,也就是平时最常见的引用异常undefined
类型派生自null
类型,所以在非严格相等的情况下,两者是相等的不同点:
null
是JavaScript中的关键字,而undefined
是JavaScript中的一个全局变量,即挂载在window对象上的一个变量,并不是关键字typeof
运算符检测时,undefined
类型的值会返回undefined
,而 null
类型的值会返回object
call
调用toString()
函数时,undefined
类型的值会返回“[object Undefined]”,而null
类型的值会返回“[object Null]”null
会转换为字符串"null"
,而undefined
会转换 为字符串"undefined"
undefined
会转换为NaN
,无法参与计算;null
会转换为0
,可以参与计算undefined
。如果需要定义某个变量来保存将来要使用的对象,应该将其初始化为null
。这样不仅能将null
作为空对象 指针的惯例,还有助于区分null
和undefined
只有两个值true
和false
,注意这是区分大小写的,例如 True 就不行。
Boolean类型使用最多的场景就是用于if语句判断。在JavaScript中,if语句可以接受任何类型的表达式,即if(a)语句中的a,可以是Boolean、Number、String、Object、 Function、Null、Undefined中的任何类型。
如果a不是Boolean类型的值,那么JavaScript解释器会自动调用Boolean()函数对a 进行类型转换,返回最终符合if语句判断的true或者false值。
不同类型与boolean类型的转换:
string
-> boolean
:
""
或者''
-> false
true
number
-> boolean
:
0
和NaN
-> false
infinity
和无穷小-infinity
-> true
object
-> boolean
:
null
-> false
null
,包括空对象{}
-> true
function
-> boolean
:
true
null
-> boolean
:
false
undefined
-> boolean
false
js中的number类型及包括整型数据,也包括浮点型数据
基本采用是十进制,同时也可以通过八进制或十六进制,下面是具体要求和写法:
0
,其他位必须是0~7的八进制序列。如024
就是十进制200x
,其他位是十六进制序列(0~9,a~f或者A~F)。如0x3f
是十进制63boolean
-> number
:
true
-> 1
false
-> 0
null
-> number
:
0
undefined
-> number
:
NaN
string
-> number
:
0
NaN
object
-> number
:
valueOf()
函数,然后通过其返回值按照上述规则进行转换。如果转换的结果是NaN
,则调用 toString()
函数,通过其返回值重新按照上述规则进行转换;如果有确定的number类型返回值,则结束,否则返回NaN
在 JavaScript中将其他类型的值转换为number类型一共有3个函数可以完成,分别是Number()
函数、parseInt()
函数、parseFloat()
函数
Number()函数可以用于将任何类型转换为Number类型,规则如上面 1.2.2 所示
例如
Number('012'); // 12
需要注意的是如果不涉及到其他类型转number类型,而是对数字进行转换,则会按照对应的进制数据格式,同义转换为十进制并返回
Number(10); // 10
Number(010); // 8,010是八进制的数据,转换成十进制是8
Number(0x10); // 16,0x10是十六进制数据,转换成十进制是16
parseInt()
函数用于解析一个字符串,并返回指定的基数对应的整数值。如果该字符串无法转换成number
类型,则会返回NaN
语法格式如下
parseInt(string, radix);
toString()
函数将其转换成字符串,字符串前面的空白符会被忽略。有下面 5 个注意点:
1.传入参数如果是非字符串类型,需要优先转换成字符串类型,即使传入的是整型数据
parseInt('0x12', 16); // 18
parseInt(0x12, 16); // 24
第一条语句直接将字符串"0x12"转换为十六进制数,得到的结果为1×16+2=18;
第二条语句由于传入的是十六进制数,所以会先转换成十进制数18,然后转换成字符串"18",再将字符串"18"转换成十六进制数,得到的结果为1×16+8=24
2.数据截取的前置匹配原则
即从字符串的第一个字符串开始匹配,如果处于基数指定的范围,则保留并继续往后匹配满足条件的字符,直到某个字符不满足基数指定的数据范围,则从该字符开始,舍弃后面的全部字符
例如
parseInt("fg123", 16); //15
如果遇到的字符串以"0x"开头,那按16进制处理时会正常计算,但是按十进制就会是0
parseInt('0x12',16); // 18 = 16 + 2
parseInt('0x12',10); // 0
需要注意的一点是,如果传入的字符串中涉及算术运算,则不执行,算术符号会被当作字符处理;如果传入的参数是算术运算表达式,则会先运算完成得到结果,再参与 parseInt()
函数的计算
parseInt(15 * 3, 10); // 45,先运算完成得到45,再进行parseInt(45, 10)的运算
parseInt('15 * 3', 10); // 15,直接当作字符串处理,并不会进行乘法运算
3.对包含字符e的不同数据的处理差异
当传入的参数本身就是Number类型时,会将e按照科学计数法计算后转换成字符串,然后按照对应的基数转换得到最终的结果。
如果传入的字符串中直接包含e,那么并不会按照科学计数法处理,而是会判断字符 e是否处在可处理的进制范围内,如果不在则直接忽略,如果在则转换成对应的进制数。
parseInt(6e3, 10); // 6000,相当于parseInt('6000', 10)
parseInt(6e3, 16); // 24576,相当于parseInt('6000', 16)
parseInt('6e3', 10); // 6,相当于parseInt('6', 10)
parseInt('6e3', 16); // 1763,相当于6×256 +14×16 + 3 = 1763
4.对浮点型数的处理
如果传入的值是浮点型数,则会忽略小数点及后面的数,直接取整
parseInt('6.01', 10); // 6
parseInt('6.99', 10); // 6
5.map()函数与parseInt()函数的隐形坑
比如想把数组中每个number类型的字符串元素都转为整数,如果使用下面方法就会出问题
var arr = ['1', '2', '3', '4'];
var result = arr.map(parseInt);
console.log(result);
因为
arr.map(parseInt);
实际与下面这个等效
arr.map(function (val, index) {
return parseInt(val, index);
});
实际处理过程是这样
parseInt('1', 0); // 1
parseInt('2', 1); // NaN
parseInt('3', 2); // NaN
parseInt('4', 3); // 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); // [1, 2, 3, 4]
parseFloat()
函数用于解析一个字符串,并返回对应的浮点数。如果给定值不能转换为数值,则会返回NaN
。parseFloat()
函数没有进制的概念。
有下面 4 条注意点:
1.如果在解析过程中遇到了正负号(+ / -)、数字0~9、小数点或者科学计数法 (e / E)以外的字符,则会忽略从该字符开始至结束的所有字符,然后返回当前已经解析的字符的浮点数形式。其中,正负号必须出现在字符的第一位,而且不能连续出现
parseFloat('+1.2'); // 1.2
parseFloat('-1.2'); // -1.2
parseFloat('++1.2'); // NaN,符号不能连续出现
parseFloat('--1.2'); // NaN,符号不能连续出现
parseFloat('1+1.2'); // 1,'+'出现在第二位,不会当作符号位处理
2.字符串前面的空白符会直接忽略,如果第一个字符就无法解析,则会直接返回NaN
parseFloat(' 1.2'); // 1.2
parseFloat('f1.2'); // NaN
3.对于字符串中出现的合法科学运算符e,进行运算处理后会转换成浮点型数。这点与parseInt()
函数的处理有很大的不同。
parseFloat('4e3'); // 4000
parseInt('4e3', 10); // 4
4.对于小数点,只能正确匹配第一个,第二个小数点是无效的,它后面的字符也都将被忽略
parseFloat('11.20'); // 11.2
parseFloat('11.2.1'); // 11.2
Number()
函数转换的是传入的整个值,并不是像parseInt()
函数和parseFloat()
函数一样会从首位开始匹配符合条件的值。如果整个值不能被完整转换,则会返回NaN
。parseFloat()
函数在解析小数点时,会将第一个小数点当作有效字符,而parseInt()
函数在解析时如果遇到小数点会直接停止,因为小数点不是整数的一部分。parseFloat()
函数在解析时没有进制的概念,而parseInt()
函数在解析时会依赖于传入的基数做数值转换。NaN存在的目的:在某些异常情况下保证程序的正常执行。
NaN的 2 个特点:任何涉及NaN的操作都会返回NaN
;NaN与任何值都不相等,包括与NaN本身
判断NaN时,ES5提供了isNaN()
函数,ES6为Number类型增加了静态函数isNaN()
函数----Number.isNaN()
传递的参数如果是number类型数据那很容易判断。
如果传递的参数不是number类型,就比较麻烦。因为isNaN()函数会进行数据的类型转换,它在处理的时候会去判断传入的变量值能否转换为数字,如果能转换成数字则会返回false
,如果无法转换则会返回true
。
NaN
的产生条件:
0 / 0
(其他数除以0会返回infinity
)NaN
,例如1 - 'a' = NaN
下面是一些示例
isNaN(NaN); // true
isNaN(undefined); // true
isNaN({}); //true
isNaN("JavaScript"); // true,字符串"JavaScript"无法转换成数字
isNaN(true); //false,Number(true)会转换成数字1
isNaN(null); //false,Number(null)会转换成数字0
isNaN(1); //false
isNaN(''); //false,Number('')会转换成数字0
isNaN("1"); //false,Number("1")会转换成数字1
// Date类型
isNaN(new Date()); // false
isNaN(new Date().toString()); // true
其中Date类型比较特殊,当我们调用new Date()
函数生成的实例并转换为数值类型时,会转换为对应的时间戳,例如下面的代码
Number(new Date()); //1543333199705
因此isNaN(new Date())
会返回false
而当我们调用了toString()
函数时,返回的是一串字符串表示的时间,无法转换成数值类型,因此isNaN(new Date().toString())
会返回true
ES6中的Number.isNaN()
函数会在真正意义上去判断变量是否为NaN,不会做数据类型转换。只有在传入的值为NaN时,才会返回true
,传入其他任何类型的值时会返回false
isNaN()
函数与Number.isNaN()
函数的差别如下:
isNaN()
函数在判断是否为NaN
时,需要先进行数据类型转换,只有在无法转换为数字时才会返回true
Number.isNaN()
函数在判断是否为NaN
时,只需要判断传入的值
是否为NaN
,并不会进行数据类型转换在JavaScript中,整数和浮点数都属于Number类型,它们都统一采用64位浮点数进行存储。
虽然它们存储数据的方式是一致的,但是在进行数值运算时,却会表现出明显的差异
性。整数参与运算时,得到的结果往往会和我们所想的一样;而对于浮点型运算,有时却会出现一些意想不到的结果
例如
0.1 + 0.2 = 0.30000000000000004
0.7 * 180 = 125.99999999999999
具体原因涉及到计算机中的存储和计算方式,比较复杂而且感觉没必要了解特别清楚就先不在这里赘述
主要思路是将浮点数先乘以一定的数值转换为整数,通过整数进行运算,然后将结果除以相同的数值转换成浮点数后返回
比如 2.1和 3.15 做运算,选其中小数点后位数更多的作为乘数因子,例如 2.1 就是10,3.15就是100,那么就选100。随后两者同时乘以最大乘数因子后再进行运算,最后再除回去
JavaScript中的String类型(字符串类型)既可以通过双引号""
表示,也可以通过单引号''
表示,而且是完全等效的
在程序处理时,我们同样不可避免地会遇到将其他类型转换为String类型的场景。如果是引用类型的数据,则在转换时总是会调用toString()
函数,得到不同类型值的字符串表示;如果是基本数据类型,则会直接将字面值转换为字符串表示形式。
在将某个数据转换为字符串时,有一个简单的方法是直接使用加号+
拼接一个空字符串""
console.log(123 + ''); // '123'
console.log([1, 2, 3] + ''); // '1,2,3'
console.log(true + ''); // 'true'
JS中有3种定义字符串的方式,分别是字符串字面量;直接调用String()
函数;new String()
构造函数
字符串字面量就是直接通过单引号或者双引号定义字符串的方式
var str = 'hello JavaScript'; // 正确写法
var str2 = "hello html"; // 正确写法
直接调用String()
函数,会将传入的任何类型的值转换成字符串类型
转换规则如下:
1.如果是Number
类型的值,则直接转换成对应的字符串
String(123); // '123'
String(123.12); // '123.12'
2.如果是Boolean
类型的值,则直接转换成true
或者false
String(true); // 'true'
String(false); // 'false'
3.如果值为null
,则返回字符串null
String(null); // 'null'
4.如果值为undefined
,则返回字符串undefined
String(undefined); // 'undefined'
5.如果值为字符串,则直接返回字符串本身
String('this is a string'); // 'this is a string'
6.如果值为引用类型,则会先调用toString()
函数获取返回值,将返回值按照上述步骤1~5判断能否转换字符串类型。如果都不满足,则会调用对象的valueOf()
函数获取返回值,并将返回值重新按照步骤1~5判断能否转换成字符串类型,如果也不满足,则会抛出类型转换的异常
new String()
构造函数使用new
运算符生成String类型的实例。
对于传入的参数同样采用和上述String()
函数一样的类型转换策略,最后的返回值是一个String类型对象的实例。
new String('hello JavaScript'); // String {"hello JavaScript"}
使用第一种字符串字面量方式和第二种直接调用String()
函数的方式得到的字符串都是基本字符串;而通过第三种方式,new
运算符生成的字符串是字符串对象
基本字符串在作比较时,只需要比较字符串的值即可;
而在比较字符串对象时,比较的是对象所在的地址。
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
在String对象的原型链上有一系列的函数,例如indexOf()
函数、substring()
函数、slice()
函数等,通过String对象的实例可以调用这些函数做字符串的处理。
但是我们发现,采用字面量方式定义的字符串没有通过new
运算符生成String对象的实例也能够直接调用原型链上的函数
'hello'.indexOf('e'); // 1
'hello'.substring(1); // 'ello'
'hello'.slice(1); // 'ello'
这是因为实际上基本字符串本身是没有字符串对象的函数,而在基本字符串调用字符串对象才有的函数时,JavaScript会自动将基本字符串转换为字符串对象,形成一种包装类型,这样基本字符串就可以正常调用字符串对象的方法了。
eval()
函数会将基本字符串作为源代码处理,如果涉及表达式会直接进行运算,返回运算后的结果;而字符串对象则会被看作对象处理,返回对象本身
var s1 = '2 + 2'; // 创建一个字符串字面量
var s2 = new String('2 + 2'); // 创建一个对象字符串
console.log(eval(s1)); // 4
console.log(eval(s2)); // String {"2 + 2"}
关于算法相关还是主要想参考《代码随想录》进行学习,因此此部分只考虑记录一下相关题目,并不记录具体分析和解决过程。
等后面专门复习算法部分时候,可以再顺便参考原书过一遍这块的相关解法。
在JavaScript中描述了一组用于操作数据值的运算符,包括算术运算符(+
、-
)、关系运算符(>
、<
)、等于运算符(==
、===
)、位运算符(与&&
、 或||
、非!
)等。
由于JavaScript是弱类型语言,因此在运算符的使用上更加灵活,接下来就对其中比较重要的一些运算符进行详细的讲解。
==
在比较时,会将两端的变量进行隐式类型转换,然后比较值的大小===
在比较时,会优先比较数据类型,数据类型相同才去判断值的大小, 如果类型不同则直接返回false
基本规则如上面所说。
额外需要注意的是:
NaN
,则直接返回false
,所以两个NaN
也不能三等于null
或者undefined
,则返回true
;如果只有一方为null
或者undefined
,则返回false
true
,否则返回false
var a = []; var b = a;
var c = [];
console.log(a === b); // true
console.log(a === c); // false
console.log({} === {}); // false
实际上,如果不是通过赋值运算符=
将定义的引用类型的值赋予变量,那么引用类型的值在比较后都会返回false
,所以我们会发现空数组或者空对象的直接比较返回的是false
[] === []; // false
{} === {}; // false
因为它不区分数据类型,而且会做隐式类型转换,所以要稍微复杂些。
下面是一些规则
如果比较的值类型相同,则采用与三等于运算符一样的规则
如果比较的值类型不同,则会按照下面的规则进行转换后再进行比较
null
或者undefined
,只有在另一方是null
或者undefined
的情况下才返回true
,否则返回false
true
,否则返回false
。(需要注意的是,如果字符串是十六进制的数据,会转换为十进制后再进行比较。字符串并不支持八进制的数据,如果字符串以0开头,则0会直接省略,后面的值当作十进制返回)valueOf()
函数或者toString()
函数,将其转换成基本数据类型后再作比较typeof运算符用于返回操作数的数据类型,有以下两种使用形式
1. typeof operand
2. typeof(operand)
operand:表示需要返回数据类型的操作数,可以是引用类型,也可以是基本数据类型。
括号有的时候是必须的,如果不加上括号将会因为优先级的问题得不到我们想要的结果。
下面是typeof
运算符在处理不同数据类型时得到的不同结果
类型 | 结果 |
---|---|
Undefined | “undefined” |
Null | “object” |
Boolean | “boolean” |
Number | “number” |
String | “string” |
Symbol (ES6新增) | “symbol” |
函数对象 | “function” |
任何其他对象 | “object” |
不止是Undefined类型,一共有3种值会返回undefined
:
NaN也是number类型的值,因此typeof(NaN) === 'number'
对于Function类型的数据,可以概括为以下这些值,typeof运算符在处理时会返回function
:
class
关键字定义的类(class是在ES6中新增的关键字,它不是一个全新的概念,原理依旧是原型继承,本质上仍然是一个Function)Math.sin()
函数、Number.isNaN()
函数等new
关键字得到,例如typeof new Function() === 'function'
对于Object类型的数据,可以概括为以下这些值,typeof运算符在处理时会返回object
:
{name: 'kingx'}
[1, 2, 3]
和Array(1, 2, 3)
new
操作符实例化后得到的对象,例如new Date()
、new function(){}
,但是new Function(){}
除外new Boolean(true)
、new Number(1)
,但不推荐这么写typeof运算符的使用在绝大部分情况下都是安全的,但是在ES6以后情况就不一样了。大致有下面 3 种问题需要在使用typeof运算符时进行考虑:
object
)逗号基本有两种用途:
对于第二种用途,如下所示
x = 8 * 2, x * 4
这是一个使用了逗号运算符的语句,首先执行左边的部分,x = 8×2,即x = 16,然后执行右边的语句,x×4 = 16×4 = 64,并将其返回。如果将整个语句赋值给一个 变量y,则该变量y的值为64。
比如:
for (var i = 0, j = 10; i < 10, j < 20; i++, j++)
{ console.log(i, j);
}
需要交换两个变量值时的常规做法如下:
var a = 'a';
var b = 'b';
var c;
c = a;
a = b;
b = c;
如果不使用额外的变量储存,那么下面有 2 种通过,
实现的方案:
var a = 'a';
var b = 'b';
// 方案1
a = [b, b = a][0];
// 方案2
a = [b][b = a, 0];
在方案1中,前一部分[b, b = a]是一个一维数组,数组第二项值是b = a,实际会将 a值赋给b,然后返回“‘a’”,因此数组最终的值为[‘b’, ‘a’],然后取索引0的值为’b’,赋 给变量a,最终实现a = ‘b’, b = ‘a’。
在方案2中,前一部分[b]是一个一维数组,后一部分[b = a, 0],实际会先执行b = a,将a值赋给b,然后返回“0”,因此后一部分实际是修改了b的值并返回索引“0”, 最终是a = [b][0],即a = b,实现了a与b的交换。
比如
if (x) {
foo();
return bar();
} else {
return 1;
}
使用,
简化后
x ? (foo(), bar()) : 1;
在所有的运算符中,逗号运算符的优先级是最低的,因此对于某些涉及优先级的问题,我们需要使用到小括号,将含有逗号运算符的表达式括起来。
例如
var a = 20;
var b = ++a, 10;
console.log(b); // Uncaught SyntaxError: Unexpected number
修改为
var a = 20;
var b = (++a, 10);
console.log(b); // 10
优先级决定了表达式在执行时的先后顺序,其中优先级最高的最先执行,优先级最低的最后执行。
首先可以先列出所有运算符类型,如下所示
1. 一元运算符 (new、delete、typeof、void)
2. 乘除法运算符 (*、/、%、++)
3. 加减法运算符 (+、-)
4. 关系运算符 (<、>、<=、>=、instanceof)
5. 相等运算符 (==、!=、===、!==)
6. 逻辑运算符 (&&、||、!)
7. 条件运算符 (?:)
8. 赋值运算符 (=、+=、-=、*=、/=、%=、<<=、>>=、>>>=)
9. 逗号运算符 (,)
优先级顺序为:
一元运算符 > 乘除法运算符 > 加减法运算符 > 关系运算符 > 相等运算符 > 逻辑运算符 > 条件运算符 > 赋值运算符 > 逗号运算符
在JavaScript中,toString()
函数与valueOf()
函数解决的是值的显示和运算的问题, 所有引用类型都拥有这两个函数。
toString()
函数的作用是把一个逻辑值转换为字符串,并返回结果。
Object
类型数据的toString()
函数默认的返回结果是[object Object]
,当我们自定义新的类时,可以重写toString()
函数,返回可读性更高的结果。
在JavaScript中,Array
,Function
,Date
等类型都实现了自定义的toString()
函数:
Array
的toString()
函数返回值为以逗号分隔构成的数组成员字符串,例如[1,2,3].toString()结果为字符串’1,2,3’Function
的toString()
函数返回值为函数的文本定义,例如(function(x){return x*2;}).toString()的结果为字符串"function(x){return x * 2;}"Date
的toString()
函数返回值为具有可读性的时间字符串,例如,new Date().toString()的结果为字符串"Sun Nov 25 2018 15:00:16 GMT+0800 (中国标准时间)"valueOf()
函数的作用是返回最适合引用类型的原始值,如果没有原始值,则会返回引用类型自身。
Object
类型数据的valueOf()
函数默认的返回结果是"{}",即一个空的对象字面量。
对于Array
、Function
、Date
等类型,valueOf()
函数的返回值:
Array
的valueOf()
函数返回的是数组本身,例如[1, 2, 3].valueOf()返回的结果为“[1,2,3]”Function
的valueOf()
函数返回的是函数本身,例如(function(x){return x * 2;}).valueOf()返回的结果为函数本身“function(x){return x * 2;}”Date
的valueOf()
函数返回的是指定日期的时间戳,例如new Date().valueOf()返回 的结果为“1543130166771”如果一个引用类型的值既存在toString()
函数又存在valueOf()
函数,那么在做隐式转换时,会调用哪个函数呢?
这里我们可以概括成 2 种场景,分别是引用类型转换为String类型,以及引用类型转换为Number类型。
一个引用类型的数据在转换为String类型时,一般是用于数据展示,转换时遵循以下规则:
toString()
函数,则会优先调用toString()
函数。如果它返回的是一个原始值,则会直接将这个原始值转换为字符串表示,并返回该字符toString()
函数,或者toString()
函数返回的不是一个原始值,则会再去调用valueOf()
函数,如果valueOf()
函数返回的结果是一个原始值,则会将这个结果转换为字符串表示,并返回该字符串toString()
函数或者valueOf()
函数都无法获得一个原始值,则会直接抛出类型转换异常一个引用类型的数据在转换为Number
类型时,一般是用于数据运算,转换时遵循以 下规则:
valueOf()
函数,则会优先调用valueOf()
函数,如果valueOf()
函数返回一个原始值,则会直接将这个原始值转换为数字表示,并返回该数字valueOf()
函数,或者valueOf()
函数返回的不是原生数据类型,则会再去调用toString()
函数,如果toString()
函数返回的结果是一个原始值,则会将这个结果转换为数字表示,并返回该数字toString()
函数或者valueOf()
函数都无法获得一个原始值,则会直接抛出 类型转换异常事实上,对除了Date类型以外的引用类型数据转换为原生数据类型时,如果是用于数据运算,则会优先调用valueOf()
函数,在valueOf()
函数无法满足条件时,则会继续调用toString()
函数,如果toString()
函数也无法满足条件,则会抛出类型转换异常。
如果是用于数据展示,则会优先调用toString()
函数,在toString()
函数无法满足条 件时,则会继续调用valueOf()
函数,如果valueOf()函数也无法满足条件,则会抛出类型 转换异常。
一个便捷判断变量是否为空的方法是,对变量取反,然后判断是否为true
if(!x){}
这是一个便捷判断变量是否为空的方法,但是其涉及的场景却很多,这里我们就分多种情况来讨论变量判空的方法:
判断一个变量是否为空时,可以直接将变量与null
或者undefined
相比较,需要注意 双等于==
和三等于===
的区别
if(obj == null) {} // 可以判断null或者undefined
if(obj === undefined) {} // 只能判断undefined
判断一个变量是否为空对象时,可以通过for...in
语句遍历变量的属性,然后调用 hasOwnProperty()
函数,判断是否有自身存在的属性,如果存在则不为空对象,如果不存在自身的属性(不包括继承的属性),那么变量为空对象
// 判断变量为空
function isEmpty(obj) {
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
return false;
}
}
return true;
}
判断变量是否为空数组时,首先需要判断变量是否为数组,然后通过数组的length 属性确定。当以上两个条件都满足时,变量是一个空数组。
arr instanceof Array && arr.length === 0
判断变量是否为空字符串时,可以直接将其与空字符串相比较,或者调用trim()
函数去掉前后的空格,然后判断字符串的长度。当满足以上两个条件中任意一个时,变量是一个空字符串。
str == '' || str.trim().length == 0;
当一个变量为Number类型时,判空即判断变量是否为0
或者NaN
,因为NaN
与任何值比较都为false
,所以我们可以通过取非运算符完成。
!(Number(num) && num) == true;
本小节一开始就讲到 !x 为true时,会包含很多种情况,这里我们一起来总结下:
null
undefined
' '
0
,包括+0
、-0
NaN
基本语法
switch(expression) {
case value1:
statement1;
break;
case value2:
statement2;
break;
default:
statement;
}
JavaScript中的switch特殊的点在于,switch语句可以用来判断任何类型的值,不一定是Number类型。
要注意JavaScript中对于case的比较是采用严格相等===
的!