javascript - typeof ile instanceof arasındaki fark nedir ve biri diğerine kıyasla ne zaman kullanılmalıdır?
Benim özel durumumda:
callback instanceof Function
veya
typeof callback == "function"
önemli mi ki, fark ne?
Ek Kaynak:
JavaScript-Garden typeof ve instanceof
Cevap #1
Özel türler için instanceof kullanın:
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
Basit yerleşik türler için typeof kullanın:
'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
Karmaşık yerleşik türler için instanceof kullanın:
/regularexpression/ instanceof RegExp; // true
typeof /regularexpression/; // object
[] instanceof Array; // true
typeof []; //object
{} instanceof Object; // true
typeof {}; // object
Ve sonuncusu biraz zor:
typeof null; // object
Cevap #2
İkisi de işlevsellik açısından benzerdir çünkü ikisi de tür bilgisi döndürür, ancak kişisel olarak instanceof'u tercih ediyorum çünkü bu, stringler yerine gerçek türleri karşılaştırıyor. Tür karşılaştırması insan hatasına daha az açıktır ve teknik olarak daha hızlıdır çünkü tüm string karşılaştırmaları yapmak yerine bellekteki göstergeleri karşılaştırır.
Cevap #3
typeof kullanmak için iyi bir sebep, değişkenin tanımsız olabileceği durumdur.
alert(typeof undefinedVariable); // alerts the string "undefined"
alert(undefinedVariable instanceof Object); // throws an exception
instanceof kullanmanın iyi bir nedeni, değişkenin null olabileceği durumdur.
var myNullVar = null;
alert(typeof myNullVar ); // alerts the string "object"
alert(myNullVar instanceof Object); // alerts "false"
Yani gerçekten bence bu, hangi tür olası verileri kontrol ettiğinize bağlı olacaktır.
Cevap #4
İşleri netleştirmek için, iki gerçeği bilmeniz gerekiyor:
- instanceof operatörü, bir constructor'ın prototype özelliğinin bir nesnenin prototype zincirinde herhangi bir yerde görünüp görünmediğini test eder. Çoğu durumda bu, nesnenin bu constructor veya onun bir alt sınıfı kullanılarak oluşturulduğu anlamına gelir. Ancak prototype,
Object.setPrototypeOf()yöntemi (ECMAScript 2015) veya__proto__özelliği ile (eski tarayıcılar, kullanımı önerilmez) açıkça ayarlanabilir. Bununla birlikte, bir nesnenin prototype'ını değiştirmek performans sorunları nedeniyle önerilmez.
Dolayısıyla instanceof yalnızca nesnelere uygulanabilir. Çoğu durumda dizeleri veya sayıları oluşturmak için yapıcıları kullanmıyorsunuz. Kullanabilirsiniz. Ama neredeyse hiç kullanmazsınız.
Ayrıca instanceof, nesnenin oluşturulmasında tam olarak hangi yapıcının kullanıldığını kontrol edemez, ancak nesne kontrol edilen sınıftan türetilmiş olsa bile true döndürecektir. Çoğu durumda bu istenen davranıştır, ancak bazen değildir. Bu yüzden bunu akılda tutmanız gerekir.
Diğer bir sorun, farklı kapsamların farklı yürütme ortamlarına sahip olmasıdır. Bu, farklı gömülü öğelere sahip oldukları anlamına gelir (farklı global nesne, farklı yapıcılar, vb.). Bu, beklenmeyen sonuçlara yol açabilir.
Örneğin, [] instanceof window.frames[0].Array false döndürecektir, çünkü Array.prototype !== window.frames[0].Array ve diziler birincisinden türetilir.
Ayrıca, tanımsız (undefined) değer üzerinde kullanılamaz, çünkü onun bir prototipi yoktur.
- typeof operatörü, bir değerin altı temel tipten birine ait olup olmadığını test eder: "number", "string", "boolean", "object", "function" veya "undefined". "object" değeri, tüm nesnelere (fonksiyonlar hariç, fonksiyonlar nesnedir ama typeof operatöründe kendi değerleri vardır) ait olur ve ayrıca "null" değeri ve dizilere de (`arrays`) aittir (null için bu bir hatadır, ancak bu hata çok eskidir, bu yüzden standart haline gelmiştir). Bu operatör, yapıcılara bağlı değildir ve değer tanımsız olsa bile kullanılabilir. Ancak nesneler hakkında herhangi bir detay vermez. Bu nedenle eğer detaylı bilgi gerekirse, instanceof kullanılmalıdır.
Şimdi bir zor konudan bahsedelim. Peki ya bir ilkel tipi oluşturmak için constructor kullanırsanız?
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
Sihir gibi görünüyor. Ama öyle değil. Bu, sözde boxing (ilkel değerin nesne ile sarılması) ve unboxing (nesneden sarılmış ilkel değerin çıkarılması) işlemidir. Bu tür bir kod "biraz" kırılgan görünebilir. Tabii ki, yalnızca konstrüktörlerle ilkel tür oluşturmaktan kaçınabilirsiniz. Ama boxing'in sizi vurabileceği başka bir olası durum daha var. Bir ilkel tür üzerinde Function.call() veya Function.apply() kullandığınızda.
function test(){
console.log(typeof this);
}
test.apply(5);
Bundan kaçınmak için katı modu kullanabilirsiniz:
function test(){
'use strict';
console.log(typeof this);
}
test.apply(5);
güncelleme: ECMAScript 2015'ten itibaren, kendi typeof == "symbol" olan bir tür daha vardır: Symbol.
console.log(typeof Symbol());
// expected output: "symbol"
Bunu MDN'de okuyabilirsiniz: (Sembol, typeof).
Cevap #5
Safari 5 ve Internet Explorer 9'da gerçekten ilginç (yani 'korkunç') davranışlar keşfettim. Bunu Chrome ve Firefox'ta büyük bir başarıyla kullanıyordum.
if (typeof this === 'string') {
doStuffWith(this);
}
Sonra IE9'da test ediyorum ve hiç çalışmıyor. Büyük sürpriz. Ama Safari'de aralıklı olarak çalışıyor! O yüzden hata ayıklamaya başlıyorum ve Internet Explorer'ın her zaman false döndürdüğünü görüyorum. Ama en garip olan şey, Safari'nin JavaScript VM'sinde bir tür optimizasyon yapıyor gibi görünmesi; ilk seferde true, ama her yenilediğinizde! false
Beynimin neredeyse patladığını hissettim.
Şimdi buna karar verdim:
if (this instanceof String || typeof this === 'string')
doStuffWith(this.toString());
}
Ve şimdi her şey harika çalışıyor. "a string".toString() çağırabileceğinizi ve bunun sadece stringin bir kopyasını döndürdüğünü unutmayın, yani
"a string".toString() === new String("a string").toString(); // true
O zaman artık ikisini birden kullanacağım.
