typeof和instanceof之间的区别是什么?何时应该使用另一个?

时间:2009-05-22 19:24:20

标签: javascript instanceof typeof

在我的特定情况下:

callback instanceof Function

typeof callback == "function"

甚至重要,有什么区别?

其他资源:

JavaScript-Garden typeof vs instanceof

25 个答案:

答案 0 :(得分:472)

对自定义类型使用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

答案 1 :(得分:120)

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

答案 2 :(得分:94)

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

所以我认为这取决于您正在检查的数据类型。

答案 3 :(得分:26)

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

  1. instanceof 运算符会测试构造函数原型属性是否出现在原型链的任何位置宾语。在大多数情况下,这意味着使用此构造函数或其后代对象创建。但也可以通过Object.setPrototypeOf()方法(ECMAScript 2015)或__proto__属性(旧浏览器,不推荐使用)明确设置原型。但是,由于性能问题,不建议更改对象的原型。
  2. 因此instanceof仅适用于对象。在大多数情况下,您不使用构造函数来创建字符串或数字。您可以。但你几乎从不这样做。

    instanceof也无法检查,确切地使用了哪个构造函数来创建对象,但是返回true,即使object是从被检查的类派生的。在大多数情况下,这是期望的行为,但有时并非如此。所以你需要保持这种想法。

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

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

    1. typeof 运算符测试值是否属于六种基本类型之一:“数字”,“字符串“,”布尔“,”对象“,”功能“或”未定义“。字符串“object”属于所有对象(函数除外,它们是对象,但在typeof运算符中有自己的值),还有“null”值和数组(对于“null”,它是一个bug,但是这个bug太旧了,所以它成为一个标准)。它不依赖于构造函数,即使值未定义也可以使用。但它没有提供有关对象的任何细节。因此,如果您需要它,请转到instanceof。
    2. 现在让我们谈谈一件棘手的事情。如果使用构造函数创建基本类型怎么办?

      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)。

答案 4 :(得分:14)

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

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

然后我在IE9中测试,它根本不起作用。大惊喜。但在Safari中,它是断断续续的!所以我开始调试,我发现Internet Explorer 总是返回false。但最奇怪的是Safari似乎在其JavaScript VM中进行了某种优化,true 第一次时,false 每次你重新加载!

我的大脑几乎爆炸了。

所以现在我已经解决了这个问题:

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

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

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

所以从现在开始我都会使用它们。

答案 5 :(得分:7)

其他重大的实际差异:

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

答案 6 :(得分:7)

instanceofcallback的子类型时,

Function也有效,我认为

答案 7 :(得分:4)

Javascript中的

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

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

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

等等。

答案 8 :(得分:3)

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

他们已经找出了差异,你可以依靠他们的理由。

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

我相信,

instanceOf无法在其他窗口中定义的函数上运行。 他们的功能与您的window.Function不同。

答案 9 :(得分: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来检查函数。

答案 10 :(得分:3)

instanceof不适用于基元,例如"foo" instanceof String将返回false,而typeof "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)

答案 11 :(得分:2)

<强>性能

typeof在两者都适用的情况下比instanceof快。

根据您的引擎,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

答案 12 :(得分: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)

Typed Array instanceof vs constructor - 1.5x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10(64位,Windows)

Typed Array instanceof vs constructor - 30x faster in Firefox 59.0b10 (64-bit, 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)

String/Number typeof vs constructor - 1.26x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10(64位,Windows)

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

String/Number typeof vs constructor - 0.78x slower in Firefox 59.0b10 (64-bit, Windows)

答案 13 :(得分:2)

显着的实际差异:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

不要问我为什么。

答案 14 :(得分:1)

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

答案 15 :(得分: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"

答案 16 :(得分:1)

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

  1. typeof var;是一元运算符,将返回var的原始类型或根类型。因此它将返回原始类型(stringnumberbigintbooleanundefinedsymbol)或{{1} }类型。

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

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

a instanceof A是一个特例,看似原始,但实际上是对象的特例。使用null来检查是否为空。

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

您可以看到function必须经过原型链,而instanceof只需检查一次根类型,因此很容易理解为什么typeoftypeof更快

答案 17 :(得分: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

答案 18 :(得分:0)

还有一种情况是,您只能与instanceof进行整理 - 它返回true或false。使用typeof,您可以获得某种

的类型

答案 19 :(得分:0)

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

答案 20 :(得分:0)

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

让我们通过示例来解决这个问题。在我们的示例中,我们将以两种不同的方式声明函数。

我们将同时使用 function declaration Function Constructor 。我们将了解 typeof instanceof 在这两种不同情况下的表现。

使用函数声明创建函数:

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

答案 21 :(得分:0)

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

callback instanceof Function

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

答案 22 :(得分:0)

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

var d = new String("abc")

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

var d = "abc"

答案 23 :(得分:0)

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

在字符串原始数据和字符串对象的情况下,typeof 返回以下内容:

const toUpdate = {
  ...
  [key]: value
}

or 

toUpdate[key] = value;

or

toUpdate[`${key}`] = value;

any of the above works

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

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

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

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

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

答案 24 :(得分:-1)

根据MDN documentation about typeof,用“ 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';

documentation about instanceof指出:

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

因此,如果您想检查例如无论什么东西都是字符串,最安全的方法是使用instanceof