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

2020/09/28 22:41 · javascript ·  · 0评论

在我的情况下:

callback instanceof Function

要么

typeof callback == "function"

没关系,有什么区别?

附加资源:

JavaScript-花园typeofinstanceof

使用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的一个很好的理由是变量是否可以为null。

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

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

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

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

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

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

其他重大实际差异:

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

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

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

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

等等。

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)

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

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

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

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

检查功能时,必须始终使用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)在此处的某处评论中也简要提及了这一点。它适用于所有具有原型的产品-因此所有产品都不是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与构造函数-在Firefox 59.0b10(64位,Windows)中慢0.78倍

实际的重大差异:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

不要问我为什么。

性能

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

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

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

  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

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

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-返回true或false。随着typeof你可以得到所提供的东西的类型

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

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

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

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

使用函数声明创建函数:

function MyFunc(){  }

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

这种不同的结果可能的解释是,因为我们做了一个函数声明,typeof可以理解,这是一个function.Because typeof判断是否为上的typeof是操作上的表达,在我们的情况下实现的呼叫方法与否如果它实现方法是一个function.Otherwise不是。对于澄清检查的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断言这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

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

var d = new String("abc")

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

var d = "abc"

根据有关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

本文地址:http://javascript.askforanswer.com/typeofheinstanceofzhijianyoushenmequbieshenmeshihouyinggaishiyongvs.html
文章标签: ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!