typeof 和 instanceof 有啥区别,啥时候应该使用另一个?

Posted

技术标签:

【中文标题】typeof 和 instanceof 有啥区别,啥时候应该使用另一个?【英文标题】:What is the difference between typeof and instanceof and when should one be used vs. the other?typeof 和 instanceof 有什么区别,什么时候应该使用另一个? 【发布时间】:2010-10-28 07:50:35 【问题描述】:

在我的特殊情况下:

callback instanceof Function

typeof callback == "function"

这有什么关系,有什么区别?

其他资源:

javascript-Garden typeof 与 instanceof

【问题讨论】:

我发现我的answer here 是一个易于使用的解决方案 还有另一种使用Object.prototype.toStringecma-international.org/ecma-262/6.0/…检查类型的方法 只使用.constructor 属性。 如果您想了解性能,请查看我的answer below。 typeof 在两者都适用的情况下(即对象)更快。 【参考方案1】:

typeof:根据 MDN 文档,typeof 是一个一元运算符,它返回一个字符串,指示未计算的操作数的类型。

对于字符串基元和字符串对象,typeof 返回以下内容:

const a = "I'm a string primitive";
const b = new String("I'm a String Object");

typeof a; --> returns 'string'
typeof b; --> returns 'object'

instanceof:是二元运算符,接受对象和构造函数。 它返回一个布尔值,指示对象在其原型链中是否具有给定的构造函数

当应用于上面的字符串实例时,与String相比,它的行为如下:

const a = "I'm a string primitive";
const b = new String("I'm a String Object");

a instanceof String; --> returns false
b instanceof String; --> returns true

参考:https://bambielli.com/til/2017-06-18-typeof-vs-instanceof/

【讨论】:

【参考方案2】:

根据MDN documentation about typeof,使用“new”关键字实例化的对象属于“对象”类型:

typeof 'bla' === 'string';

// The following are confusing, dangerous, and wasteful. Avoid them.
typeof new Boolean(true) === 'object'; 
typeof new Number(1) === 'object'; 
typeof new String('abc') === 'object';

虽然documentation about instanceof 指出:

const objectString = new String('String created with constructor');
objectString instanceOf String; // returns true
objectString instanceOf Object; // returns true

因此,如果有人想检查,例如不管它是如何创建的,它都是一个字符串,最安全的方法是使用instanceof

【讨论】:

【参考方案3】:

不需要过多的上面的例子,只要记住两个观点:

    typeof var;是一元运算符,将返回var的原始类型或根类型。这样它将返回原始类型(stringnumberbigintbooleanundefinedsymbol)或object 类型。

    1234563基于它们是不同的(如OOP类继承概念),这里a instanceof A - 二元运算符 - 会帮助你,它将通过原型链检查正确操作数(A)的构造函数是否出现。

所以当你想检查“根类型”或使用原始变量时 - 使用“typeof”,否则使用“instanceof”。

null是一个特例,看起来很原始,但确实是一个对象的特例。使用a === null 代替检查null。

另一方面,function 也是一个特例,它是内置对象但typeof 返回function

如你所见instanceof 必须通过原型链,同时typeof 只需检查一次根类型,因此很容易理解为什么typeofinstanceof

【讨论】:

【参考方案4】:

准确地说 instanceof 应该用于通过构造函数(通常是自定义类型)创建值的地方,例如

var d = new String("abc")

typeof 检查仅由分配创建的值,例如

var d = "abc"

【讨论】:

【参考方案5】:

要说清楚,你需要知道两个事实:

    instanceof 运算符测试 构造函数prototype 属性 是否出现在 prototypes 链 的任何位置目的。在大多数情况下,这意味着对象是通过使用此构造函数或其后代创建。但也可以通过Object.setPrototypeOf() 方法(ECMAScript 2015)或__proto__ 属性(旧浏览器,已弃用)显式设置原型。但是,由于性能问题,不建议更改对象的原型。

因此 instanceof 仅适用于对象。在大多数情况下,您不会使用构造函数来创建字符串或数字。你可以。但你几乎从不这样做。

instanceof 也无法检查到底是哪个构造函数用于创建对象,但会返回 true,即使对象是从被检查的类派生的。在大多数情况下,这是所需的行为,但有时并非如此。所以你需要保持这种心态。

另一个问题是不同的作用域有不同的执行环境。这意味着它们具有不同的内置函数(不同的全局对象、不同的构造函数等)。这可能会导致意想不到的结果。

例如,[] instanceof window.frames[0].Array 将返回 false,因为 Array.prototype !== window.frames[0].Array 和数组继承自前者。 此外,它不能用于未定义的值,因为它没有原型。

    typeof 运算符测试值是否属于六种基本类型之一:“number”、“string >”、“boolean”、“object”、“function”或“undefined”。字符串“object”属于所有对象(除了函数,它们是对象,但在 typeof 运算符中有自己的值),还有“null”值和数组(对于“null”,这是一个错误,但这个错误太老了,因此它已成为标准)。它不依赖于构造函数,即使值未定义也可以使用。但它没有提供有关对象的任何细节。因此,如果您需要它,请转到 instanceof。

现在让我们谈谈一件棘手的事情。如果使用构造函数创建原始类型会怎样?

let num = new Number(5);
console.log(num instanceof Number); // print true
console.log(typeof num); // print object
num++; //num is object right now but still can be handled as number
//and after that:
console.log(num instanceof Number); // print false
console.log(typeof num); // print number

看起来像魔术。但事实并非如此。这就是所谓的装箱(按对象包装原始值)和拆箱(从对象中提取包装的原始值)。这种代码似乎“有点”脆弱。当然,您可以避免使用构造函数创建原始类型。但是还有另一种可能的情况,拳击可能会击中你。当您在原始类型上使用 Function.call() 或 Function.apply() 时。

function test()
  console.log(typeof this);
 
test.apply(5);

为避免这种情况,您可以使用严格模式:

function test()
  'use strict';
  console.log(typeof this);
 
test.apply(5);

更新: 自 ECMAScript 2015 以来,还有一种称为 Symbol 的类型,它有自己的 typeof == "symbol"

console.log(typeof Symbol());
// expected output: "symbol"

你可以在 MDN 上阅读它:(Symbol, typeof)。

【讨论】:

if an object is created by a given constructor 这是不正确的。如果 o 继承自 C.prototype,o instanceof C 将返回 true。您稍后在回答中提到了一些关于此的内容,但不是很清楚。 不正确...来自书中:“github.com/getify/You-Dont-Know-JS”a instanceof Foo; // true instanceof 运算符将一个普通对象作为其左侧操作数,将一个函数作为其右侧操作数。 instanceof回答的问题是:在a的整个[[Prototype]]链中,Foo.prototype任意指向的对象是否曾经出现过? 我已经编辑了答案,更加正确。感谢您的 cmets。 另外,添加了对装箱/拆箱问题的说明。【参考方案6】:

对自定义类型使用instanceof

var ClassFirst = function () ;
var ClassSecond = function () ;
var instance = new ClassFirst();
typeof instance; // object
typeof instance == 'ClassFirst'; // false
instance instanceof Object; // true
instance instanceof ClassFirst; // true
instance instanceof ClassSecond; // false 

typeof 用于简单的内置类型:

'example string' instanceof String; // false
typeof 'example string' == 'string'; // true

'example string' instanceof Object; // false
typeof 'example string' == 'object'; // false

true instanceof Boolean; // false
typeof true == 'boolean'; // true

99.99 instanceof Number; // false
typeof 99.99 == 'number'; // true

function()  instanceof Function; // true
typeof function()  == 'function'; // true

对复杂的内置类型使用instanceof

/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object

[] instanceof Array; // true
typeof []; //object

 instanceof Object; // true
typeof ; // object

最后一个有点棘手:

typeof null; // object

【讨论】:

这个答案清楚地说明了为什么 instaceof 应该用于原始类型。很明显,当涉及到自定义类型以及“对象”类型的好处时,您没有选择。但是是什么让函数与“简单的内置类型”混为一谈呢?我觉得一个函数的行为方式像一个对象很奇怪,但它的类型是“函数”,使得使用“typeof”变得可行。不过,你为什么不鼓励 instanceof 呢? @Assimilater 您也可以将 instanceof 与函数一起使用,但是我认为这 3 条规则非常容易记住,是的,函数是一个例外:) 另一个棘手的部分 -> 'example string' instanceof String; // false but new String('example string') instanceof String; //真 @Luke 通常像这样使用“新字符串”是个坏主意。它创建了一个“字符串对象”而不是字符串原语。请参阅此处的部分developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Use instanceof for complex built in types - 这仍然容易出错。最好使用 ES5 Array.isArray() 等。或推荐的垫片。【参考方案7】:

这只是对这里所有其他解释的补充知识 - 我建议在任何地方使用.constructor

TL;DR:typeof 不是一个选项的情况下,以及当你知道你不关心原型链时 strong>,Object.prototype.constructor 可能是比instanceof 更可行甚至更好的替代方案:

x instanceof Y
x.constructor === Y

它从 1.1 开始就已成为标准,因此无需担心向后兼容性。

Muhammad Umer 也在此处某处的评论中简要提到了这一点。它适用于所有带有原型的东西——所以不是nullundefined

// (null).constructor;      // TypeError: null has no properties
// (undefined).constructor; // TypeError: undefined has no properties

(1).constructor;                 // function Number
''.constructor;                  // function String
([]).constructor;                // function Array
(new Uint8Array(0)).constructor; // function Uint8Array
false.constructor;               // function Boolean()
true.constructor;                // function Boolean()

(Symbol('foo')).constructor;     // function Symbol()
// Symbols work, just remember that this is not an actual constructor:
// new Symbol('foo'); //TypeError: Symbol is not a constructor

Array.prototype === window.frames.Array;               // false
Array.constructor === window.frames.Array.constructor; // true

此外,根据您的用例,它可能比instanceof很多(原因可能是它不必检查整个原型链)。就我而言,我需要一种快速的方法来检查一个值是否是一个类型化数组:

function isTypedArrayConstructor(obj) 
  switch (obj && obj.constructor)
    case Uint8Array:
    case Float32Array:
    case Uint16Array:
    case Uint32Array:
    case Int32Array:
    case Float64Array:
    case Int8Array:
    case Uint8ClampedArray:
    case Int16Array:
      return true;
    default:
      return false;
  


function isTypedArrayInstanceOf(obj) 
  return obj instanceof Uint8Array ||
    obj instanceof Float32Array ||
    obj instanceof Uint16Array ||
    obj instanceof Uint32Array ||
    obj instanceof Int32Array ||
    obj instanceof Float64Array ||
    obj instanceof Int8Array ||
    obj instanceof Uint8ClampedArray ||
    obj instanceof Int16Array;

https://run.perf.zone/view/isTypedArray-constructor-vs-instanceof-1519140393812

结果:

Chrome 64.0.3282.167(64 位,Windows)

Firefox 59.0b10(64 位,Windows)

出于好奇,我对typeof 做了一个快速的玩具基准测试;令人惊讶的是,它的性能并没有差多少,而且在 Chrome 中似乎更快:

let s = 0,
    n = 0;

function typeofSwitch(t) 
    switch (typeof t) 
        case "string":
            return ++s;
        case "number":
            return ++n;
        default:
            return 0;
    


// note: no test for null or undefined here
function constructorSwitch(t) 
    switch (t.constructor) 
        case String:
            return ++s;
        case Number:
            return ++n;
        default:
            return 0;
    


let vals = [];
for (let i = 0; i < 1000000; i++) 
    vals.push(Math.random() <= 0.5 ? 0 : 'A');

https://run.perf.zone/view/typeof-vs-constructor-string-or-number-1519142623570

注意:功能的列出顺序在图像之间切换!

Chrome 64.0.3282.167(64 位,Windows)

Firefox 59.0b10(64 位,Windows)

注意:功能的列出顺序在图像之间切换!

【讨论】:

【参考方案8】:

当然很重要........!

让我们通过示例来完成。在我们的示例中,我们将以两种不同的方式声明函数。

我们将同时使用 function declarationFunction Constructor。我们将了解 typeofinstanceof 在这两种不同情况下的表现。

使用函数声明创建函数:

function MyFunc()  

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

对这种不同结果的可能解释是,当我们做了一个函数声明时,typeof 可以理解它是一个函数。因为 typeof 检查是否不是操作 typeof 的表达式,在我们的例子中 MyFunc 实现了 Call Method 或没有。如果它实现了 Call 方法,它就是一个函数。否则不是。为了澄清检查 ecmascript specification for typeof

使用函数构造函数创建函数:

var MyFunc2 = new Function('a','b','return a+b') // A function constructor is used 

typeof MyFunc2 == 'function' // true

MyFunc2 instanceof Function // true

这里 typeof 断言 MyFunc2 是一个函数以及 instanceof 运算符。我们已经知道 typeof 检查 MyFunc2 是否实现了 Call 方法。因为 MyFunc2 是一个函数并且它实现了 call 方法,这就是 typeof 知道它是一个函数。另一方面,我们使用 function constructor 来创建 MyFunc2,它成为 Function constructor 的一个实例。这就是为什么 instanceof 也解析为 true

使用什么更安全?

正如我们在这两种情况下看到的那样,typeof 运算符可以成功地断言我们正在处理一个函数,它比 instanceof 更安全。 instanceof 将在 function declaration 的情况下失败,因为 function declarations 不是 Function constructor 的实例>.

最佳实践:

正如 Gary Rafferty 所建议的,最好的方法是同时使用 typeof 和 instanceof。

  function isFunction(functionItem) 

        return typeof(functionItem) == 'function' || functionItem instanceof Function;

  

  isFunction(MyFunc) // invoke it by passing our test function as parameter

【讨论】:

对此答案的任何建设性批评将不胜感激。【参考方案9】:

考虑到性能,最好使用 typeof 使用典型的硬件,如果您创建一个循环 1000 万次迭代的脚本 指令: typeof str == 'string' 需要 9ms 而 'string' instanceof String 需要 19 毫秒

【讨论】:

【参考方案10】:

性能

在两者都适用的情况下,typeofinstanceof 快。

根据您的引擎,typeof 的性能差异可能在 20% 左右。 (您的里程可能会有所不同

这是Array 的基准测试:

var subject = new Array();
var iterations = 10000000;

var goBenchmark = function(callback, iterations) 
    var start = Date.now();
    for (i=0; i < iterations; i++)  var foo = callback(); 
    var end = Date.now();
    var seconds = parseFloat((end-start)/1000).toFixed(2);
    console.log(callback.name+" took: "+ seconds +" seconds.");
    return seconds;


// Testing instanceof
var iot = goBenchmark(function instanceofTest()
     (subject instanceof Array);
, iterations);

// Testing typeof
var tot = goBenchmark(function typeofTest()
     (typeof subject == "object");
, iterations);

var r = new Array(iot,tot).sort();
console.log("Performance ratio is: "+ parseFloat(r[1]/r[0]).toFixed(3));

结果

instanceofTest took: 9.98 seconds.
typeofTest took: 8.33 seconds.
Performance ratio is: 1.198

【讨论】:

typeof subject == "array" 应该返回 false。 typeof 主题是“对象”。 为什么 typeof 更快? Javascript 是在实习文字字符串吗? 原因是:instanceof 总是 遵循对象的原型链,因此性能损失将取决于类在原型链中的距离,instanceof 被测试。因此,对于短继承链,惩罚会更低(例如,[] instanceof Array instanceof Object),而对于长继承链,惩罚会更大。因此,如果从您的某些假设代码的角度来看,obj instanceof SomeClasstypeof obj !== 'string' 的含义相同(如果您只是在 if 中进行测试,而不是 switch-ing 通过多个类等),那么你最好选择第二个,性能方面,【参考方案11】:

var newObj =  new Object;//instance of Object
var newProp = "I'm xgqfrms!" //define property
var newFunc = function(name)//define function 
	var hello ="hello, "+ name +"!";
	return hello;

newObj.info = newProp;// add property
newObj.func = newFunc;// add function

console.log(newObj.info);// call function
// I'm xgqfrms!
console.log(newObj.func("ET"));// call function
// hello, ET!

console.log(newObj instanceof Object);
//true
console.log(typeof(newObj));
//"object"

【讨论】:

怎么办,能不能得到UA(navigator.userAgent)?【参考方案12】:

检查函数时,必须始终使用typeof

这就是区别:

var f = Object.create(Function);

console.log(f instanceof Function); //=> true
console.log(typeof f === 'function'); //=> false

f(); // throws TypeError: f is not a function

这就是为什么绝不能使用instanceof 来检查函数的原因。

【讨论】:

我可以说是typeof 是错误的——f 是以下所有内容:Object(一个对象)和一个Function(一个函数)。除了我,使用instanceof 更有意义,因为知道它是一个函数,我也知道它是一个对象,因为所有函数都是 ECMAScript 中的对象。反之则不然——从typeof 知道f 确实是object 我不知道它也是一个函数。 @amn 对我来说,它是 Function 的 broken 实例。它从 Function 中获取 lengthnamecall 等属性,但它们都已失效。更糟糕的是,它不能被调用,TypeError 说:f is not a function【参考方案13】:

另一种情况是您只能与instanceof 进行核对 - 它返回真或假。使用typeof,您可以获得提供的类型 something

【讨论】:

【参考方案14】:

尽管 instanceof 可能比 typeof 快一点,但我更喜欢第二个,因为它可能具有魔力:

function Class() ;
Class.prototype = Function;

var funcWannaBe = new Class;

console.log(funcWannaBe instanceof Function); //true
console.log(typeof funcWannaBe === "function"); //false
funcWannaBe(); //Uncaught TypeError: funcWannaBe is not a function

【讨论】:

【参考方案15】:

我会推荐使用原型的callback.isFunction()

他们已经发现了差异,你可以相信他们的原因。

我猜其他的 JS 框架也有这样的东西。

instanceOf 不会在其他窗口中定义的函数上工作,我相信。 他们的功能与您的window.Function不同。

【讨论】:

【参考方案16】:

其他显着的实际差异:

// Boolean

var str3 = true ;

alert(str3);

alert(str3 instanceof Boolean);  // false: expect true  

alert(typeof str3 == "boolean" ); // true

// Number

var str4 = 100 ;

alert(str4);

alert(str4 instanceof Number);  // false: expect true   

alert(typeof str4 == "number" ); // true

【讨论】:

【参考方案17】:

两者在功能上相似,因为它们都返回类型信息,但我个人更喜欢instanceof,因为它比较的是实际类型而不是字符串。类型比较不太容易出现人为错误,而且它在技术上更快,因为它比较内存中的指针而不是进行整个字符串比较。

【讨论】:

在某些情况下,instanceof 无法按预期工作,而 typeof 工作良好...developer.mozilla.org/En/Core_JavaScript_1.5_Reference/… instanceof 与同一窗口中的对象一起使用。如果您使用 iframe/frame 或弹出窗口,每个 (i)frame/window 都有自己的“功能”对象,如果您尝试比较来自另一个 (i)frame/window 的对象,instanceof 将失败。 typeof 在所有情况下都可以使用,因为它返回字符串“function”。 jsperf.com/typeof-function-vs-instanceof/3 我在 Chrome 和 FF3.X 上试过,“typeof”方法更快。 这只是错误的。它们不相同。它们并非都适用于所有相同的情况,尤其是跨不同的 JavaScript VM 和浏览器。 您的回答是“两者在功能上基本相同。”恕我直言,这显然是错误的。正如我在回答中概述和解释的那样,这两种选择都不适用于任何情况——尤其是跨浏览器。更好的方法是将两者与 || 一起使用运算符。【参考方案18】:

instanceof 不适用于基元,例如 "foo" instanceof String 将返回 falsetypeof "foo" == "string" 将返回 true

另一方面,typeof 在自定义对象(或类,无论你想如何称呼它们)方面可能不会做你想做的事。例如:

function Dog() 
var obj = new Dog;
typeof obj == 'Dog' // false, typeof obj is actually "object"
obj instanceof Dog  // true, what we want in this case

碰巧函数既是“函数”基元又是“函数”的实例,这有点奇怪,因为它不像其他基元类型那样工作。

(typeof function() == 'function') == (function() instanceof Function)

但是

(typeof 'foo' == 'string') != ('foo' instanceof String)

【讨论】:

【参考方案19】:

我在 Safari 5 和 Internet Explorer 9 中发现了一些非常有趣(读作“可怕”)的行为。我在 Chrome 和 Firefox 中使用它并取得了巨大成功。

if (typeof this === 'string') 
    doStuffWith(this);

然后我在IE9中测试,完全不行。大惊喜。但在 Safari 中,它是断断续续的!于是我开始调试,我发现 Internet Explorer 总是返回false。但最奇怪的是,Safari 似乎在其 JavaScript VM 中进行了某种优化,它是 truefirst 时间,但 false每次你点击重新加载!

我的大脑几乎要爆炸了。

所以现在我决定了:

if (this instanceof String || typeof this === 'string')
    doStuffWith(this.toString());

现在一切正常。请注意,您可以调用"a string".toString(),它只返回字符串的副本,即

"a string".toString() === new String("a string").toString(); // true

所以从现在开始我会同时使用这两个。

【讨论】:

【参考方案20】:

显着的实际差异:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

别问我为什么。

【讨论】:

因为这里的str 是字符串原语,而不是字符串对象。数字原语和布尔原语也是如此,它们不是其“构造”对应物的实例,即字符串、数字和布尔对象。 JavaScript 在需要时自动将这三个原语转换为对象(例如利用对象原型链上的方法)。在实际差异的另一面,instanceof 更适合检查数组,因为 typeof [] == "object" // true.【参考方案21】:

使用 typeof 的一个很好的理由是变量可能未定义。

alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception

使用 instanceof 的一个很好的理由是变量可能为空。

var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar  instanceof Object); // alerts "false"

所以在我看来,这实际上取决于您检查的可能数据类型。

【讨论】:

+1 还要注意 instanceof 不能与原始类型比较,typeof 可以。 在 Chrome 29.0.1541.0 dev undefined instanceof Object 中返回 false,并且不抛出异常。我不知道这种变化有多近,但它使instanceof 更具吸引力。 undefined instanceof Object 不会抛出异常,因为,嗯,undefined 已定义。该常量存在于命名空间中。当变量不存在时(例如由于拼写错误),instanceof 将抛出异常。另一方面,对不存在的变量使用 typeof 会产生“未定义”。【参考方案22】:

使用 instanceof 是因为如果您更改类的名称,您将收到编译器错误。

【讨论】:

【参考方案23】:

instanceof 在 Javascript 中可能是不稳定的 - 我相信主要框架会尽量避免使用它。不同的窗口是它可以破坏的方式之一 - 我相信类层次结构也会混淆它。

有更好的方法来测试一个对象是否是某种内置类型(这通常是你想要的)。创建实用函数并使用它们:

function isFunction(obj) 
  return typeof(obj) == "function";

function isArray(obj) 
  return typeof(obj) == "object" 
      && typeof(obj.length) == "number" 
      && isFunction(obj.push);

等等。

【讨论】:

如果您不知道: typeof 不需要括号,因为它是关键字而不是函数。恕我直言,您应该使用 === 而不是 ==。 @some 您对 typeof 的看法是正确的,但在这种情况下不需要 ===,只有当比较的值可能相等而没有相同类型时才需要它。在这里,它不能。 @some typeof 会返回字符串以外的内容吗? 因此 isArray 对于具有 push 方法和数字长度属性的堆栈对象来说是错误的。什么情况下(instanceof Array)会出错? @ChrisNoe 多帧共享对象出现问题:groups.google.com/forum/#!msg/comp.lang.javascript/XTWYCOwC96I/…【参考方案24】:

来自严格的 OO 教养,我会去

callback instanceof Function

字符串很容易出现我糟糕的拼写或其他拼写错误。另外,我觉得它读起来更好。

【讨论】:

【参考方案25】:

instanceof 也适用于 callbackFunction 的子类型时,我认为

【讨论】:

以上是关于typeof 和 instanceof 有啥区别,啥时候应该使用另一个?的主要内容,如果未能解决你的问题,请参考以下文章

js中typeof和instanceof用法区别

js中typeof和instanceof用法区别

typeof和instanceof的区别

javascript typeof 和 instanceof 的区别和联系

typeof()和instanceof()用法区别

typeof,instanceof,constructor它们的用法和区别