在我的特殊情况下:
callback instanceof Function
或者
typeof callback == "function"
有没有关系,有什么区别?
附加资源:
JavaScript-Garden typeof vs instanceof
在我的特殊情况下:
callback instanceof Function
或者
typeof callback == "function"
有没有关系,有什么区别?
附加资源:
JavaScript-Garden typeof vs instanceof
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
两者在功能上相似,因为它们都返回类型信息,但是我个人更喜欢它,instanceof
因为它比较的是实际类型而不是字符串。类型比较不太容易出现人为错误,并且它在技术上更快,因为它比较内存中的指针而不是进行整个字符串比较。
使用 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"
因此,在我看来,这实际上取决于您正在检查的可能数据类型。
为了清楚起见,您需要知道两个事实:
Object.setPrototypeOf()
__proto__
因此 instanceof 仅适用于对象。在大多数情况下,您不会使用构造函数来创建字符串或数字。你可以。但你几乎从不这样做。
instanceof 也无法检查究竟是哪个构造函数用于创建对象,但会返回 true,即使对象是从被检查的类派生的。在大多数情况下,这是所需的行为,但有时并非如此。所以你需要保持这种心态。
另一个问题是不同的作用域有不同的执行环境。这意味着它们具有不同的内置函数(不同的全局对象、不同的构造函数等)。这可能会导致意想不到的结果。
例如,[] instanceof window.frames[0].Array
将返回false
,因为Array.prototype !== window.frames[0].Array
和数组继承自前者。
此外,它不能用于未定义的值,因为它没有原型。
现在让我们谈谈一件棘手的事情。如果你使用构造函数来创建一个原始类型呢?
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"
我在 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
所以从现在开始我会同时使用这两种方法。
其他显着的实际差异:
// 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
instanceof
我认为当callback
是 的子类型时也有效Function
instanceof
在 Javascript 中可能会不稳定——我相信主要框架会尽量避免使用它。不同的窗口是它可以破坏的方式之一 - 我相信类层次结构也会混淆它。
有更好的方法来测试一个对象是否是某种内置类型(这通常是你想要的)。创建实用函数并使用它们:
function isFunction(obj) {
return typeof(obj) == "function";
}
function isArray(obj) {
return typeof(obj) == "object"
&& typeof(obj.length) == "number"
&& isFunction(obj.push);
}
等等。
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/
我建议使用原型的callback.isFunction()
.
他们已经找出了差异,你可以指望他们的原因。
我猜其他 JS 框架也有这样的东西。
instanceOf
我相信,它不适用于其他窗口中定义的功能。它们的功能与您的window.Function
.
instanceof
不适用于原语,例如"foo" instanceof String
will returnfalse
而typeof "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)
表现
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
检查功能时,必须始终使用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
来检查功能的原因。
这只是对这里所有其他解释的补充知识——我不建议在.constructor
任何地方使用。
TL;DR:在typeof
无法选择的情况下,并且当您知道自己不关心原型链时,Object.prototype.constructor
可能是一个可行甚至更好的替代方案instanceof
:
x instanceof Y
x.constructor === Y
它自 1.1 以来一直在标准中,因此无需担心向后兼容性。
Muhammad Umer 也在此处某处的评论中简要提到了这一点。它适用于带有原型的所有东西 - 所以一切都不是null
或undefined
:
// (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)
注意:列出功能的顺序在图像之间切换!
显着的实际差异:
var str = 'hello word';
str instanceof String // false
typeof str === 'string' // true
不要问我为什么。
使用 instanceof 因为如果您更改类的名称,您将收到编译器错误。
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"
无需对上述大量示例感到不知所措,只需记住两个观点:
typeof var;
是一元运算符,将返回原始类型或 var 的根类型。这样它将返回原始类型(string
、number
、bigint
、boolean
、undefined
和symbol
)或object
类型。
对于更高级别的对象,如内置对象(String、Number、Boolean、Array..)或复杂或自定义对象,它们都是object
根类型,但基于它们构建的实例类型是不同的(如 OOP 类继承概念),这里a instanceof A
- 二元运算符 - 会帮助你,它将通过原型链检查正确操作数(A)的构造函数是否出现。
因此,每当您想检查“根类型”或使用原始变量时 - 使用“typeof”,否则使用“instanceof”。
null
是一个特例,看起来很原始,但确实是对象的特例。用于a === null
检查空值。
另一方面,function
也是一种特殊情况,即内置对象但typeof
返回function
如您所见,instanceof
必须通过原型链,同时typeof
只需检查一次根类型,因此很容易理解为什么typeof
比instanceof
确切地说 ,应该在通过构造函数(通常是自定义类型)创建值的地方使用instanceof,例如
var d = new String("abc")
而typeof检查仅由分配创建的值,例如
var d = "abc"
来自严格的面向对象教育,我会去
callback instanceof Function
字符串很容易出现我糟糕的拼写或其他拼写错误。另外,我觉得它读起来更好。
尽管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
另一种情况是您只能与instanceof
- 它返回真或假。有了typeof
你可以获得提供的东西的类型
考虑到性能,您最好将 typeof 与典型硬件一起使用,如果您创建一个包含 1000 万次迭代循环的脚本,则指令: typeof str == 'string' 将花费 9ms 而 'string' instanceof String 将花费 19ms
当然有关系…………!
让我们通过示例来完成。在我们的示例中,我们将以两种不同的方式声明函数。
我们将同时使用function declaration
和 Function Constructor。我们将了解这两种不同情况下的方式typeof
和instanceof
行为。
使用函数声明创建函数:
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
根据关于 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
.