typeof和instanceof之间有什么区别,什么时候应该使用vs?


394

在我的情况下:

callback instanceof Function

要么

typeof callback == "function"

甚至有关系吗,有什么区别?

附加资源:

JavaScript-花园typeofinstanceof


2
我在这里找到作为易于使用的解决方案的答案
CrandellWS 2014年

1
使用Object.prototype.toString ecma-international.org/ecma-262/6.0/…
rab

1
只需使用.constructor属性即可。
穆罕默德·乌默

如果您对性能有所疑问,请参见下面的答案。在两者都适用的情况下(即对象),typeof更快。
马丁·彼得

Answers:


540

使用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

11
这个答案清楚地说明了为什么instaceof 应该用于原始类型。很明显,关于自定义类型以及“对象”类型的好处,您没有选择的余地。但是,什么使函数与“简单的内置类型”融合在一起呢?我发现一个函数如何表现得像一个对象,这很奇怪,但是它的类型是“函数”,使得使用“ typeof”成为可能。但是,为什么您不鼓励instanceof?
Assimilater 2014年

4
@Assimilater您也可以将instanceof与函数一起使用,但是我认为这3条规则很容易记住,是的,函数是一个例外:)
SzymonWygnański2015年

2
另一个棘手的部分->'example string'instanceof String; // false,但是新的String('example string')instanceof String; // true
路加福音

2
@Luke通常不好用这样的“ new String”。创建一个“字符串对象”而不是一个字符串原语。见这里developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/...
科林·d

4
Use instanceof for complex built in types-这仍然容易出错。最好使用ES5 Array.isArray()等。或建议的垫片。
OrangeDog '16

122

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


8
也有一些情况下的instanceof不会按预期方式工作和typeof运算效果很好... developer.mozilla.org/En/Core_JavaScript_1.5_Reference/...
farinspace

55
instanceof适用于同一窗口中的对象。如果您使用iframe /框架或弹出窗口,则每个(i)框架/窗口都有其自己的“功能”对象,并且如果您尝试比较另一个(i)框架/窗口的对象,instanceof将失败。typeof将在所有情况下均有效,因为它返回字符串“ function”。
一些

14
jsperf.com/typeof-function-vs-instanceof/3 我在Chrome和FF3.X上尝试过,“ typeof”方法更快。
Morgan Cheng

10
这是错误的。它们是不相同的。它们不能同时在所有相同的情况下工作,尤其是在不同的JavaScript VM和浏览器上。
Justin Force

8
您的回答是“在功能上,两者基本上是相同的”。显然,这显然是错误的。正如我的回答中概述和解释的那样,这两种方法都不能在每种情况下都有效,尤其是在浏览器中。更好的方法是同时使用|| 操作员。
贾斯汀·

103

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

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

使用instanceof的一个很好的理由是变量是否可以为null。

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

因此,我认为这实际上取决于您要检查的数据类型。


11
+1还请注意,instanceof不能与基本类型进行比较,typeof可以。
蒂诺(Tino)

3
在Chrome 29.0.1541.0中,开发人员undefined instanceof Object返回false,并且不会引发异常。我不知道这种变化是最近发生的,但是它instanceof更具吸引力。
赛普拉斯弗兰肯费尔德

7
undefined instanceof Object不会因为undefined定义了eh而引发异常。该常量存在于名称空间中。当变量不存在时(例如由于输入错误),instanceof将引发异常。另一方面,在不存在的变量上使用typeof会产生“未定义”。
cleong

31

为了弄清楚,您需要知道两个事实:

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

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

同样instanceof无法检查,确切地使用了哪个构造函数创建对象,但是即使对象是从要检查的类派生的,也会返回true。在大多数情况下,这是所需的行为,但有时并非如此。因此,您需要保持头脑。

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

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

  1. typeof运算操作测试值是否属于六种基本类型之一:“ 号码 ”,“ ”,“ 布尔 ”,“ 对象 ”,“ 函数 ”或“ 不确定 ”。字符串“ 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);

upd: 自ECMAScript 2015起,还有另外一种称为Symbol的类型,它具有自己的typeof == “ symbol”

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

您可以在MDN上阅读它:(Symboltypeof)。


2
if an object is created by a given constructor 这是不正确的。 o instanceof C如果o从C.prototype继承,将返回true。您稍后在回答中提到了一些有关此内容的信息,但不是很清楚。
oyenamit

1
不正确的...从书中:“ github.com/getify/You-Dont-Know-JS ” Foo的实例;// true instanceof运算符将普通对象用作其左侧操作数,将一个函数用作其右侧操作数。问题instanceof的答案是:在a的整个[[Prototype]]链中,由Foo.prototype任意指向的对象是否出现过?
Deen John '18

1
为了更正确,我已经编辑了答案。感谢您的评论。
Vladimir Liubimov

另外,增加了装箱/拆箱问题的说明。
Vladimir Liubimov

15

我已经在Safari 5和Internet Explorer 9中发现了一些非常有趣(称为“可怕”)的行为。我在Chrome和Firefox中成功使用了此行为。

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

然后,我在IE9中进行了测试,但它根本不起作用。大惊喜。但是在Safari中,它是断断续续的!因此,我开始调试,发现Internet Explorer 总是在返回false。但最奇怪的是,Safari浏览器似乎是在做某种在它的JavaScript虚拟机优化的地方是true第一时间,但false 每一次你打重装!

我的大脑快要爆炸了。

所以现在我已经解决了:

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

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

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

因此,从现在开始,我将同时使用两者。


8

其他重大实际差异:

// 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

7

instanceof我也认为当callback是的子类型时Function


4

instanceofJavascript中的代码可能会出现问题-我相信主要框架会尽量避免使用它。不同的窗口是打破窗口的方式之一-我相信类层次结构也可能使窗口混淆。

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

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

等等。


2
如果您不知道:typeof不需要括号,因为它是关键字而不是函数。恕我直言,您应该使用===而不是==。
一些

5
@some您对typeof是正确的,但是在这种情况下,不需要===,仅当要比较的值可以相等而没有相同类型时才需要。在这里,它不能。
妮可

@of typeof会返回字符串以外的东西吗?
肯尼思·J

因此,对于具有push方法和数字长度属性的堆栈对象,isArray是错误的。在什么情况下(instanceof Array)会出错?
克里斯·诺

@ChrisNoe该问题出现在多个框架之间共享的对象上:groups.google.com/forum

3

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)

3

我建议使用原型的callback.isFunction()

他们已经找出了区别,您可以指望他们的理由。

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

instanceOf我相信,在其他窗口中定义的功能上将无法使用。它们的功能与您的不同window.Function


3

检查功能时,必须始终使用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

@amn对我来说,这是Function 的损坏实例。它变得像属性lengthnamecall从功能,但所有的人都停止活动。更糟糕的是,它不能被调用并TypeError说出:f is not a function
maaartinus

2

实际的重大差异:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

不要问我为什么。


11
因为这里str是字符串基元,而不是字符串对象。数字基元和布尔基元也是如此,它们不是“构造的”对应物,字符串,数字和布尔对象的实例。JavaScript会在需要时自动将这三个原语转换为对象(例如,使用对象原型链上的方法)。在实际差异的另一面,instanceof更适合检查数组,因为typeof [] == "object" // true
Andy E 2010年

2

性能

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

1
typeof subject ==“ array”应该返回false。主题的类型是“对象”。
Shardul '17

为什么typeof更快?是Javascript中间文字字符串?
Gregory Magarshak '17

原因是:instanceof 始终遵循对象的原型链,因此性能损失将取决于原型链中的类instanceof是否受到测试。因此,对于较短的继承链,处罚将较低(例如[] instanceof Array{} instanceof Object),而对于较长的处罚将更大。因此,如果同时obj instanceof SomeClasstypeof obj !== 'string'手段,从你的一些假设性的代码的角度相同(FE如果你只是做一个试验if,而不是switch通过多类等-ing),那么你最好挑第二个,性能,明智的,
ankhzet

2

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

TL; DR:typeof没有选择的情况下,并且当您知道自己不关心原型链时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)

类型化数组instanceof vs构造函数-Chrome 64.0.3282.167(64位,Windows)中速度提高了1.5倍

Firefox 59.0b10(64位,Windows)

类型化数组instanceof vs构造函数-在Firefox 59.0b10(64位,Windows)中快30倍

出于好奇,我做了一个快速的玩具基准测试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)

字符串/数字typeof vs构造函数-Chrome 64.0.3282.167(64位,Windows)中快1.26倍

Firefox 59.0b10(64位,Windows)

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

字符串/数字typeof vs构造函数-在Firefox 59.0b10(64位,Windows)中慢0.78倍


1

使用instanceof,因为如果您更改类的名称,则会出现编译器错误。


1

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)吗?
xgqfrms

0

来自严格的面向对象的培养,我会去

callback instanceof Function

字符串容易产生我的拼写或其他拼写错误。另外我觉得它读起来更好。


0

尽管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


0

考虑到性能,您最好将typeof与典型的硬件配合使用,如果创建的脚本具有1000万次迭代循环,则指令:typeof str =='string'将花费9ms,而'string'instanceof String将花费19ms


0

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

让我们看一下示例,在我们的示例中,我们将以两种不同的方式声明函数。

我们将同时使用function declarationFunction Constructor。我们将如何SE typeofinstanceof的行为在这两个不同的方案。

使用函数声明创建函数:

function MyFunc(){  }

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

这种不同的结果可能的解释是,因为我们做了一个函数声明,typeof可以理解,这是一个function.Because typeof判断是否为上的typeof是操作上的表达,在我们的情况下实现的呼叫方法与否。如果实现了方法,则为函数,否则为非函数。为明确起见,检查ecmascript规范中的typeofMyFunc Call

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

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运算符可以成功断言我们正在此处处理一个函数,它比更加安全instanceofinstanceof在以下情况下会失败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

任何对此答案的建设性批评将不胜感激。
AL-zami

0

确切地说, 应该使用instanceof,其中通过构造函数(通常是自定义类型)创建值,例如

var d = new String("abc")

typeof则检查仅由赋值创建的值,例如

var d = "abc"

0

无需过多考虑以上示例,只需记住以下两个观点:

  1. typeof var;是一元运算符,将返回var的原始类型或根类型。这样它会返回原始类型(stringnumberbigintbooleanundefined,和symbol)或object类型。

  2. 对于更高级别的对象,例如内置对象(String,Number,Boolean,Array ..)或复杂或自定义对象,它们都是object根类型,但是基于它们建立的实例类型是多种多样的(例如OOP类)继承概念),这里a instanceof A-一个二进制运算符-将为您提供帮助,它将遍历原型链以检查是否出现了正确的操作数(A)的构造函数。

因此,每当您要检查“根类型”或使用原始变量时,请使用“ typeof”,否则请使用“ instanceof”。

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

另一方面,function也是一种特殊情况,它是内置对象但typeof返回function

如您所见,instanceof必须遍历原型链,而typeof只需一次检查根类型,因此很容易理解为什么typeofinstanceof


0

根据有关typeof的MDN文档,使用“ new”关键字实例化的对象的类型为“ object”:

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';

虽然有关的instanceof文档点是:

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

因此,如果不管某个东西是如何创建的,都要检查例如某个东西是否是字符串,那么最安全的方法就是使用instanceof

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.