В чем разница между typeof и 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" 

Так что, на мой взгляд, это будет зависеть от того, какие типы данных вы проверяете.

Чтобы все было ясно, вам нужно знать два факта:

  1. Оператор instanceof проверяет, появляется ли свойство прототипа конструктора в цепочке прототипов объекта. В большинстве случаев это означает, что объект был создан с помощью этого конструктора или его потомка. Но также прототип может быть установлен явно методом Object.setPrototypeOf() (ECMAScript 2015) или свойством __proto__ (старые браузеры, устаревшие). Из-за проблем с производительностью не рекомендуется изменять прототип объекта.

Таким образом, instanceof применим только к объектам. В большинстве случаев вы не используете конструкторы для создания строк или чисел. Ты можешь. Но вы почти никогда этого не делаете.

Также instanceof не может проверить, какой именно конструктор использовался для создания объекта, но вернет true, даже если объект получен из проверяемого classа. В большинстве случаев это желаемое поведение, но иногда это не так. Поэтому вам нужно держать этот ум.

Другая проблема заключается в том, что разные области применения имеют разные среды исполнения. Это означает, что они имеют разные встроенные функции (разные глобальные объекты, разные конструкторы и т. Д.). Это может привести к неожиданным результатам.

Например, [] instanceof window.frames[0].Array вернет false , потому что Array.prototype !== window.frames[0].Array и массивы наследуются от первого.
Кроме того, он не может использоваться для неопределенного значения, потому что у него нет прототипа.

  1. Оператор typeof проверяет, принадлежит ли значение одному из шести основных типов : « число », « строка », « логическое », « объект », « функция » или « неопределенное ». Если строка «объект» принадлежит всем объектам (кроме функций, которые являются объектами, но имеют собственное значение в операторе typeof), а также «нулевое» значение и массивы (для «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, который имеет свой собственный символ типа == ==.

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

Вы можете прочитать об этом на MDN: ( Symbol , typeof ).

Я обнаружил некоторые действительно интересные (прочитанные как «ужасные») поведение в Safari 5 и Internet Explorer 9. Я использовал это с большим успехом в Chrome и Firefox.

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

Затем я тестирую в IE9, и он вообще не работает. Большой сюрприз. Но в Сафари это прерывисто! Поэтому я начинаю отладку, и обнаруживаю, что 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 

Поэтому я буду использовать и то и другое.

instanceof также работает, когда callback является подтипом Function , я думаю

Другие Значительные практические различия:

 // 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 в Javascript может быть шелушащимся – я считаю, что основные структуры пытаются избежать его использования. Различные windows – один из способов, которыми он может сломаться – я считаю, что иерархии classов тоже могут смутить.

Существуют более эффективные способы проверки того, является ли объект определенным встроенным типом (обычно это то, что вы хотите). Создайте служебные функции и используйте их:

 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 вернет false тогда как typeof "foo" == "string" вернет true .

С другой стороны, typeof , вероятно, не будет делать то, что вы хотите, когда речь идет о пользовательских объектах (или classах, что бы вы ни называли). Например:

 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 не будет работать над функциями, определенными в других windowsх, я считаю. Их функция отличается от вашего window.Function . 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 для проверки функции.

Значительная практическая разница:

 var str = 'hello word'; str instanceof String // false typeof str === 'string' // true 

Не спрашивай меня, почему.

Представление

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 

Это просто дополнительные знания ко всем остальным объяснениям здесь – я не предлагаю использовать .constructor повсюду.

TL; DR: В ситуациях, когда typeof не является опцией, и когда вы знаете, что вам не нужна цепочка прототипов , Object.prototype.constructor может быть жизнеспособной или даже лучшей альтернативой, чем instanceof :

 x instanceof Y x.constructor === Y 

Он был в стандарте с 1,1, поэтому не стоит беспокоиться о обратной совместимости.

Мухаммед Умер кратко упомянул об этом и в комментарии здесь. Он работает на все с прототипом – так что все не 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)

Типичный массив экземпляра vs constructor - в 1,5 раза быстрее в Chrome 64.0.3282.167 (64-разрядный, Windows)

Firefox 59.0b10 (64-разрядная, Windows)

Typed Array instanceof vs constructor - в 30 раз быстрее в 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)

String / Number typeof vs constructor - в 1,6 раза быстрее в Chrome 64.0.3282.167 (64-разрядная, Windows)

Firefox 59.0b10 (64-разрядная, Windows)

ПРИМЕЧАНИЕ. Порядок, в котором перечислены функции, переключается между изображениями!

String / Number typeof vs constructor - 0.78x медленнее в Firefox 59.0b10 (64-разрядная, Windows)

Используйте instanceof, потому что если вы измените имя classа, вы получите ошибку компилятора.

 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" 

Исходя из строгого воспитания ОО, я поеду

 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 с типичным оборудованием, если вы создадите скрипт с циклом из 10 миллионов итераций, команда: typeof str == ‘string’ займет 9 мс, в то время как «string» instanceof String займет 19 мс

Конечно, это важно ……..!

Давайте рассмотрим это с помощью примеров. В нашем примере мы объявим функцию двумя разными способами.

Мы будем использовать как function declaration и конструктор функций . Мы увидим, как typeof и instanceof ведут себя в этих двух разных сценариях.

Создать функцию с помощью объявления функции:

 function MyFunc(){ } typeof Myfunc == 'function' // true MyFunc instanceof Function // false 

Возможным объяснением такого разного результата является то, что, поскольку мы сделали объявление функции, typeof может понять, что это функция. typeof проверяет, является ли выражение, на котором работает типof, в нашем случае MyFunc реализовал метод вызова или нет . Если он реализует метод Call это функция. В противном случае нет. Для уточнения проверьте спецификацию ecmascript для 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 MyFunc2 уже знаем MyFunc2 проверки, если MyFunc2 реализовал метод Call или нет. Поскольку MyFunc2 является функцией и реализует метод call , вот как typeof знает, что это функция. с другой стороны, мы использовали function constructor для создания MyFunc2 , он становится экземпляром конструктора Function constructor Именно поэтому instanceof также разрешает true .

Что безопаснее использовать?

Как мы видим, в обоих случаях оператор typeof может успешно утверждать, что мы имеем дело с функцией здесь, это безопаснее, чем instanceof . instanceof будет работать в случае function declaration потому что function declarations не являются экземпляром конструктора Function constructor .

Наилучшая практика:

Как предложил Гэри Рафферти , лучший способ – использовать оба типаof и instanceof вместе.

  function isFunction(functionItem) { return typeof(functionItem) == 'function' || functionItem instanceof Function; } isFunction(MyFunc) // invoke it by passing our test function as parameter 
  • Браузер командной строки с поддержкой js
  • Google DFP - изменение размера пользовательского объявления SafeFrame внешнего контейнера iframe изнутри (развернуть объявление)
  • Typcript: не может получить доступ к значению элемента в унаследованном конструкторе classа
  • JavaScript% (modulo) дает отрицательный результат для отрицательных чисел
  • Как проверить, содержит ли строка текст из массива подстрок в JavaScript?
  • Поддерживает ли Javascript / EcmaScript3 синтаксический анализ даты ISO8601?
  • Как удалить стиль, добавленный функцией .css ()?
  • Расширять примитивы без их прототипирования
  • Как форматировать числа, добавив 0 к одноразрядным номерам?
  • Внедрение переменной javascript перед скриптом содержимого
  • Как получить ключ в объекте JavaScript по его значению?
  • Давайте будем гением компьютера.