В чем разница между typeof и instanceof и когда следует использовать один против другого?
в моем конкретном случае:
callback instanceof Function
или
typeof callback == "function"
какая разница, какая разница?
Дополнительный Ресурс:
В JavaScript-Сад typeof vs instanceof
21 ответов:
использовать
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"Так на самом деле, на мой взгляд, это будет зависеть от того, какой тип данных вы проверяете.
чтобы прояснить ситуацию, вам нужно знать два факта:
- The instanceof оператор проверяет, является ли прототип собственность на конструктор появляется в любом месте цепи прототипов объекта. В большинстве случаев это означает, что объект создано С помощью этого конструктора, или на своего потомка. Но также прототип может быть установлен явно с помощью
Object.setPrototypeOf()метод (ECMAScript 2015) или кстати__proto__свойство (старые браузеры, устаревшим). Изменение прототипа объекта не рекомендуется, из-за проблем с производительностью.таким образом, instanceof применим только к объектам. В большинстве случаев вы не используете конструкторы для создания строк или чисел. Вы можете. Но ты почти никогда этого не делаешь.
также instanceof не может проверить, какой именно конструктор был использован для создания объекта, но вернет true, даже если объект является производным от класс, который проверяется. В большинстве случаев это желаемое поведение, но иногда это не так. Так что вам нужно сохранить этот ум.
другая проблема заключается в том, что разные области имеют разные среды выполнения. Это означает, что они имеют разные встроенные модули (разные глобальные объекты, разные конструкторы и т. д.). Это может привести к неожиданным результатам.
например,
[] instanceof window.frames[0].Arrayвернутсяfalse, потому чтоArray.prototype !== window.frames[0].Arrayи массивы наследуют от бывшего.
Также, он не может быть использован на неопределенное значение, потому что он не имеет прототипа.
- The typeof оператор проверяет, принадлежит ли значение один из шести основных типов: "","строка","boolean","объект","функции" или "неопределено". Где строка "объект" принадлежит всем объектам (кроме функций, которые являются объектами, но имеют свое собственное значение в оператор 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 test(){ console.log(typeof this); } test.apply(5);чтобы избежать этого, вы можете использовать "строгий режим":
function test(){ 'use strict'; console.log(typeof this); } test.apply(5);upd: Начиная С ECMAScript 2015, есть еще один тип под названием Symbol, который имеет свой собственный typeof =="знак".
console.log(typeof Symbol()); // expected output: "symbol"
я обнаружил некоторые действительно интересные (читается как "ужасное") поведение в Safari 5 и Internet Explorer 9. Я использовал это с большим успехом в Chrome и Firefox.
if (typeof this === 'string') { doStuffWith(this); }затем я тестирую в IE9, и он вообще не работает. Большое удивление. Но в сафари, это с перерывами! Поэтому я начинаю отладку, и я нахожу, что Internet Explorer всегда возвращение
false. Но самое странное, что Safari, похоже, делает какую-то оптимизацию в своем JavaScript VM, где этоtruethe первый, но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в Javascript может быть flaky-я считаю, что основные фреймворки стараются избегать его использования. Различные окна-это один из способов, которым он может сломаться - я считаю, что иерархии классов могут также запутать его.есть лучшие способы для проверки того, является ли объект определенным встроенным типом (который обычно является тем, что вы хотите). Создайте служебные функции и используйте их:
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вероятно, не будет делать то, что вы хотите, когда речь заходит о пользовательских объектах (или классах, как бы вы их ни называли). Например: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для проверки функции.
существенное практическое значение:
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.перфорация.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.перфорация.зона/Вид/typeof на-против-конструктор-строка или число-1519142623570
Примечание: порядок, в котором перечислены функции переключается между изображениями!
Chrome 64.0.3282.167 (64-бит, Windows)
Firefox 59. 0b10 (64-бит, Windows)
Примечание: порядок, в котором перечислены функции переключается между изображениями!
использовать оператор 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"
исходя из строгого воспитания ОО, я бы пошел на
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 мс
конечно, это важно........ !
давайте пройдемся с этим examples.In в нашем примере мы объявим функцию двумя различными способами.
мы будем использовать как
function declarationи Конструктор Функция. Мы увидим, какtypeofиinstanceofведет себя в этих двух различных вариант развития событий.создать функцию с помощью объявления функции:
function MyFunc(){ } typeof Myfunc == 'function' // true MyFunc instanceof Function // falseвозможным объяснением такого различного результата является, как мы сделали объявление функции,
typeofможно понять, что это функция.Потому чтоtypeofпроверяет, является ли выражение, на котором typeof работает, в нашем случае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оператора.Мы уже знаемtypeofпроверить, еслиMyFunc2реализовалаCallметод или not.AsMyFunc2- это функция, и он реализуетcallметод, вот какtypeofзнает, что это функция.С другой стороны, мы использовалиfunction constructorсоздатьMyFunc2, он становится экземпляромFunction constructor.Вот почемуinstanceofтакже решаетtrue.что безопаснее использовать ?
как мы видим, в обоих случаях
typeofоператор может успешно утверждать, что мы имеем дело с функцией здесь,это безопаснее, чемinstanceof.instanceofпотерпит неудачу в случаеfunction declaration, потому чтоfunction declarationsне являются экземпляромFunction constructor.рекомендация :
как Гари Рафферти предположил, что лучший способ следует использовать как оператор instanceof typeof и вместе.
function isFunction(functionItem) { return typeof(functionItem) == 'function' || functionItem instanceof Function; } isFunction(MyFunc) // invoke it by passing our test function as parameter




Comments