460

在我的特殊情况下:

callback instanceof Function

或者

typeof callback == "function"

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

附加资源:

JavaScript-Garden typeof vs instanceof

4

25 回答 25

622

用于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
于 2011-07-08T14:30:26.040 回答
121

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

于 2009-05-22T19:28:10.810 回答
106

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

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

于 2010-01-20T16:35:17.860 回答
44

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

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

于 2016-01-29T09:32:07.760 回答
17

我在 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

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

于 2011-11-22T00:28:53.253 回答
9

其他显着的实际差异:

// 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
于 2011-01-20T09:20:44.870 回答
7

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

于 2009-05-22T19:27:55.990 回答
5

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

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

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

等等。

于 2009-05-22T19:41:32.403 回答
4

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/

于 2021-05-02T19:11:09.283 回答
3

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

他们已经找出了差异,你可以指望他们的原因。

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

instanceOf我相信,它不适用于其他窗口中定义的功能。它们的功能与您的window.Function.

于 2009-05-22T19:29:02.290 回答
3

instanceof不适用于原语,例如"foo" instanceof Stringwill returnfalsetypeof "foo" == "string"will return 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)
于 2012-02-03T09:42:48.667 回答
3

表现

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
于 2015-08-28T13:25:17.247 回答
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来检查功能的原因。

于 2016-07-19T23:38:33.913 回答
3

这只是对这里所有其他解释的补充知识——我建议在.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 与构造函数 - 在 Chrome 64.0.3282.167(64 位,Windows)中快 1.5 倍

Firefox 59.0b10(64 位,Windows)

类型化数组 instanceof 与构造函数 - 在 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)

字符串/数字类型与构造函数 - 在 Chrome 64.0.3282.167(64 位,Windows)中快 1.26 倍

Firefox 59.0b10(64 位,Windows)

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

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

于 2018-02-20T23:37:58.903 回答
2

显着的实际差异:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

不要问我为什么。

于 2010-08-20T14:07:56.597 回答
1

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

于 2009-05-22T19:55:36.293 回答
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"

于 2016-09-05T08:37:00.947 回答
1

无需对上述大量示例感到不知所措,只需记住两个观点:

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

  2. 对于更高级别的对象,如内置对象(String、Number、Boolean、Array..)或复杂或自定义对象,它们都是object根类型,但基于它们构建的实例类型是不同的(如 OOP 类继承概念),这里a instanceof A- 二元运算符 - 会帮助你,它将通过原型链检查正确操作数(A)的构造函数是否出现。

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

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

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

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

于 2020-03-25T13:46:08.193 回答
0

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

var d = new String("abc")

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

var d = "abc"
于 2019-12-13T14:57:03.290 回答
-1

来自严格的面向对象教育,我会去

callback instanceof Function

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

于 2009-05-22T19:29:03.850 回答
-1

尽管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
于 2016-05-23T11:39:26.267 回答
-1

另一种情况是您只能与instanceof- 它返回真或假。有了typeof你可以获得提供的东西的类型

于 2016-06-02T16:35:09.857 回答
-1

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

于 2017-09-16T22:55:38.053 回答
-1

当然有关系…………!

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

我们将同时使用function declarationFunction Constructor。我们将了解这两种不同情况下的方式typeofinstanceof行为。

使用函数声明创建函数:

function MyFunc(){  }

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

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

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

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

typeof MyFunc2 == 'function' // true

MyFunc2 instanceof Function // true

这里typeof断言thatMyFunc2是一个函数和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
于 2018-01-04T05:55:19.907 回答
-1

根据关于 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.

于 2020-05-05T14:29:52.200 回答