JavaScript数据类型,类型转换和类型判断
数据类型
- 原始类型:
Number、String、Boolean、Null、Undefined、Symbol、BigInt - 引用类型:
Object
引用数据类型可统称为一种,在JS中万物皆对象,除了基本数据类型其他都是对象。数组是对象、函数是对象、正则表达式也是对象。如Function、Array、Date等都是基于Object的。
基本数据类型
基本数据类型的主要特点是赋值方式是传值,并且值存在 栈 中。
由操作系统自动分配释放存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈;
| 数据类型 | 实例 | 说明 |
|---|---|---|
| Number | 12,-1,17.23,3.1E-2 |
数值型数据 |
| BigInt | 12n,-2n,0n |
表示任意精度格式的整数,BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。 |
| String | "message",“str”,“name” |
字符型数据,需加英文双引号或单引号或反引号 |
| Boolean | true, false |
布尔型数据,不用加引号,表示逻辑真与假 |
| Undefined | undefined |
JavaScript中未定义的值 |
| Null | null |
表示空值 |
| Symbol | let var_symbol = Symbol(); let var_symbol = Symbol.for('symbol'); |
Symbol 指的是独一无二的值。每个通过 Symbol() 生成的值都是唯一的。可以防止命名冲突 |
Number
Number型数据即为数值型数据用来表示整数和浮点数,分为正数、负数、小数等。
整数型数值可以使用十进制、八进制以及十六进制标识
- 十进制:直接使用数字表示,例如:
123、456等。 - 八进制:以
0开头,例如:010、077等。 - 十六进制:以
0x或0X开头,例如:0xFF、0x3F等。
1 | let numn1=1; //十进制,输出值为1 |
注意: 当你在JavaScript中使用八进制或十六进制数值时,它们会被自动转换为十进制表示。例如,010会被解释为十进制的8,但是081会被解释成81(因为8进制里面没有8) ,0xFF会被解释为十进制的255。
浮点数是指包含小数点的实数,且可用科学计数法来表示。科学计数法一般用于值极大或者极小的时候。
1 | //Number--浮点数 |
如果浮点数看起来是整数, JavaScript会 自动将浮点数转换为整数。原因是JavaScript总是希望使用更少的内存,因为浮点数使用的内存是整数值的两倍。
范围: Number类型只能表示$-(2^{53}-1)到(2^{53}-1)$ 之间的值
Number.MIN_VALUE的值为5e-324,这是 Number 类型能够表示的最接近于零的正数。这意味着任何小于 5e-324 的正数都会被 JavaScript 解释为 0。Number.MAX_VALUE的值为1.7976931348623157e+308,这是 Number 类型能够表示的最大值。这意味着任何大于 1.7976931348623157e+308 的数值都会被 JavaScript 解释为 Infinity。- 当数值范围超过最大值或最小值时,可以使用
Infinity和-Infinity来表示无限数
1 | //Number.MIN_VALUE和Number.MAX_VALUE |
特殊的Number类型:
Infinity- 当一个数太大,以至于无法用
Number.MAX_VALUE表示时,JavaScript 会返回Infinity。 - 当一个正数除以0时,结果为
Infinity。 - 使用
Number.POSITIVE_INFINITY可以访问这个值。例如:1 / 0返回Infinity。
- 当一个数太大,以至于无法用
-Infinity- 当一个数太小,以至于无法用
Number.MIN_VALUE表示时,JavaScript 会返回-Infinity。 - 当一个负数除以0或一个正数除以
-0时,结果为-Infinity。 - 使用
Number.NEGATIVE_INFINITY可以访问这个值。例如:-1 / 0返回-Infinity。
- 当一个数太小,以至于无法用
NaN(虽然 Not a Number,但是是Number类型)- 表示值不是数字(Not a Number) 。他是一个特殊的数值,表示无效数字。当一个操作或计算机结果不是一个有效的数字时,JavaScript会返回
NaN - 任何与NaN的运算都会返回NaN
- NaN不等于任何值,包括其本身
- 表示值不是数字(Not a Number) 。他是一个特殊的数值,表示无效数字。当一个操作或计算机结果不是一个有效的数字时,JavaScript会返回
BigInt
BigInt 类型的数据必须添加后缀n。
BigInt数据类型提供了一种方法来表示大于$2^{53}-1$的整数。BigInt可以表示 任意大的整数(不能表示小数) 。
Number类型只能安全的支持$-9007199254740991(-(2^{53}-1))$ 和 $9007199254740991(2^{53}-1)$之间的整数,任何超过这个范围的数值都会失去精度;而BigInt可以解决这个问题
- 在整数的末尾追加n:
console.log(9007199254740999n); //9007199254740999 - 调用
BigInt()构造函数:1
2let bigInt = BigInt("9007199254740999");
//传递给BigInt()的参数将自动转换为BigInt 9007199254740999n
注意:
- BigInt 除了不能使用一元加号运算符外,其他的运算符都可以使用
- BigInt 和 Number 之间不能进行混合操作
String
字符串是零个或多个字符的序列。JavaScript不区分单个字符和字符串,任何字符或字符串以英文单引号('')或双引号("")开头和结尾。
JavaScript字符串是不可变的,意味着一旦被创建就无法修改。
- 以双引号开头的字符串必须是双引号结尾,以单引号开头的字符串也必须是单引号结尾,以什么引号开头就以什么引号结尾
- 无论单引号或是双引号必须成对使用
- 单引号/双引号可以互相嵌套,但是不以自已嵌套自已(单套双或双套单)
- 必要时可以使用转义符 `` ,输出单引号或双引号
| 转义字符 | 描述 |
|---|---|
\b |
退格符 |
\f |
换页符 |
\n |
换行符 |
\r |
回车符 |
\t |
制表符(Tab) |
\v |
垂直制表符 |
' |
单引号 |
" |
双引号 |
| `` | 反斜杠 |
Boolean
boolean型数据表示的是布尔型数据,它有两个固定的值 true 和 false,表示肯定的数据用 true,表示否定的数据用 false,且任何时刻都只能使用两种状态中的一种,不能同时出现。
注意: Boolean型变量赋值时,不能在 true 或 false 外面加引号,否则就变成字符串(string)了
Undefined
Undefined型是未定义类型,未定义是比较特殊的类型,只有一个值 undefined。默认情况下,当声明变量时但未赋值的情况下,变量的默认值为 undefined。JavaScript 中变量的值决定了变量的数据类型。( Undefined是一种数据类型,只有一个值undefined )
1 | // 只声明了变量,并末赋值 |
Null
Null型数据表示空值,作用是表明数据空缺的值,只有一个值null。一般在设定已存在的变量(或对象的属性)为空时较为常见。(Null是一种数据类型,只有一个值null)
注意: console.log(null == undefined) 结果是true
Symbol
Symbol 本质上是一种唯一标识符,可用作对象的唯一属性名,这样其他人就不会改写或覆盖你设置的属性值。在创建symbol类型数据 时的参数只是作为标识使用,所以 Symbol() 也是可以的。
- 声明:
let id = Symbol('id') - 即使是用同一个变量(标识)生成的值也不相等:
- 隐藏性,
for···in和object.keys()不能访问 - 但是也有能够访问的方法:
Object.getOwnPropertySymbols, 该方法会返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。
1 | let id = Symbol("id"); |
- 全局注册并登记的方法:
Symbol.for():有时候希望能够多次使用同一个symbol值的情况。
1 | let name1 = Symbol.for('name'); //检测到未创建后新建 |
- 通过symbol对象获取到参数值:
Symbol.keyFor()
1 | let name1 = Symbol.for('name'); |
引用数据类型
堆(heap):用来保存栈中简单数据字段对指针的引用
存储复杂类型,一般由程序员分配释放,若程序员不释放,由垃圾回收机制 回收;
复杂数据类型引用放在栈里面,实际数据存放到堆里面。
ObjectArrayFunctionDateRegExpMapSetWeakMapWeakSetPromiseErrorBlobFileArrayBuffer- . . .
包装类型
在JavaScript中,一些操作并不直接适用于原始类型的值,而是需要将它们转换为相应的对象。这就引入了”包装类”的概念。这些包装类是由JavaScript自动创建的临时对象,用于实现对原始值进行操作。
一般来说,有三种包装类:
Number、String和Boolean。当我们使用原始数据类型调用相关属性或方法时,JavaScript会 自动将 其转换为相应的包装对象,以便于对其进行操作。
所有的包装类都有 valueOf() 和 toString() 方法,除了Math 和 Error 对象没有valueOf方法
包装类才有组包与拆包
组包与拆包
组包是由简单变复杂,拆包是由复杂变简单。
组包
基本数据类型 转成 引用数据 类型
- 显式组包:
new 包装类() - 隐式组包:
1 | let test=1; |
拆包
引用数据 类型 转成 基本数据 类型
调用
包装类.valueOf()
隐式组包 和 隐式拆包:
let test = 1; test.toString(); // '1' 组包 test = new Number(test);typeof test;// number 隐式拆包了
显式组包 和 显式拆包:
test = new Number(test);// 显式组包test = test.valueof();//显式拆包
Boolean
toString()方法返回指定的布尔对象的字符串形式。
1 | let flag1 = new Boolean(true); |
valueOf()方法返回一个Boolean对象的原始值
1 | let x = new Boolean(); |
Number
一些方法和Global上的方法功能一样,一般都是用Global上的方法即可。
1 | //例如: Number.parseInt() 、Number.parseFloat() |
String
String包装类 隐式 或 显式 组包以后可以使用一些String原型上的一些api:
charAt(index)方法从一个字符串中返回指定的字符。index默认为0index大于字符串总长度,返回空字符串
indexOf(searchValue[, fromIndex])查找字符串中是否存在某个字符串,并返回所在索引 。fromIndex默认为0,从某个位置开始查找- 如果未找到该值,则返回-1
lastIndexOf和indexOf类似,是查找最后一次出现的索引位置slice(begin[, end])方法提取一个字符串的一部分,并返回一新的字符串。begin开始位置end结束位置,默认值是从begin一直到字符串结束
concat将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。toUpperCase()将调用该方法的字符串值转换为大写形式,并返回。toLowerCase()会将调用该方法的字符串值转为小写形式,并返回。trim()方法会从一个字符串的两端删除空白字符
类型转换
JS中只存在 三种 类型转换
- to string
- to boolean
- to number
然后具体到不同的数据类型向这三种类型转换,如原始数据类型(string, number, boolean, undefined, null) 和引用数据类型(object)
按转换类型划分
其他类型转成Number
| 数据类型 | 转为值 |
|---|---|
| String | 纯数字的字符串转为对应的数字,空字符串和空格字符串是0,其他字符变成NaN |
| Boolean | true为1,false为0 |
| Object | 调用valueOf()的返回结果,没有则返回toString()结果,若对象没有valueOf()和toString()则返回NaN |
| null | 返回0 |
| undefined | 返回NaN |
Number([])返回0,Number([3])返回3,Number([1, 2])返回NaN。
显式转换
Number():可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回 NaNparseInt()/parseFloat():parseFloat会解析第一个.遇到第二个.或者非数字结束,如果解析的内容里只有整数,解析成整数
1 | let a = '12.3px' |
隐式转换
isNaN() 函数用于判断是否是一个非数字类型
-,*,/,%,**(除了+)都可以将其他类型在和数字进行运算时转成数字类型
1 | console.log('2' - 1) // 1 |
- +和-(-转过来是负的) 都可以把其他类型(尤其是字符串)转成数字类型
1 | console.log(+'21') // 21 |
其他类型转成String
| 数据类型 | 转为值 |
|---|---|
| Number | 转为对应数字的字符串形式,NaN 是“NaN” |
| Boolean | true为"true",false为"false" |
| Object | 返回toString()的返回值,默认是“[object Object]” |
| null | 返回"null" |
| undefined | 返回"undefined" |
显式转换
- toString(), 注意,不可以转
null和underfined,但NaN可以转:NaN.toString()结果是'NaN' - String(),都可以转
隐式转换
- 用“字符串(通常是空字符串)
+”拼接,如:12+''会转成字符串'12'
其他类型转成Boolean
| 数据类型 | 转为true的值 | 转为false的值 |
|---|---|---|
| Number | 任何非零数字(包括无穷大) | 0、-0和NaN |
| String | 任何非空字符 | “”(空字符串) |
| Object | 任何对象 | 无 |
| null | 无 | null |
| undefined | 无 | undefined |
转为false的:
""空字符串0 || -0 || 0n各种0nullundefinedNaN
其余都是true,注意
'0','<一到多个空格>'也是true哦,它们不是空字符串。
显式转换
Boolean():都可以转,包括null,undefined,NaN(这三个都是false)!!:经过两次取反可以将一个值转成布尔类型。如!!null的结果是false
隐式转换
在if,while,逻辑运算符或逻辑判断时会自动转成Boolean。
显式转换
to string的原始类型转换
- toString(), 注意,不可以转
null和underfined,但NaN可以转:NaN.toString()结果是'NaN'
1 | console.log(1..toString()) // '1' |
- String(),都可以转
1 | console.log(String(1)) // '1' |
to number的原始类型转换
| 原始类型 | 类型转换规则 |
|---|---|
| string | (""空字符串, "<空白符>", "<多个空白符>") -> 0 ; "number"纯数字字符串 -> number; "<16进制数>" -> <16 进制数> -> 十进制数; 其他字符串 → NaN |
| number | 无需转换(NaN->NaN) |
| boolean | true -> 1, false -> 0 |
| null | 0 |
| undefined | NaN |
Number():可以把任意值转换成数值,如果要转换的字符串中有一个不是数值的字符,返回 NaNparseInt()/parseFloat():parseFloat会解析第一个.遇到第二个.或者非数字结束,如果解析的内容里只有整数,解析成整数
to boolean的原始类型转换
转换为false
""0||-0||0nnullundefinedNaN
转换为
true- 非空字符串
- 非
0和非NaN的数值
对象 to {string, number, boolean}的 To Primitive类型转换
在ES5版本, 当我们显式或者隐式地将对象转换为原始值(primitive value)的时候, 通常是默认调用对象自身或者原型链上的toString() 或者valueOf() 方法, 将其转换原始值. 或者可以自定义覆盖对象的这两个方法来控制对象的to primitive行为, 不过不建议这样做.
ES6 为开发者提供了官方的
[Symbol.toPrimitve]接口来自定义对象的to primitive操作, 当对象发生显式或者隐式类型转换操作的时候, 会自动调用其预先定义的[Symbol.toPrimitive]方法, 同时会忽略对象自身的toString()和valueOf()方法.
toString()和valueOf()方法, 这两个方法可以自定义,也可以是原型方法.。一些JavaScript的内置对象会有自己的内置toString()和valueOf()方法, 位于其原型上, 汇总如下:
| 类型 | toString | valueOf |
|---|---|---|
| object | “[object <type>]“ |
指向自身 |
| function | 函数的字符串形式 | 指向自身 |
| array | “arr[0], arr[1], ...“ 或者 ""(数组为空) |
指向自身 |
| date | 包含本地时间信息的字符串 | 从1970年 1 月 1 日开始至今的毫秒数 |
| regexp | 正则表达式的字符串表示形式 | 指向自身 |
| error | 错误名+错误信息: “<err>.name:<err>.message“ |
指向自身 |
总结:只有Date重写了自身的valueOf()方法,其余都是返回自身。除了Number、Boolean、String、Array、Date、RegExp、Function这几种实例化对象之外,其他对象返回的都是该对象的类,都是继承的Object.prototype.toString方法。
1 | let obj = new Object({}); |
对象 to boolean
一般情况下, 对象to boolean都是直接转换为 true , 而且不会调用对象的 [Symbol.toPrimitive], toString, valueOf 这三个方法。
注意: document.all对象在浏览器中转为布尔值的时候为false, 这是一种极特殊情况,在vscode中使用这个对象的时候,会提示已经被弃用了,了解即可。
对象to string | number
ES5时的转换方式
在ES5的时候, 对象的类型转换是通过内置或者自定义的toString, valueOf 方法进行to primitive类型转换的。
对象to string
调用对象的
toString()方法:首先,尝试调用对象的toString()方法。检查
toString()的返回值:- 如果
toString()方法返回一个原始值(如字符串、数字、布尔值等),则将这个原始值用作对象的字符串表示形式。 - 如果
toString()方法返回一个对象,那么程序将进入下一步。
- 如果
调用对象的
valueOf()方法:如果toString()方法返回一个对象,则尝试调用对象的valueOf()方法。检查
valueOf()的返回值:- 如果
valueOf()方法返回一个原始值,那么这个原始值将被用作对象的字符串表示形式。 - 如果
valueOf()方法返回一个对象,那么JavaScript将会抛出一个错误,因为无法将对象转换为字符串。
- 如果
总结来说,对象到字符串的转换遵循以下顺序:
- 调用对象的
toString()方法。 - 如果
toString()返回原始值,使用该值。 - 如果
toString()返回对象,调用对象的valueOf()方法。 - 如果
valueOf()返回原始值,使用该值。 - 如果
valueOf()返回对象,抛出错误。
对象to number
顺序和对象to string相反。
调用对象的
valueOf()方法:首先,尝试调用对象的valueOf()方法。检查
valueOf()的返回值:- 如果
valueOf()方法返回一个原始值(如字符串、数字、布尔值等),则将这个原始值用作对象的数字表示形式。 - 如果
valueOf()方法返回一个对象,那么程序将进入下一步。
- 如果
调用对象的
toString()方法:如果valueOf()方法返回一个对象,则尝试调用对象的toString()方法。检查
toString()的返回值:- 如果
toString()方法返回一个原始值,那么这个原始值将被用作对象的数字表示形式。 - 如果
toString()方法返回一个对象,那么JavaScript将会抛出一个错误,因为无法将对象转换为数字。
- 如果
总结来说,对象到数字的转换遵循以下顺序:
- 调用对象的
valueOf()方法。 - 如果
valueOf()返回原始值,使用该值进行原始值到数字的转换。 - 如果
valueOf()返回对象,调用对象的toString()方法。 - 如果
toString()返回原始值,使用该值进行原始值到数字的转换。 - 如果
toString()返回对象,抛出错误。
ES6的转换方式
在ES6, 开发者可以通过官方提供的
[Symbol.toPrimitive]接口去定义对象 to primitive 的行为。 需要注意的是, 如果自定义了对象的[Symbol.toPrimitive]的方法, 那么, 当对象发生 to primitive类型转换的时候, 那么只会调用[Symbol.toPrimitive]方法, 而无视ES5中提供的toString(),valueOf()方法。
比如下面将对象显式转换为string的代码中, 只有 [Symbol.toPrimitive]() 会被调用:如果返回结果为对象, 则直接报错(不会去调用toString或者是valueOf方法); 如果返回结果为原始值, 则将将该原始值进行to string操作, 作为最终的对象 to primitive结果:
1 | const obj = { |
隐式转换
对于某些运算符, 当A
- 宽松相等运算符
==,!= - 关系运算符(
>,<,<=,>=) - 逻辑运算符(
&&,||,!) if,while,for,? :+ (condition)中的条件表达式(condition)- 加性运算符
+ - 算数运算符(
-,*,/,%) - 一元
+,-操作
一元加号,减号
+即强制转换为Number类型。直接参考显示类型转换中的to number-与+类似,不过会将结果取负号
1 | +"1" // 1 |
加法
在求值时,它首先将两个操作数强制转换为基本类型。然后,检查两个操作数的类型:
- 如果有一方是字符串,另一方则会被转换为字符串,并且它们连接起来。
- 如果双方都是
BigInt,则执行BigInt加法。如果一方是BigInt而另一方不是,会抛出TypeError。 - 否则,双方都会被转换为数字,执行数字加法。
1 | 1 + "1" // "11" |
减法
减法不涉及字符串拼接,故需要都转换为Number类型。
- 如果有一个操作数为
string,boolean,null,undefined中一种,则在后台调用Number()将其转化为数值,再进行减法运算。 - 如果有一个操作数是对象 ,则调用对象的
valueOf()方法取得表示该对象的数值。如果得到的值是NaN,减法结果是NaN。如果对象没有valueOf()方法,调用它的toString()方法,并将得到的字符串转化为数值。 (参考上文一元加号的运算法则)
1 | []-1 //-1 过程[]->''->0 即相当于 0-1 |
相等判断
==相等
注意:特例NaN不等于自身
ECMAScript® 2023 Language Specification (ecma-international.org) 对于==的规定:
若
Type(x)与Type(y)相同,则进行严格相等 (===) 的比较。若
x为null且y为undefined,返回true。若
x为undefined且y为null,返回true。这里只需记住
document.all与null或undefined,返回true即可。若
Type(x)为Number且Type(y)为String,返回比较x == ToNumber(y)的结果。若
Type(x)为String且Type(y)为Number,返回比较ToNumber(x) == y的结果。若
Type(x)为String且Type(y)为BigInt:- 使用与
BigInt()构造函数相同的算法将字符串转换为BigInt。如果转换失败,返回false,然后再进行比较。
- 使用与
和第7步类似(顺序交换即可):
- 若
Type(x)为BigInt且Type(y)为String,尝试将字符串y转换为BigInt,转换成功则比较两个BigInt值。
- 若
若
Type(x)为Boolean,返回比较ToNumber(x) == y的结果。若
Type(y)为Boolean,返回比较x == ToNumber(y)的结果。若
Type(x)为String或Number,且Type(y)为Object,返回比较x == ToPrimitive(y)的结果。若
Type(x)为Object且Type(y)为String或Number,返回比较ToPrimitive(x) == y的结果。BigInt与Number类型比较:
a. 如果Number类型的值为无穷值(Infinity或-Infinity),直接返回false。
b. 如果两个值转换为数学上的值相同,返回true。(数学上-0与+0均为0)返回
false。
===全等
类型必须相同。
NaN不等于自身。
1 | null == undefined //true |
Object.is()
全等的缺陷:NaN === NaN //false,-0 === +0 //true
1 | Object.is(NaN,NaN) //true |
Object.is() 与===的区别:
- 处理 0 的特殊情况:如果
a或b严格等于0,函数会检查1/a是否等于1/b。这是因为1/0的结果是Infinity,而1/-0的结果是-Infinity,这可以区分+0和-0。 - 处理 NaN 的特殊情况:如果
a和b都不等于它们自己(这是 NaN 的一个特性),则函数返回true,表示两个值都是NaN。 - 一般比较:如果上述两种特殊情况都不满足,函数使用
===运算符进行比较,这是一种严格相等的比较。
1 | //实现Object.is() |
面试题
题目一
console.log([] == !{})结果是?
!运算符优先级高于==,故先进行!运算。!{}运算结果为false,结果变成[] == false比较。- 根据4.1中的规则(引用类型与基本类型比较),等式左边
ToPrimitive([]) == ''。按照上面规则进行原始值转换,[]会先调用valueOf函数,返回this。不是原始值,继续调用toString方法,x = [].toString() = ''。 故结果为'' == 0比较。 - 等式左边为
string,右边为number,等式左边x = ToNumber('') = 0。所以结果变为:0 == 0,打印true,比较结束。
题目二
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;result的结果是?
1 | //拆解 |
题目三
1 | let arr= [] |
知识点1:在js中,数组底层也是通过键值对存储的。当我们以索引形式为数组添加元素时,会发生以下过程。自动将传入的索引值转换为CanonicalNumericIndexString (规范数字索引字符串)
- 将索引转换为数值类型
- 再将索引转换为字符串类型
- 最终添加至数组
故
arr[0]与arr["0"]事实上等价知识点2:数组也是一个对象,可以添加属性。数组的索引范围为 $[0,2^{32}-1)$ ,而向对象中添加属性时,若不在此范围,就相当于向其身上添加属性。
在JavaScript中,数组的索引通常是数字,并且它们被用来按顺序存储元素。然而,JavaScript对象(包括数组)的键(即索引)可以是字符串或任何值,只要它能够被转换为字符串(除了
undefined),这就意味着你可以使用非数字的键来设置数组的元素。
let arr = [];这行代码创建了一个空数组arr。arr[0] = 1;这里将数字1赋值给数组的第一个元素,使用数字0作为索引。arr["0"] = 2;这行代码将数字2赋值给数组的第二个元素,使用字符串"0"作为索引。在JavaScript中,字符串索引和数字索引是等价的,所以这实际上是创建了数组的第二个元素。arr["1"] = 3;这里将数字3赋值给数组的第三个元素,使用字符串"1"作为索引。同样,字符串索引会被转换为数字索引。arr[-1] = 4;这行代码将数字4赋值给数组的一个特殊索引-1。在大多数情况下,数组的索引不能为负数,但在这里,由于使用了方括号语法,JavaScript 允许将任何值(包括负数)作为索引。这将创建一个索引为-1的属性,但它不是数组的常规索引,并且不会影响数组的length属性。arr[{}] = 5;这行代码尝试将数字5赋值给一个对象作为索引。在JavaScript中,对象作为索引时会被转换为字符串[object Object],因此这将创建一个非数字索引的属性,其值为5。- 最终,当你打印
arr时:console.log(arr);
你将得到一个包含多个元素和属性的数组对象,其中一些是数组的索引,一些是对象的属性。数组的 length 属性将反映其索引数组的长度,即 [0, 3]。这是因为 arr["0"] 和 arr[0] 引用相同的位置,而 arr["1"] 会创建一个新的索引为 1 的元素,使得数组长度变为 2。arr[-1] 和 arr[{}] 不会影响数组的 length,但它们会被添加为对象的属性。
请注意,数组的 length 是 2,因为只有索引 0 和 1 被赋值,而 -1 和 {} 创建的是非标准索引,它们不会出现在数组的索引序列中,但作为对象属性存在。
类型判断
typeof
typeof是一元运算符,可以用来返回一个变量或表达式的数据类型。它可以准确地判断除null之外的原始类型,并且可以判断function类型。
但是没法用来区分引用数据类型的,因为所有的引用数据类型都会返回”object” 。
注意: null 、 NaN 、 document.all 的判断
1 | console.log(typeof "hello"); // 输出: "string" |
instanceOf
语法:obj instanceof Type
判断 obj 是不是 Type 类的实例 ,只可用来判断引用数据, 右操作数必须是函数或者 class
用于判断一个对象是否是某个构造函数(或其子类)的实例,只能判断引用类型。它通过原型链的查找来判断对象的类型。
手写instanceOf :
1 | function myInstanceof(Fn, obj) { |
1 | let arr = [1, 2, 3]; |
Object.prototype.toString.call()
利用函数动态 this 的特性。
Object.prototype.toString()方法可以返回一个对象的字符串表示形式。它会读取数据结构内部属性来读取数据的类型 class。通过调用call() 方法,可以改变toString() 中this的指向,使其返回 "[object 类型]" 的形式,其中 类型可以是任意数据类型。
1 | Object.prototype.toString.call(123); // "[object Number]" |
constructor
constructor 作用和 instanceof 非常相似。但 constructor 检测 Object 与 instanceof 不一样,还可以处理 基本数据类型 的检测。
constructor 指向创建 该实例对象的构造函数
注意: null 和 undefined 没有 constructor,以及 constructor 可以被改写,不太可靠
1 | const arr = [1, 2, 3]; |
isxxx
isPrototypeof()
用于判断一个对象是否为另一个对象的原型。
prototypeObj.isPrototypeOf(object),如果 prototypeObj 是 object 的原型对象,isPrototypeOf 方法返回 true,否则返回 false
功能基本等同于 instanceof
注意:isPrototypeOf 方法只能用于判断对象类型,不能用于判断基本数据类型。如果 prototypeObj 不是一个对象,isPrototypeOf 方法会抛出 TypeError 异常。
1 | const obj = { name: "云牧", age: 18 } |
getPrototypeOf()
getPrototypeOf() 返回一个对象的原型,只能用于判断对象类型。
1 | const obj = { name: "云牧", age: 18 } |
Array.isArray()
Array.isArray()方法用于判断一个对象是否为数组,且只能判断数组类型。
1 | console.log(Array.isArray([1, 2, 3])); // 输出: true |
Number.isNaN()
Number.isNaN()方法用于判断是否为NaN。
1 | console.log(Number.isNaN(NaN)) // true |
加餐:ES6中NaN的加强
NaN 和 Number.NaN 特点
typeof判断类型是数字number- 自己不等于自己
isNaN
如果非数字,隐式转换传入结果如果是 NaN,就返回 true,反之返回 false
1 | console.log(isNaN(NaN)) // true |
Number.isNaN
判断一个值是否是数字,并且值是否等于 NaN
1 | console.log(Number.isNaN(NaN)) // true |
indexOf 和 includes
indexOf 不可查找 NaN, includes 则可以查找 NaN
1 | const arr = [NaN] |
Number.isFinite()
Number.isFinite() 可以判断一个值是否为有限数
1 | console.log(Number.isFinite(123)); // true |
鸭子类型检测
检查自身属性的类型或者执行结果的类型
通常作为候选方案
1 | const isObject = value => |
1 | function kindof(obj) { |
Symbol.toStringTag
- 原理:
Object.prototype.toString会读取该值 - 适用场景:需自定义类型
- 注意事项:兼容性
1 | class MyArray { |
等比较
原理:与某个固定值进行比较
适用场景:undefined、 window、 document、 null 等
1 | _.isNull = function(obj) { |
void 0 始终返回 undefined,void 后面接任意值都是返回 undefined, 这是为了兼容 IE,因为在 IE 中 undefined 值可以被改写












