一.数据类型
JavaScript中有7中数据类型,分为基本数据类型和引用数据类型两大类:
1.基本数据类型
-
Number
(数字):整数或浮点数,例如3.14
或-42
。 -
String
(字符串):字符串是一系列字符,例如"Hello, World!"
。 -
Boolean
(布尔值):表示真或假,例如true
或false
。 -
Null
(空值):表示没有值,例如null
。 -
Undefined
(未定义):表示未定义的值,例如undefined
。 -
Symbol
(符号):表示唯一的标识符,例如Symbol('example)
。
2.引用数据类型
-
Object
(对象):是一组属性和方法的集合,例如{ name: 'Alice', age: 30 }
。 -
Array
(数组):是一个有序的集合,例如[1, 2, 3]
。 -
Function
(函数):是一段可重复使用的代码块,例如function add(a, b) { return a + b; }
。 -
Date
(日期):表示日期和时间,例如new Date()
。 -
RegExp
(正则表达式):用于匹配字符串的模式,例如/\d+/g
。
3.基本数据类型和引用数据类型区别
-
基本数据类型存在于
栈
(stack)中,是不可变的,修改一个基本数据类型的值,实际上会创建一个新的值。 -
引用数据类型存在于
堆
(heap)中,是可变的,引用数据类型的变量实际上是对值得引用,而不是值本身。- 例如:如果两个变量引用同一个对象,当一个变量修改该对象时,另一个变量也会受到影响。
-
注:堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
-
在数据结构中,栈中数据的存取方式为先进后出。
-
堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
-
4.判断数据类型的方法
typeof
操作符
console.log(typeof 123); // number
console.log(typeof true); // boolean
console.log(typeof undefined); // undefined
console.log(typeof null); // object
console.log(typeof {}); // object
console.log(typeof []); // object
console.log(typeof function(){}); // function
typeof
操作符用于检测变量的数据类型,返回一个字符串,其值为变量的数据类型。它能够正确地判断基本数据类型的数据类型,但不能用于判断引用类型,因为它会统一返回为object
。
instanceof
操作符
console.log(new String("hello") instanceof String); // true
console.log(123 instanceof Number); // false
console.log(new Number(123) instanceof Number); // true
console.log(true instanceof Boolean); // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log({} instanceof Object); // true
console.log([] instanceof Array); // true
console.log(function(){} instanceof Function); // true
instanceof
操作符用于检测一个对象是否为某个类的实例,它的原理是检查对象的原型链中是否存在指定类的原型。它不能用于判断基本数据类型。
Object.prototype.toString.call()
方法
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call(true)); // [object Boolean]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call({})); // [object Object]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(function(){})); // [object Function]
Object.prototype.toString
方法用于返回一个表示对象类型的字符串。它的原理是获取对象的内部[[Class]]属性,并将其转换为字符串形式。所有对象的内部[[Class]]属性都可以通过Object.prototype.toString.call(obj)
方法获取。
constructor
属性
console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
constructor
属性返回对象的构造函数。每个对象(除 null
和 undefined
)都有一个constructor
属性,可以通过该属性获取对象的构造函数。由于每个数据类型都对应一个构造函数,因此可以通过判断变量的 constructor
属性来判断变量的数据类型。
5.判断数组的方法
instanceof
运算符
let arr = [1, 2, 3];
console.log(arr instanceof Array); // true
Array.isArray()
方法
let arr = [1, 2, 3];
console.log(Array.isArray(arr)); // true
Object.prototype.toString.call()
方法
let arr = [1, 2, 3];
console.log(Object.prototype.toString.call(arr) === "[object Array]"); // true
注意: 第一种和第二种方式的效率较高,并且可以处理跨 iframe
的情况。第三种方式会出现误判,例如当一个类似数组的对象使用 Object.prototype.toString.call()
方法判断时,也会返回 “[object Array]”,因此需要谨慎使用。
6.instanceof的原理和实现
instanceof
用于检查一个对象是否是另一个对象的实例。它的语法如下:
object instanceof constructor //object是要检查的对象,constructor是一个函数或类,表示要检查的类型。
-
原理
instanceof
的原理是检查object
的原型链上是否存在constructor.prototype
。如果object
的原型链上存在constructor.prototype
,则object
是constructor
的实例,否则不是。 -
实现
下面是一种基于原型链的实现
instanceof
的方法:
function myInstanceOf(object, constructor) {
let proto = Object.getPrototypeOf(object);
while (proto) {
if (proto === constructor.prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
return false;
}
let arr = [];
console.log(myInstanceOf(arr, Array)); // true
console.log(myInstanceOf(arr, Object)); // true
console.log(myInstanceOf(arr, RegExp)); // false
该方法首先获取object
的原型对象,并循环遍历原型链,逐级比较每个原型对象是否等于constructor.prototype
。如果找到了相等的原型对象,则返回true
,否则返回false
。
7.(0.1+0.2 ! == 0.3)问题
-
原因
使用 IEEE 754 标准来表示浮点数,该标准使用二进制来表示小数。因为在二进制中无法准确地表示一些十进制小数,因此在进行浮点数计算时会出现舍入误差,从而导致某些计算结果不准确。
0.1
在十进制中可以准确地表示为0.1
,但在二进制中表示为0.0001100110011001100110011001100110011001100110011...
(循环节为0011
),其中小数点后的数值是无限循环的。同样地,0.2 在二进制中也是无限循环的,表示为0.0011001100110011001100110011001100110011001100110...
(循环节为0011
) -
解决方案
-
方案1:
Math.abs()
function isEqual(num1, num2) { return Math.abs(num1 - num2) < Number.EPSILON; } // Number.EPSILON 属性表示 1 与Number可表示的大于 1 的最小的浮点数之间的差值。 console.log(isEqual(0.1 + 0.2, 0.3); // 输出 true
-
方案2:
toFixed()
var result = (0.1 + 0.2).toFixed(1); // 将小数点后一位四舍五入 console.log(result); // 输出 0.3
注意:``toFixed()
在Chrome 浏览器
中存在精度问题(工作中踩的坑😢),例如parseFloat((0.615).toFixed(2))
的结果为0.61
。具体可参考这篇文章点我跳转
-
8.类型转换
类型转换可以分为两种:
-
隐式类型转换:JavaScript 引擎自动将一个数据类型转换为另一个数据类型,常见的隐式类型转换包括:
- 字符串和数字之间的运算,会将字符串转换为数字。
- 布尔值和数字之间的运算,会将布尔值转换为数字。
- 字符串和布尔值之间的运算,会将字符串转换为布尔值。
- 对象和原始值之间的运算,会将对象转换为原始值。
- undefined 和 null 会被转换为 false,数字 0 也会被转换为 false。
-
显式类型转换: 开发人员明确地将一个数据类型转换为另一个数据类型,常见的显式类型转换包括:
- 使用
Number()
函数将字符串转换为数字。 - 使用
parseInt()
函数将字符串转换为整数。 - 使用
parseFloat()
函数将字符串转换为浮点数。 - 使用
String()
函数将数字或其他数据类型转换为字符串。 - 使用
Boolean()
函数将其他数据类型转换为布尔值。
- 使用
9.Object.is()、==、===的区别
Object.is()
、“===”
、“==”
都用于比较两个值是否相等。
-
Object.is()
方法一般情况下和
===
的判断结果相同,但是新增了特殊情况,比如:-0
和+0
不相等,NaN
和NaN
是相等的 -
==
操作符用于比较两个值是否相等,如果类型不一致会强制类型转化后再比较
-
===
操作符用于比较两个值是否严格相等,它会进行类型和值的比较。