V8 引擎的存储机制
在 V8 引擎中,原始类型和复杂类型的存储方式有所不同:
- 原始类型的值直接存储在调用栈中。原始类型包括:
number、string、boolean、undefined、symbol、bigint。 - 复杂类型的值存储在堆结构中,并将堆中的引用地址存储在调用栈中。复杂类型包括对象、数组、函数等。
由于调用栈空间较小,而引用类型的数据量可能非常大,因此将引用类型的数据直接放在调用栈中很容易导致栈溢出。将引用类型的数据存储在堆中,并在栈中保存其引用地址,可以有效避免这一问题。
typeof 操作符
typeof 操作符主要用于判断值的类型,但它有一些局限性:
typeof可以判断除null之外的所有原始类型。typeof无法准确判断除function之外的引用类型。
typeof 判断原理
typeof 的判断原理是将值转换为二进制后检查其前三位。大部分引用类型的二进制表示前三位都是 0,而 null 的二进制表示全部是 0。由于这种方式的局限性,typeof null 返回 object,这也是 JavaScript 中一个著名的 bug。
let str = 'hello'
let num = 123
let flag = false
let un = undefined
let nu = null
let obj = {}
let arr = []
let fn = function() {}
let date = new Date()
console.log(typeof str);// String
console.log(typeof(num));// number
console.log(typeof(flag));// boolean
console.log(typeof(un));// undefined
console.log(typeof(null));// object
console.log(typeof(obj));// object
console.log(typeof(arr));// object
console.log(typeof(fn));// function
console.log(typeof(date));// object
instanceof 操作符
instanceof 操作符用于判断一个对象是否是另一个对象的实例。它只能用于判断引用类型,通过原型链的查找来判断:
function Foo() {}
const foo = new Foo();
console.log(foo instanceof Foo); // true
instanceof 会顺着原型链查找,直到找到原型链的顶端。如果在原型链中找到了指定的构造函数的原型,则返回 true,否则返回 false。
let str = 'hello'
let num = 123
let flag = false
let un = undefined
let nu = null
let obj = {}
let arr = []
let fn = function() {}
let date = new Date()
console.log(str instanceof String);// false
console.log(num instanceof Number);// false
console.log(flag instanceof Boolean);// false
console.log(un instanceof undefined);
console.log(nu instanceof null);
console.log(obj instanceof Object);// true
console.log(arr instanceof Array);// true
console.log(fn instanceof Function)// true
console.log(date instanceof Date)// true
Object.prototype.toString
Object.prototype.toString.call() 是一种更准确的类型判断方式。它通过调用 toString 方法并传入一个值来返回该值的内部类型表示:
- 对象的
toString方法:返回对象的字符串表示形式。 - 数组的
toString方法:将数组中的元素用逗号连接成字符串。 - 其他类型的
toString方法:直接返回字符串字面量。
Object.prototype.toString(x) 的工作原理
- 如果
toString接受的值是undefined,则返回"[object Undefined]"。 - 如果
toString接受的值是null,则返回"[object Null]"。 - 调用
ToObject(x)将x转为对象,此时得到的对象内部一定拥有一个属性[[class]],而该属性[[class]]的值就是x的类型。 - 设
class是[[class]]的值。 - 返回由
"[object "和class和"]"拼接得到的字符串。
例如:
console.log(Object.prototype.toString.call(123)); // [object Number]
console.log(Object.prototype.toString.call([])); // [object Array]
console.log(Object.prototype.toString.call(null)); // [object Null]
console.log(Object.prototype.toString.call(undefined)); // [object Undefined]
Array.isArray
Array.isArray 方法用于判断一个值是否为数组。与 typeof 和 instanceof 不同,它专门用于检测数组类型,提供了比 typeof 和 instanceof 更可靠的方式来判断一个值是否为数组。
console.log(Array.isArray([])); // true
console.log(Array.isArray({})); // false
console.log(Array.isArray('123')); // false
综上所述,JavaScript 提供了多种方法来判断变量的类型,包括 typeof、instanceof、Object.prototype.toString 和 Array.isArray。每种方法都有其适用范围和局限性,开发者可以根据具体需求选择合适的方法来判断变量的类型。