В чем разница между typeof и instanceof и когда следует использовать один против другого?



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



callback instanceof Function


или



typeof callback == "function"


какая разница, какая разница?



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



В JavaScript-Сад typeof vs instanceof

393   21  

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"

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

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

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

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

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

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

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

  1. 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"

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

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

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

затем я тестирую в IE9, и он вообще не работает. Большое удивление. Но в сафари, это с перерывами! Поэтому я начинаю отладку, и я нахожу, что Internet Explorer всегда возвращение false. Но самое странное, что Safari, похоже, делает какую-то оптимизацию в своем JavaScript VM, где это true the первый, но 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 может быть 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)

Typed Array instanceof vs constructor - 1.5x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59. 0b10 (64-бит, Windows)

Typed Array instanceof vs constructor - 30x faster in Firefox 59.0b10 (64-bit, 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)

String/Number typeof vs constructor - 1.26x faster in Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59. 0b10 (64-бит, Windows)

Примечание: порядок, в котором перечислены функции переключается между изображениями!

String/Number typeof vs constructor - 0.78x slower in Firefox 59.0b10 (64-bit, 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.As MyFunc2 - это функция, и он реализует 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

    Ничего не найдено.