详解typeof与instanceOf

typeof

typeof 操作符返回一个字符串,表示未经计算的操作数的类型。

语法: typeof 运算符后接操作数:
typeof operand
typeof(operand)

参数:
operand:一个表示对象或原始值的表达式,其类型将被返回。

下表总结了 typeof 可能的返回值。

类型 结果
Undefined “undefined”
Null “object” (见下文)
Boolean “boolean”
Number “number”
BigInt(ECMAScript 2020 新增) “bigint”
String “string”
Symbol (ECMAScript 2015 新增) “symbol”
宿主对象(由 JS 环境提供) 取决于具体实现
Function 对象 (按照 ECMA-262 规范实现 [[Call]]) “function”
其他任何对象 “object”

typeof null

// JavaScript 诞生以来便如此
typeof null === 'object';

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"

使用 new 操作符

// 除 Function 外的所有构造函数的类型都是 'object'
var str = new String('String');
var num = new Number(100);

typeof str; // 返回 'object'
typeof num; // 返回 'object'

var func = new Function();

typeof func; // 返回 'function'

正则表达式
对正则表达式字面量的类型判断在某些浏览器中不符合标准:

typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1

错误
在 ECMAScript 2015 之前,typeof 总能保证对任何所给的操作数返回一个字符串。即便是没有声明的标识符,typeof 也能返回 'undefined'。使用 typeof 永远不会抛出错误。

扫描二维码关注公众号,回复: 13125138 查看本文章
if(typeof a!="undefined"){
    
    }

但在加入了块级作用域的 letconst 之后,在其被声明之前对块中的 letconst 变量使用 typeof 会抛出一个 ReferenceError。块作用域变量在块的头部处于“暂存死区”,直至其被初始化,在这期间,访问变量将会引发错误。

typeof undeclaredVariable === 'undefined';

typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError

let newLetVariable;
const newConstVariable = 'hello';
class newClass{
    
    };

typeof 各类数据 结果

Value Class Type
“foo” String string
new String(“foo”) String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object (function in Nitro/V8)
new RegExp(“meow”) RegExp object (function in Nitro/V8)
{} Object object
new Object() Object object
null Null object
undefined Undefined undefined
BigInt(123) Bigint bigint
Symbol() Symbol symbol

上面表格中,Type 一列表示 typeof 操作符的运算结果。可以看到,这个值在大多数情况下都返回 “object”。

Class 一列表示对象的内部属性 [[Class]] 的值。

JavaScript 标准文档中定义: [[Class]] 的值只可能是下面字符串中的一个: Arguments, Array, Boolean, Date, Error, Function, JSON, Math, Number, Object, RegExp, String,Symbol,Bigint

结论:
typeof几乎不可能得到它们想要的结果。

instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

语法: object instanceof constructor
参数: object(某个实例对象)constructor(某个构造函数)
描述: instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

instanceof 只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。

比较自定义对象

function Foo() {
    
    }
function Bar() {
    
    }
Bar.prototype = new Foo();
new Bar() instanceof Bar; // true, new Bar().__proto__ === Bar.prototype
new Bar() instanceof Foo; // true, new Bar().__proto__.__proto__ === Foo.prototype

// 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
Bar.prototype = Foo;
new Bar() instanceof Foo; // false, new Bar().__proto__.__proto__ !== Foo.prototype

instanceof 比较内置类型

new String('foo') instanceof String; // true, new String('foo').__proto__ === String.prototype
new String('foo') instanceof Object; // true, new String('foo').__proto__.__proto__ === Object.prototype
'foo' instanceof String; // false, 'foo'不为对象
'foo' instanceof Object; // false,'foo'不为对象

有一点需要注意,instanceof 用来比较属于不同 JavaScript 上下文的对象(比如,浏览器中不同的文档结构)时将会出错, 因为它们的构造函数不会是同一个对象。

// 定义构造函数
function C(){
    
    }
function D(){
    
    }

var o = new C();


o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype


o instanceof D; // false,因为 D.prototype 不在 o 的原型链上

o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object // true,同上

C.prototype = {
    
    };
var o2 = new C();

o2 instanceof C; // true

o instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上.

D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 _proto_ 伪属性,是可以实现的。比如执行 obj._proto_ = {} 之后,obj instanceof Foo 就会返回 false 了。

正确获取数据类型

JavaScript 标准文档只给出了一种获取上文 [[Class]] 值的方法,那就是使用 Object.prototype.toString

Object.prototype.toString 返回一种标准格式字符串,

Object.prototype.toString.call([])  // "[object Array]"
Object.prototype.toString.call({
    
    })  // "[object Object]"
Object.prototype.toString.call(2)  // "[object Number]"

所以可以通过 slice 截取指定位置的字符串,如下所示:

Object.prototype.toString.call([]).slice(8, -1); // Array

上面例子中,Object.prototype.toString 方法被调用,this 被设置为了需要获取 [[Class]] 值的对象。

为了更加明确地检查类型,将typeof 在生产级代码中使用的包装器如下:

/**
 * @param data 必填 需要获取类型的数据
 * @param { boolean } isGetfullClass 选填 是否获取完整数据类型结构
 **/
function getDataType(data, isGetfullClass) {
    
    
	
  // get toPrototypeString() of data (handles all types)
  // Early JS environments return '[object Object]' for null, so it's best to directly check for it.
  if (isGetfullClass) {
    
    
      return (data === null) ? '[object Null]' : Object.prototype.toString.call(data);
  }
  if (data == null) {
    
     return (data + '').toLowerCase(); } // implicit toString() conversion

  var deepType = Object.prototype.toString.call(data).slice(8,-1).toLowerCase();
  if (deepType === 'generatorfunction') {
    
     return 'function' }

  // Prevent overspecificity (for example, [object HTMLDivElement], etc).
  // Account for functionish Regexp (Android <=2.3), functionish <object> element (Chrome <=57, Firefox <=52), etc.
  // String.prototype.match is universally supported.

  return deepType.match(/^(arguments|array|bigint|boolean|date|error|function|json|math|number|generator|regexp|symbol|object)$/) ? deepType :
     (typeof data === 'object' || typeof data === 'function') ? 'object' : typeof data;
}

猜你喜欢

转载自blog.csdn.net/weixin_44116302/article/details/114038531
今日推荐