判断js对象类型的方法

概述

js判断对象类型基本就是四种方法:

  1. typeof
  2. instanceof
  3. constructor.name
  4. Object.prototype.toString

各种方法的原理和优劣可以看判断JS数据类型的四种方法 - 一像素 - 博客园 (cnblogs.com),本文主要介绍其中最准确的方法Object.prototype.toString

得到对象类型方法

let x = []
console.log(Object.prototype.toString.call(x)) // [object Array]

Object.prototype.toString 方法是检测对象类型的一种标准方式,因为它能够返回一个清晰、一致的表示对象类型的字符串。对于标准内建对象,这个方法返回的字符串遵循 "[object Xxx]" 的格式,其中 Xxx 就是对象的类型。

方法原理

当你调用 Object.prototype.toString.call(new Date()) 时,这个方法会读取调用它的对象的内部 [[Class]] 属性来确定对象的类型。对于不同类型的对象,[[Class]] 属性有不同的值,比如对于一个日期对象(Date 实例),[[Class]] 的值是 Date。因此,当你对一个 Date 实例调用 Object.prototype.toString 方法时,它会返回字符串 [object Date]

在ECMAScript规范中,[[Class]] 是一个内部属性,它不直接暴露给开发者。

自定义对象配置

我看到有部分文章说Object.prototype.toString方法的缺点是自定义的对象无法使用这种方法获取到类型,只能拿到[object Object],这是不正确的。我们可以通过配置自定义对象的Symbol.toStringTag属性值来使得Object.prototype.toString正确打印出自定义对象的类型值。

class X {
  // 使用getter定义Symbol.toStringTag
  get [Symbol.toStringTag]() {
    return 'X';
  }
}

let x = new X();
console.log(Object.prototype.toString.call(x)); // 输出:'[object X]'

总结

  • js获取对象类型最准确的方法是通过借调Object.prototype.toString,例如Object.prototype.toString.call(x)
  • 自定义对象也可以通过配置对象的Symbol.toStringTag属性,使得自定义对象的实例也可通过借调Object.prototype.toString来获取到对象类型;
  • js内置对象没有配置Symbol.toStringTag属性,而是使用了内置隐藏属性[[Class]]来保存当前对象类型,其同样可以通过借调Object.prototype.toString打印出来。

对instanceof的补充

instanceof是通过判断左侧对象的__proto__属性所指的原型对象是否在右侧“类”的prototype属性所指的原型链上,来判断左侧对象是否为右侧“类”的实例。

但是在iframe中,不论是父页面通过直接拿到contentWindow来拿到子窗体进而拿到对象,还是子页面通过window.parent/window.top进而拿到父窗体进而拿到对象,拿到的对象使用instanceof一定是false的。如下所示:

// 父页面
window.onload = function () {
  var iframe = document.getElementById("childFrame");
  var childWindow = iframe.contentWindow;
  var childArray = childWindow.childArray;

  // 尝试在父页面中检查这个数组是否是Array的实例
  console.log("childWindow.childArray", childArray instanceof Array); // 这里会输出false
};
// 子页面
var childArray = [1, 2, 3];

这是因为JavaScript在不同的全局执行环境(如不同的iframe或窗口)中,会为每个环境创建一套独立的内置对象,包括Array、Object等。即便这些iframe或窗口来自同一个源,它们的全局执行环境也是隔离的。这意味着来自不同iframe的对象实例,即使它们的构造函数看似相同(比如都是Array),也被认为是不同的,因为它们分别属于不同的全局执行环境。

posted @ 2024-02-28 16:34  Cat_Catcher  阅读(523)  评论(0编辑  收藏  举报
#