В чем разница между typeof и instanceof и когда один из них должен использоваться по сравнению с другим? - PullRequest
345 голосов
/ 22 мая 2009

В моем конкретном случае:

callback instanceof Function

или

typeof callback == "function"

это вообще имеет значение, какая разница?

Дополнительный ресурс:

JavaScript-Garden typeof против instanceof

Ответы [ 21 ]

473 голосов
/ 08 июля 2011

Используйте 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
120 голосов
/ 22 мая 2009

Оба схожи по функциональности, потому что оба возвращают информацию о типах, однако я лично предпочитаю instanceof, потому что он сравнивает фактические типы, а не строки. Сравнение типов менее подвержено человеческим ошибкам и технически быстрее, поскольку сравнивает указатели в памяти, а не выполняет сравнение целых строк.

94 голосов
/ 20 января 2010

Хорошая причина использовать 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"

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

26 голосов
/ 29 января 2016

Чтобы прояснить ситуацию, вам нужно знать два факта:

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

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

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

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

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

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

14 голосов
/ 22 ноября 2011

Я обнаружил действительно интересное (читаемое как «ужасное») поведение в 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

Так что теперь я буду использовать оба.

7 голосов
/ 22 мая 2009

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

7 голосов
/ 20 января 2011

Прочие Существенные практические различия:

// 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
4 голосов
/ 22 мая 2009

instanceof в Javascript может быть нестабильным - я считаю, что основные фреймворки стараются избегать его использования. Различное окно - это один из способов его разрушения - я полагаю, что иерархия классов может также запутать его.

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

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

и т. Д.

3 голосов
/ 20 июля 2016

При проверке функции всегда следует использовать 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 для проверки функции.

3 голосов
/ 22 мая 2009

Я бы рекомендовал использовать прототип callback.isFunction().

Они выяснили разницу, и вы можете рассчитывать на их причину.

Полагаю, другие JS-фреймворки тоже есть.

instanceOf не будет работать с функциями, определенными в других окнах, я полагаю. Их функция отличается от вашей window.Function.

...