อะไรคือความแตกต่างระหว่าง typeof และ instanceof และควรใช้กับอันอื่นเมื่อใด?


394

ในกรณีของฉันโดยเฉพาะ:

callback instanceof Function

หรือ

typeof callback == "function"

มันแตกต่างกันอย่างไรความแตกต่างคืออะไร?

ทรัพยากรเพิ่มเติม:

JavaScript สวนtypeof VS instanceof


2
ฉันพบคำตอบที่นี่เป็นวิธีแก้ปัญหาที่ใช้งานง่าย
CrandellWS

1
มีวิธีตรวจสอบประเภทอื่นโดยใช้Object.prototype.toString ecma-international.org/ecma-262/6.0/…
rab

1
เพียงใช้.constructorคุณสมบัติแทน
มูฮัมหมัดอูเมอร์

หากคุณสงสัยเกี่ยวกับประสิทธิภาพการทำงานให้ดูของฉันคำตอบด้านล่าง typeofเร็วขึ้นเมื่อสามารถใช้งานได้ทั้งสองอย่าง (คือวัตถุ)
Martin Peter

คำตอบ:


540

ใช้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

11
คำตอบนี้ทำให้ชัดเจนว่าทำไมไม่ควรใช้instaceof สำหรับประเภทดั้งเดิม เห็นได้ชัดว่าคุณไม่มีตัวเลือกเมื่อพูดถึงประเภทที่กำหนดเองรวมถึงประโยชน์สำหรับประเภท 'วัตถุ' แต่อะไรที่ทำให้ฟังก์ชั่นมีก้อนออกมาด้วย "Simple built-in types"? ฉันคิดว่ามันแปลก ๆ ว่าฟังก์ชั่นทำงานอย่างไรเหมือนวัตถุ แต่มันเป็นฟังก์ชั่นแบบ 'ฟังก์ชั่น' โดยใช้ 'typeof' ที่เป็นไปได้ ทำไมคุณถึงไม่สนับสนุนอินสแตนซ์ของมัน
Assimilater

4
@Assimilater คุณสามารถใช้ instanceof กับการทำงานได้เป็นอย่างดี แต่ผมคิดว่าทั้ง 3 กฎเป็นเรื่องง่ายมากที่จะจำและใช่ฟังก์ชั่นเป็นข้อยกเว้น :)
Szymon Wygnański

2
อีกส่วนที่ยุ่งยาก -> 'สตริงตัวอย่าง' instanceof String; // false แต่ String ใหม่ ('สตริงตัวอย่าง') instanceof String; // จริง
ลุค

2
@Luke โดยทั่วไปแล้วเป็นความคิดที่ดีที่จะใช้ "new String" เช่นนี้ ที่สร้าง "วัตถุสตริง" มากกว่าสตริงดั้งเดิม ดูส่วนที่นี่developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ …
Colin D

4
Use instanceof for complex built in types- สิ่งนี้ยังมีแนวโน้มที่จะเกิดข้อผิดพลาด ดีกว่าที่จะใช้ ES5 Array.isArray()และคณะ หรือคำแนะนำที่แนะนำ
OrangeDog

122

ทั้งสองอย่างมีความคล้ายคลึงกันในการใช้งานเพราะพวกเขาทั้งคู่ส่งคืนข้อมูลประเภทอย่างไรก็ตามฉันชอบเป็นการส่วนตัวinstanceofเพราะเป็นการเปรียบเทียบประเภทจริงมากกว่าสตริง การเปรียบเทียบประเภทมีแนวโน้มที่จะเกิดข้อผิดพลาดน้อยกว่ามนุษย์และเร็วกว่าในทางเทคนิคเนื่องจากการเปรียบเทียบตัวชี้ในหน่วยความจำแทนที่จะทำการเปรียบเทียบสตริงทั้งหมด


8
มีบางสถานการณ์ที่ instanceof จะใช้งานไม่ได้ตามที่คาดไว้และ typeof ทำงานได้ดี ... developer.mozilla.org/En/Core_JavaScript_1.5_Reference/…
Farinspace

55
instanceof ทำงานร่วมกับวัตถุในหน้าต่างเดียวกัน หากคุณใช้ iframe / frame หรือ popup-windows แต่ละ (i) frame / window มี "function" วัตถุของตัวเองและ instanceof จะล้มเหลวหากคุณพยายามเปรียบเทียบวัตถุจากหน้าต่าง / เฟรมอื่น (i) typeof จะทำงานในทุกกรณีเพราะมันจะส่งกลับสตริง "ฟังก์ชั่น"
บาง

14
jsperf.com/typeof-function-vs-instanceof/3 ฉันลองใช้ Chrome และ FF3.X วิธี "typeof" นั้นเร็วขึ้น
Morgan Cheng

10
นี่เป็นเพียงความเท็จ พวกเขาไม่เหมือนกัน พวกเขาไม่ทำงานทั้งในสถานการณ์เดียวกันโดยเฉพาะอย่างยิ่งใน VM VM และเบราว์เซอร์ที่แตกต่างกัน
Justin Force

8
คำตอบของคุณบอกว่า "ทั้งคู่เหมือนกันในแง่ของการใช้งาน" ด้วยความเคารพนี่เป็นความเท็จอย่างยิ่ง ตามที่อธิบายและอธิบายไว้ในคำตอบของฉันตัวเลือกไม่ทำงานในทุกสถานการณ์โดยเฉพาะในเบราว์เซอร์ วิธีที่ดีกว่าคือการใช้ทั้งกับ || ผู้ประกอบการ
Justin Force

103

เหตุผลที่ดีในการใช้ 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"

ดังนั้นในความคิดของฉันมันขึ้นอยู่กับประเภทของข้อมูลที่เป็นไปได้ที่คุณกำลังตรวจสอบ


11
+1 ยังทราบว่าinstanceofไม่สามารถเปรียบเทียบกับประเภทดั้งเดิมและสามารถพิมพ์ได้
Tino

3
ใน Chrome 29.0.1541.0 dev undefined instanceof Objectจะส่งคืนค่าเท็จและจะไม่เกิดข้อยกเว้น ฉันไม่รู้ว่าการเปลี่ยนแปลงนั้นจะเกิดinstanceofขึ้นเมื่อเร็ว ๆ นี้ แต่มันน่าดึงดูดยิ่งขึ้น
Cypress Frankenfeld

7
undefined instanceof Objectไม่ส่งข้อยกเว้นเนื่องจากundefinedมีการกำหนดเอ๊ะ ค่าคงที่มีอยู่ในเนมสเปซ เมื่อไม่มีตัวแปร (เนื่องจากมีการพิมพ์ผิดเช่น), instanceof จะส่งข้อยกเว้น การใช้ typeof กับตัวแปรที่ไม่มีอยู่จะทำให้ 'ไม่ได้กำหนด' ในทางกลับกัน
cleong

31

ในการทำให้สิ่งต่าง ๆ ชัดเจนคุณจำเป็นต้องรู้ข้อเท็จจริงสองประการ:

  1. ตัวดำเนินการอินสแตนซ์ของการทดสอบว่าคุณสมบัติต้นแบบของตัวสร้างปรากฏที่ใดก็ได้ในห่วงโซ่ต้นแบบของวัตถุ ในกรณีส่วนใหญ่นี่หมายความว่าวัตถุถูกสร้างขึ้นโดยใช้ตัวสร้างนี้หรือบนของลูกหลานของมัน แต่ต้นแบบอาจถูกกำหนดอย่างชัดเจนโดยObject.setPrototypeOf()วิธีการ (ECMAScript 2015) หรือโดย__proto__คุณสมบัติ (เบราว์เซอร์เก่าเลิกใช้แล้ว) ไม่แนะนำให้เปลี่ยนต้นแบบของวัตถุเนื่องจากปัญหาประสิทธิภาพการทำงาน

ดังนั้น instanceof สามารถใช้ได้กับวัตถุเท่านั้น ในกรณีส่วนใหญ่คุณไม่ได้ใช้ตัวสร้างเพื่อสร้างสตริงหรือตัวเลข คุณสามารถ. แต่คุณแทบไม่เคยทำ

อินสแตนซ์ของไม่สามารถตรวจสอบได้ว่าคอนสตรัคเตอร์ใดที่ใช้สร้างวัตถุ แต่จะส่งคืนจริงแม้ว่าวัตถุนั้นจะได้รับมาจากคลาสที่ถูกตรวจสอบ ในกรณีส่วนใหญ่นี่เป็นพฤติกรรมที่ต้องการ แต่บางครั้งก็ไม่เป็นเช่นนั้น ดังนั้นคุณต้องจำไว้

ปัญหาอื่นคือขอบเขตที่แตกต่างกันมีสภาพแวดล้อมการดำเนินการที่แตกต่างกัน ซึ่งหมายความว่าพวกเขามีบิวด์อินที่แตกต่างกัน (วัตถุทั่วโลกที่แตกต่างกันคอนสตรัคเตอร์ที่แตกต่าง ฯลฯ ซึ่งอาจส่งผลให้เกิดผลลัพธ์ที่ไม่คาดคิด

ตัวอย่างเช่น[] instanceof window.frames[0].ArrayจะกลับมาfalseเพราะArray.prototype !== window.frames[0].Arrayและอาร์เรย์สืบทอดมาจากอดีต
นอกจากนี้มันไม่สามารถใช้กับค่าที่ไม่ได้กำหนดได้เนื่องจากมันไม่มีต้นแบบ

  1. ตัวดำเนินการtypeofทดสอบว่าค่าเป็นหนึ่งในหกประเภทพื้นฐานหรือไม่ : " number ", " string ", " boolean ", " object ", " function " หรือ " undefined " ที่สตริง "วัตถุ" เป็นวัตถุทั้งหมด (ยกเว้นฟังก์ชั่นซึ่งเป็นวัตถุ แต่มีค่าของตัวเองในผู้ประกอบการ typeof) และยังมี "null" ค่าและอาร์เรย์ (สำหรับ "null" มันเป็นข้อผิดพลาด แต่ข้อผิดพลาดนี้เก่า ดังนั้นมันจึงกลายเป็นมาตรฐาน) มันไม่ได้ขึ้นอยู่กับการก่อสร้างและสามารถใช้งานได้แม้ว่าค่าจะไม่ได้กำหนด แต่มันไม่ได้ให้รายละเอียดใด ๆ เกี่ยวกับวัตถุ ดังนั้นหากคุณต้องการมันไปที่อินสแตนซ์ของ

ทีนี้เรามาพูดถึงสิ่งหนึ่งที่ยุ่งยาก ถ้าคุณใช้ Constructor เพื่อสร้างประเภทดั้งเดิม

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

ดูเหมือนว่าเวทมนตร์ แต่มันไม่ใช่ มันเรียกว่าการชกมวย (ห่อค่าดั้งเดิมโดยวัตถุ) และ unboxing (แยกค่าดั้งเดิมห่อจากวัตถุ) โค้ดประเภทนี้ดูเหมือนจะ "เปราะบาง" แน่นอนคุณสามารถหลีกเลี่ยงการสร้างประเภทดั้งเดิมกับตัวสร้าง แต่มีอีกสถานการณ์ที่เป็นไปได้เมื่อมวยอาจตีคุณ เมื่อคุณใช้ 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 มีประเภทอีกหนึ่งที่เรียกว่าสัญลักษณ์ซึ่งมี typeof ของตัวเอง == "สัญลักษณ์"

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

คุณสามารถอ่านเกี่ยวกับ MDN: ( Symbol , typeof )


2
if an object is created by a given constructor สิ่งนี้ไม่ถูกต้อง o instanceof Cจะคืนค่าจริงถ้า o สืบทอดจาก C.prototype คุณได้พูดถึงบางสิ่งเกี่ยวกับเรื่องนี้ในภายหลังในคำตอบของคุณ แต่มันไม่ชัดเจน
oyenamit

1
ไม่ถูกต้อง ... จากหนังสือ: " github.com/getify/You-Dont-Know-JS " a instanceof Foo; // true ตัวดำเนินการ instanceof รับวัตถุธรรมดาเป็นตัวถูกดำเนินการทางซ้ายและฟังก์ชันเป็นตัวถูกดำเนินการทางขวา คำถามของคำตอบคือ: ในห่วงโซ่ [[Prototype]] ทั้งหมดของวัตถุที่ชี้โดย Foo.prototype จะปรากฏขึ้นโดยพลการหรือไม่?
Deen John

1
ฉันแก้ไขคำตอบเพื่อให้ถูกต้องมากขึ้น ขอบคุณสำหรับความคิดเห็นของคุณ
Vladimir Liubimov

นอกจากนี้ยังได้เพิ่มคำอธิบายของปัญหาการชกมวย / การบอกเลิกไม่ได้เพิ่ม
Vladimir Liubimov

15

ฉันค้นพบพฤติกรรมที่น่าสนใจ (อ่านว่า "น่ากลัว") ใน Safari 5 และ Internet Explorer 9 ฉันใช้สิ่งนี้กับความสำเร็จที่ยิ่งใหญ่ใน Chrome และ Firefox

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

จากนั้นฉันทดสอบใน IE9 และมันไม่ทำงานเลย แปลกใจใหญ่ แต่ใน Safari มันไม่ต่อเนื่อง! ดังนั้นผมจึงเริ่มต้นการแก้จุดบกพร่องและฉันพบว่า Internet Explorer ถูกเสมอfalseกลับมา แต่สิ่งที่แปลกประหลาดคือ Safari ดูเหมือนว่าจะทำชนิดของการเพิ่มประสิทธิภาพใน VM JavaScript ของบางอย่างที่มันเป็นแรกเวลา แต่ทุกครั้งที่คุณกดโหลด!truefalse

สมองของฉันเกือบจะระเบิด

ดังนั้นตอนนี้ฉันได้ตัดสินในเรื่องนี้:

if (this instanceof String || typeof this === 'string')
    doStuffWith(this.toString());
}

และตอนนี้ทุกอย่างใช้งานได้ดี โปรดทราบว่าคุณสามารถโทร"a string".toString()และมันก็แค่ส่งคืนสำเนาของสตริงเช่น

"a string".toString() === new String("a string").toString(); // true

ดังนั้นฉันจะใช้ทั้งสองต่อจากนี้ไป


8

ความแตกต่างในทางปฏิบัติที่สำคัญอื่น ๆ :

// 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

instanceofใน Javascript อาจเป็นขุย - ฉันเชื่อว่าเฟรมเวิร์กสำคัญพยายามหลีกเลี่ยงการใช้งาน หน้าต่างที่แตกต่างเป็นหนึ่งในวิธีที่มันสามารถทำลาย - ฉันเชื่อว่าลำดับชั้นของคลาสสามารถสร้างความสับสนได้เช่นกัน

มีวิธีที่ดีกว่าสำหรับการทดสอบว่าวัตถุนั้นเป็นชนิดในตัวหรือไม่ (ซึ่งโดยปกติจะเป็นสิ่งที่คุณต้องการ) สร้างฟังก์ชั่นยูทิลิตี้และใช้พวกเขา:

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

และอื่น ๆ


2
ในกรณีที่คุณไม่ทราบ: พิมพ์ไม่จำเป็นต้องใช้วงเล็บเพราะมันเป็นคำหลักและไม่ใช่ฟังก์ชั่น และ IMHO คุณควรใช้ === แทนที่จะ ==
บาง

5
@some คุณมีความถูกต้องเกี่ยวกับ typeof แต่ในกรณีนี้ไม่จำเป็นต้อง === มันเป็นสิ่งจำเป็นเฉพาะเมื่อค่าที่ถูกเปรียบเทียบอาจเท่ากันโดยไม่ต้องมีชนิดเดียวกัน ที่นี่มันไม่สามารถ
Nicole

@ บางชนิดไม่เคยส่งคืนสิ่งที่นอกเหนือจากสตริงหรือไม่
Kenneth J

ดังนั้น isArray จะผิดสำหรับการพูดวัตถุสแต็กที่มีวิธีการผลักดันและคุณลักษณะความยาวเป็นตัวเลข ภายใต้สถานการณ์ใด (อินสแตนซ์ของอาเรย์) จะผิด?
Chris Noe

@ChrisNoe ปัญหาเกิดขึ้นกับวัตถุที่แชร์ระหว่างหลายเฟรม: groups.google.com/forum/#!msg/comp.lang.javascript/XTWYCOwC96I/…

3

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)

3

callback.isFunction()ฉันจะแนะนำให้ใช้ของต้นแบบ

พวกเขาหาข้อแตกต่างและคุณสามารถไว้ใจได้

ฉันเดาว่าเฟรมเวิร์ก JS อื่นมีสิ่งต่าง ๆ เช่นกัน

instanceOfฉันเชื่อว่าจะไม่ทำงานในฟังก์ชั่นที่กำหนดไว้ในหน้าต่างอื่น window.Functionฟังก์ชั่นของพวกเขาแตกต่างจากของคุณ


3

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เพื่อตรวจสอบฟังก์ชั่น


ฉันสามารถยืนยันว่ามันเป็นtypeofสิ่งที่ผิด - fเป็นทั้งหมดต่อไปนี้: Object(วัตถุ) และFunction(ฟังก์ชั่น) ยกเว้นสำหรับฉันมันสมเหตุสมผลมากกว่าที่จะใช้instanceofเพราะรู้ว่ามันเป็นฟังก์ชั่นฉันรู้ว่ามันเป็นวัตถุเช่นกันเนื่องจากฟังก์ชั่นทั้งหมดเป็นวัตถุใน ECMAScript การสนทนาไม่เป็นความจริง - การรู้จากtypeofสิ่งนั้นfเป็นสิ่งที่objectฉันไม่รู้ว่ามันเป็นฟังก์ชั่น
พฤศจิกายน

@amn สำหรับผมมันเป็นเสียตัวอย่างของฟังก์ชั่น จะได้รับคุณลักษณะเช่นlength, nameและcallจากฟังก์ชั่น แต่ทั้งหมดของพวกเขาตาย มีอะไรเลวก็ไม่สามารถเรียกและกล่าวว่า:TypeError f is not a function
maaartinus

2

ความแตกต่างในทางปฏิบัติที่สำคัญ:

var str = 'hello word';

str instanceof String   // false

typeof str === 'string' // true

อย่าถามฉันทำไม


11
เพราะนี่strคือสายอักขระดั้งเดิมไม่ใช่วัตถุสตริง เช่นเดียวกับ primitives จำนวนและดั้งเดิมของบูลีนพวกมันไม่ใช่อินสแตนซ์ของคู่หู "ที่สร้าง", วัตถุ String, Number และ Boolean จาวาสคริปต์จะแปลงดั้งเดิมทั้งสามนี้เป็นวัตถุเมื่อจำเป็น (เช่นการใช้วิธีการบนโซ่ต้นแบบของวัตถุ) เมื่อพลิกด้านของความแตกต่างในทางปฏิบัติของคุณinstanceoftypeof [] == "object" // trueจะดีกว่าสำหรับการตรวจสอบตั้งแต่อาร์เรย์
Andy E

2

ประสิทธิภาพ

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

1
typeof subject == "array" ควรคืนค่าเท็จ หัวเรื่องของ typeof คือ "object"
Shardul

ทำไมการพิมพ์จึงเร็วขึ้น? Javascript กำลังจัดการกับสตริงตัวอักษร?
Gregory Magarshak

เหตุผลคือตามห่วงโซ่ต้นแบบของวัตถุinstanceof เสมอดังนั้นการปรับประสิทธิภาพจะขึ้นอยู่กับว่าโซ่ต้นแบบนั้นinstanceofถูกทดสอบไปไกลแค่ไหน ดังนั้นสำหรับลูกโซ่การสืบทอดแบบสั้นการลงโทษจะลดลง (เช่น[] instanceof Array, {} instanceof Object) และนานกว่านั้นใหญ่กว่า ดังนั้นถ้าทั้งคู่obj instanceof SomeClassและมีความtypeof obj !== 'string'หมายเหมือนกันจากมุมมองของรหัสสมมุติของคุณ (fe ถ้าคุณเพิ่งทำแบบทดสอบifและไม่switchผ่านหลายชั้นเรียน ฯลฯ ) คุณควรเลือกที่สองที่มีประสิทธิภาพดีกว่า
ankhzet

2

นี่เป็นเพียงความรู้เสริมสำหรับคำอธิบายอื่น ๆ ทั้งหมดที่นี่ - ฉันไม่แนะนำให้ใช้.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)

อินสแตนซ์ Array ที่พิมพ์ออกมาเทียบกับตัวสร้าง - เร็วขึ้น 1.5 เท่าใน Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64- บิต, Windows)

อินสแตนซ์ Array ที่พิมพ์ออกมาเทียบกับตัวสร้าง - เร็วขึ้น 30x ใน Firefox 59.0b10 (64- บิต, Windows)

ออกจาก curiousity ฉันไม่เป็นมาตรฐานของเล่นอย่างรวดเร็วกับ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)

สตริง / หมายเลข typeof กับตัวสร้าง - เร็วขึ้น 1.26x ใน Chrome 64.0.3282.167 (64-bit, Windows)

Firefox 59.0b10 (64- บิต, Windows)

หมายเหตุ: ลำดับการทำงานของฟังก์ชั่นที่ปรากฏในรายการระหว่างภาพ!

String / Number typeof vs constructor - 0.78x ช้าลงใน Firefox 59.0b10 (64- บิต, Windows)



1

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"


ฉันควรทำอย่างไรฉันจะได้รับ UA (navigator.userAgent)?
xgqfrms

0

มาจากการศึกษาที่เข้มงวดของ OO ฉันจะไปหา

callback instanceof Function

เงื่อนไขมีแนวโน้มที่จะสะกดผิดหรือผิดประเภทอื่น ๆ ของฉัน บวกฉันรู้สึกว่าอ่านดีขึ้น


0

แม้จะมี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

0

อีกกรณีหนึ่งคือคุณสามารถเปรียบเทียบได้instanceof- มันจะคืนค่าจริงหรือเท็จ ด้วยtypeofคุณจะได้รับประเภทของสิ่งที่ให้


0

ด้วยประสิทธิภาพในใจคุณควรใช้ typeof กับฮาร์ดแวร์ทั่วไปถ้าคุณสร้างสคริปต์ด้วยการวนซ้ำ 10 ล้านคำสั่ง: typeof str == 'string' จะใช้เวลา 9ms ในขณะที่ 'string' instanceof String จะใช้เวลา 19 มิลลิวินาที


0

แน่นอนว่ามันสำคัญ ........ !

ลองทำอย่างนี้กับตัวอย่างในตัวอย่างของเราเราจะประกาศฟังก์ชันในสองวิธีที่ต่างกัน

เราจะใช้ทั้งสองfunction declarationและ สร้างฟังก์ชั่น เราจะเห็นวิธีtypeofและinstanceofพฤติกรรมในสถานการณ์ที่แตกต่างกันสองสถานการณ์

สร้างฟังก์ชั่นโดยใช้การประกาศฟังก์ชั่น:

function MyFunc(){  }

typeof Myfunc == 'function' // true

MyFunc instanceof Function // false

คำอธิบายที่เป็นไปได้สำหรับผลที่แตกต่างกันดังกล่าวเป็นอย่างที่เราทำคำประกาศฟังก์ชั่นtypeofสามารถเข้าใจว่ามันเป็น function.Because typeofการตรวจสอบหรือไม่ว่าการแสดงออกที่ typeof คือการดำเนินการเกี่ยวกับในกรณีของเราดำเนินการวิธีการโทรหรือไม่ ถ้ามันใช้วิธีมันเป็นฟังก์ชั่นอื่น ๆ ไม่ได้สำหรับการชี้แจงการตรวจสอบข้อมูลจำเพาะ ecmascript สำหรับประเภทของMyFunc Call

สร้างฟังก์ชั่นโดยใช้ตัวสร้างฟังก์ชั่น:

var MyFunc2 = new Function('a','b','return a+b') // A function constructor is used 

typeof MyFunc2 == 'function' // true

MyFunc2 instanceof Function // true

นี่typeofอ้างว่าMyFunc2เป็นฟังก์ชั่นเช่นเดียวกับinstanceofoperator.We รู้อยู่แล้วว่าtypeofการตรวจสอบถ้าMyFunc2นำมาใช้Callวิธีการหรือ not.As MyFunc2เป็นฟังก์ชั่นและใช้callวิธีการที่เป็นวิธีที่typeofจะรู้ว่ามันเป็น function.On มืออื่น ๆ ที่เราใช้function constructorในการสร้างMyFunc2มัน จะกลายเป็นตัวอย่างของFunction constructor.That เป็นเหตุผลที่ยังมีมติให้instanceoftrue

ปลอดภัยกว่าการใช้อะไร

เราจะเห็นได้ในทั้งสองกรณีผู้ประกอบการที่ประสบความสำเร็จสามารถถูกกล่าวหาว่าเราจะจัดการกับฟังก์ชั่นที่นี่จะปลอดภัยกว่าtypeof จะล้มเหลวในกรณีของเพราะไม่ได้เป็นตัวอย่างของinstanceofinstanceoffunction declarationfunction declarationsFunction constructor

ปฏิบัติที่ดีที่สุด :

ตามที่Gary Raffertyแนะนำวิธีที่ดีที่สุดควรใช้ทั้ง typeof และ instanceof ร่วมกัน

  function isFunction(functionItem) {

        return typeof(functionItem) == 'function' || functionItem instanceof Function;

  }

  isFunction(MyFunc) // invoke it by passing our test function as parameter

การวิจารณ์เชิงสร้างสรรค์ใด ๆ เกี่ยวกับคำตอบนี้จะได้รับการชื่นชม
AL-zami

0

เพื่อให้เป็นอินสแตนซ์ที่แม่นยำมาก ควรใช้ในกรณีที่ค่าถูกสร้างผ่านตัวสร้าง

var d = new String("abc")

ขณะtypeofเพื่อตรวจสอบค่าที่สร้างขึ้นโดยได้รับมอบหมายสำหรับเช่น

var d = "abc"

0

ไม่จำเป็นต้องเอาชนะด้วยตัวอย่างข้างต้นมากมายเพียงจำมุมมองสองประการ:

  1. typeof var;เป็นโอเปอเรเตอร์ unary จะส่งคืนชนิดดั้งเดิมหรือชนิดรูทของ var เพื่อที่จะกลับมาชนิดดั้งเดิม ( string, number, bigint, boolean, undefinedและsymbol) หรือobjectประเภท

  2. ในกรณีที่วัตถุระดับสูงเช่นวัตถุในตัว (String, Number, Boolean, Array .. ) หรือวัตถุที่ซับซ้อนหรือกำหนดเองทั้งหมดของพวกเขาเป็นobjectประเภทราก แต่ประเภทฐานสร้างประเภทอินสแตนซ์ที่พวกเขาจะแตกต่างกัน (เช่นชั้น OOP แนวคิดเกี่ยวกับการสืบทอด) ที่นี่a instanceof A- ตัวดำเนินการไบนารี - จะช่วยคุณได้มันจะผ่านห่วงโซ่ต้นแบบเพื่อตรวจสอบว่าตัวสร้างของตัวถูกดำเนินการด้านขวา (A) ปรากฏขึ้นหรือไม่

ดังนั้นเมื่อใดก็ตามที่คุณต้องการตรวจสอบ "ประเภทราก" หรือทำงานกับตัวแปรดั้งเดิม - ใช้ "typeof" มิฉะนั้นใช้ "instanceof"

nullเป็นกรณีพิเศษซึ่งดูเหมือนว่าจะเป็นแบบดั้งเดิม แต่แท้จริงแล้วเป็นกรณีพิเศษสำหรับวัตถุ ใช้a === nullเพื่อตรวจสอบค่าว่างแทน

ในทางกลับกันfunctionก็เป็นกรณีพิเศษซึ่งเป็นวัตถุในตัว แต่typeofกลับfunction

อย่างที่คุณเห็นinstanceofต้องผ่านโซ่ต้นแบบในขณะเดียวกันtypeofเพียงตรวจสอบชนิดของรูทหนึ่งครั้งดังนั้นจึงง่ายที่จะเข้าใจว่าทำไมจึงtypeofเร็วกว่าinstanceof


0

ตามเอกสารของ MDN เกี่ยวกับ typeofวัตถุที่สร้างอินสแตนซ์ด้วยคำสำคัญ "ใหม่" นั้นเป็นประเภท 'object':

typeof 'bla' === 'string';

// The following are confusing, dangerous, and wasteful. Avoid them.
typeof new Boolean(true) === 'object'; 
typeof new Number(1) === 'object'; 
typeof new String('abc') === 'object';

ในขณะที่เอกสารเกี่ยวกับอินสแตนซ์ของจุดที่:

const objectString = new String('String created with constructor');
objectString instanceOf String; // returns true
objectString instanceOf Object; // returns true

instanceofดังนั้นหากใครต้องการที่จะตรวจสอบเช่นว่าสิ่งที่เป็นสตริงไม่ว่ามันถูกสร้างขึ้นวิธีที่ปลอดภัยที่สุดที่จะใช้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.