ทำไมอินสแตนซ์ของคืนเท็จสำหรับตัวอักษรบางตัว?


284
"foo" instanceof String //=> false
"foo" instanceof Object //=> false
true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false

// the tests against Object really don't make sense

ตัวอักษร Array และ Object literals ตรงกัน ...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

ทำไมไม่ทั้งหมด หรือทำไมพวกเขาไม่ได้ทั้งหมดไม่ ?
แล้วพวกมันคือตัวอย่างของอะไร?

มันเหมือนกันใน FF3, IE7, Opera และ Chrome อย่างน้อยมันก็สอดคล้องกัน


พลาดไม่กี่

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

คำตอบ:


424

Primitives เป็นประเภทที่แตกต่างจากวัตถุที่สร้างขึ้นจากภายใน Javascript จากMozilla API เอกสาร :

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)

ฉันไม่สามารถหาวิธีสร้างประเภทดั้งเดิมด้วยรหัสบางทีมันเป็นไปไม่ได้ นี่อาจจะเป็นเหตุผลที่คนใช้แทนtypeof "foo" === "string"instanceof

วิธีง่าย ๆ ในการจดจำสิ่งต่าง ๆ เช่นนี้กำลังถามตัวเองว่า "ฉันสงสัยว่าอะไรจะมีเหตุผลและเรียนรู้ได้ง่าย"? ไม่ว่าคำตอบนั้นคืออะไร Javascript ก็ทำอย่างอื่น


5
ทุกวันด้วยเหตุผลใหม่ที่จะเกลียด JavaScript เป็นวันที่ดี ฉันรู้ว่ามันค้างชำระนาน แต่ฉันขอขอบคุณสำหรับโพสต์นี้
toniedzwiedz

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

14
FYI คุณสามารถสร้างคำพื้นฐานได้โดยไม่มีไวยากรณ์ตามตัวอักษร (new String()).valueOf();
สถานะสีเทากำลังจะมาถึง

11
โปรดทราบว่าtypeof foo === 'string'ไม่เพียงพอ: ดูคำตอบของ axkibe
ไบรอัน Larsen

1
นอกจากนี้typeof new String('')ผลตอบแทน"object"
transang

105

ฉันใช้:

function isString(s) {
    return typeof(s) === 'string' || s instanceof String;
}

เพราะในสตริง JavaScript สามารถเป็นตัวอักษรหรือวัตถุ


28
ฉันพบบางสิ่งที่สั้น btw function isString(s) { return s.constructor === String; }ใช้งานได้กับตัวอักษรและวัตถุสตริง (อย่างน้อยใน V8)
axkibe

7
ต้องรัก JavaScript
Derek 朕會功夫

2
ฉันใช้ jQuery.type (s) === 'string' ( api.jquery.com/jquery.type ), jQuery.isArray (), jQuery.isFunction (), jQuery.isNumeric () เมื่อเป็นไปได้
Ivan Samygin

1
@axkibe ขณะที่คุณกำลังที่ถูกต้องก็ไม่ได้เกือบเป็น performanttypeofเป็น
Qix - MONICA ถูกยกเลิกเมื่อ

คุณสามารถใช้ typeof "?" == String.name.toLowerCase () [แต่ทำไม [] อินสแตนซ์ของ Array?]
QuentinUK

62

ใน JavaScript ทุกอย่างเป็นวัตถุ (หรืออย่างน้อยอาจได้รับการปฏิบัติเหมือนเป็นวัตถุ) ยกเว้นprimitives (booleans, null, ตัวเลข, สตริงและค่าundefined(และสัญลักษณ์ใน ES6)):

console.log(typeof true);           // boolean
console.log(typeof 0);              // number
console.log(typeof "");             // string
console.log(typeof undefined);      // undefined
console.log(typeof null);           // object
console.log(typeof []);             // object
console.log(typeof {});             // object
console.log(typeof function () {}); // function

ในขณะที่คุณสามารถดูวัตถุอาร์เรย์และค่าnullเป็นวัตถุที่พิจารณาทั้งหมด ( nullเป็นการอ้างอิงถึงวัตถุที่ไม่มีอยู่) ฟังก์ชั่นจะแตกต่างเพราะพวกเขาเป็นวัตถุชนิดcallableพิเศษ อย่างไรก็ตามพวกเขายังคงเป็นวัตถุ

บนมืออื่น ๆ ตัวอักษรtrue, 0, ""และundefinedไม่ได้เป็นวัตถุ เป็นค่าดั้งเดิมใน JavaScript อย่างไรก็ตาม booleans ตัวเลขและสตริงยังมีการก่อสร้างBoolean, NumberและStringตามลำดับซึ่งห่อพื้นฐานของตนเพื่อให้การทำงานเพิ่ม:

console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0));     // object
console.log(typeof new String(""));    // object

ที่คุณสามารถดูเมื่อค่าดั้งเดิมถูกห่อภายในBoolean, NumberและStringการก่อสร้างตามลำดับพวกเขากลายเป็นวัตถุ instanceofประกอบการทำงานเฉพาะสำหรับวัตถุ (ซึ่งเป็นเหตุผลที่จะส่งกลับfalseค่าดั้งเดิม):

console.log(true instanceof Boolean);              // false
console.log(0 instanceof Number);                  // false
console.log("" instanceof String);                 // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number);      // true
console.log(new String("") instanceof String);     // true

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

โชคดีที่มีวิธีแก้ไขปัญหานี้อย่างง่าย การใช้งานเริ่มต้นของtoString(เช่นตามที่กำหนดไว้ในObject.prototype.toString) ส่งคืน[[Class]]ทรัพย์สินภายในของทั้งค่าดั้งเดิมและวัตถุ:

function classOf(value) {
    return Object.prototype.toString.call(value);
}

console.log(classOf(true));              // [object Boolean]
console.log(classOf(0));                 // [object Number]
console.log(classOf(""));                // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0)));     // [object Number]
console.log(classOf(new String("")));    // [object String]

[[Class]]คุณสมบัติภายในของค่ามีประโยชน์มากกว่าtypeofค่าดังกล่าว เราสามารถใช้Object.prototype.toStringในการสร้างtypeofผู้ประกอบการเวอร์ชั่น (มีประโยชน์) ของเราเองดังต่อไปนี้:

function typeOf(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
}

console.log(typeOf(true));              // Boolean
console.log(typeOf(0));                 // Number
console.log(typeOf(""));                // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0)));     // Number
console.log(typeOf(new String("")));    // String

หวังว่าบทความนี้จะช่วย หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับความแตกต่างระหว่างวัตถุพื้นฐานและวัตถุที่ห่อหุ้มอ่านโพสต์บล็อกต่อไปนี้: ชีวิตลับของ JavaScript พื้นฐาน


6
+1, altough nullเป็นค่าดั้งเดิมเช่นกัน (มีเพียงtypeofผู้ปฏิบัติงานที่สับสน)
Bergi

33

คุณสามารถใช้คุณสมบัตินวกรรมิก:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true

18
โปรดทราบว่าเมื่อทดสอบตัวแปรเทคนิคนี้อาจล้มเหลวในบางสถานการณ์ มีการอ้างอิงโดยนัยไปยังหน้าต่างปัจจุบันด้านหน้าStringและBooleanในตัวอย่างข้างต้นดังนั้นหากคุณกำลังทดสอบconstructorคุณสมบัติของตัวแปรสตริงที่สร้างขึ้นในหน้าต่างอื่น (เช่นป๊อปอัปหรือเฟรม) มันจะไม่เท่ากับเพียงแค่Stringมันจะ thatOtherWindowsName.Stringเทียม
Michael Mathews

และอินสแตนซ์ของไม่จัดการกับสิ่งนี้และส่งคืนผลลัพธ์บูลีนที่เหมาะสมหรือไม่
Chris Noe

5
สิ่งนี้จะล้มเหลวหากคุณผ่านการสืบทอดของ String
ไบรอัน Larsen

1
@MichaelMathews: วิธีนี้ใช้เพื่อแก้ไข:Object.prototype.toString.call('foo') === '[object String]'
rvighne

@BryanLarsen และ @MichaelMathews มีปัญหาในการใช้งานd.constructor == Stringหรือไม่? เช่นกับผู้ประกอบการที่เท่าเทียมกันหลวม
dotnetCarpenter

7
 typeof(text) === 'string' || text instanceof String; 

คุณสามารถใช้มันได้มันจะใช้ได้ทั้งสองกรณีเป็น

  1. var text="foo"; // typeof จะทำงาน

  2. String text= new String("foo"); // instanceof จะทำงาน



1

ฉันเชื่อว่าฉันคิดวิธีแก้ปัญหาที่ทำงานได้:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false

-1

https://www.npmjs.com/package/typeof

ส่งคืนการแทนค่าสตริงinstanceof(ชื่อตัวสร้าง)

function instanceOf(object) {
  var type = typeof object

  if (type === 'undefined') {
    return 'undefined'
  }

  if (object) {
    type = object.constructor.name
  } else if (type === 'object') {
    type = Object.prototype.toString.call(object).slice(8, -1)
  }

  return type.toLowerCase()
}

instanceOf(false)                  // "boolean"
instanceOf(new Promise(() => {}))  // "promise"
instanceOf(null)                   // "null"
instanceOf(undefined)              // "undefined"
instanceOf(1)                      // "number"
instanceOf(() => {})               // "function"
instanceOf([])                     // "array"

-2

สำหรับฉันความสับสนที่เกิดจาก

"str".__proto__ // #1
=> String

ดังนั้น"str" istanceof Stringควรกลับมาtrueเพราะวิธีการทำงานของ istanceof ดังต่อไปนี้:

"str".__proto__ == String.prototype // #2
=> true

ผลลัพธ์ของนิพจน์# 1และ# 2ขัดแย้งกันดังนั้นควรมีอย่างใดอย่างหนึ่งผิด

# 1 ผิด

ฉันเข้าใจว่ามันเกิดจาก__proto__คุณสมบัติที่ไม่ใช่มาตรฐานดังนั้นให้ใช้มาตรฐาน:Object.getPrototypeOf

Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object

ตอนนี้ไม่มีความสับสนระหว่างการแสดงออก# 2และ# 3


2
# 1 ถูกต้อง แต่มันเกิดจากการเข้าถึงสถานที่ให้บริการซึ่งกล่องมูลค่าดั้งเดิมประเภทของวัตถุนั้นคล้ายกับหรือObject("str").__proto__ Object("str") instanceof String
Jonathan Lonowski

@JonathanLonowski ขอบคุณที่ชี้ให้เห็น ฉันไม่ทราบว่า
mko

-8

หรือคุณสามารถสร้างฟังก์ชั่นของคุณเองเช่น:

function isInstanceOf(obj, clazz){
  return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};

การใช้งาน:

isInstanceOf('','String');
isInstanceOf(new String(), 'String');

สิ่งเหล่านี้ควรกลับมาจริง


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