JavaScript에서 instanceof 연산자는 무엇입니까?


313

instanceof사람들이 JavaScript를 객체 지향 프로그래밍 언어가 아니라고 생각하는 경향이 있기 때문에 JavaScript 의 키워드는 처음 접했을 때 상당히 혼란 스러울 수 있습니다.

  • 무엇입니까?
  • 어떤 문제가 해결됩니까?
  • 적절한시기와시기는?

3
아래 답변은 매우 유용하지만 실제 응용 프로그램에서는 많이 사용하지 않습니다 (적어도 나는 사용하지 않습니다). 문자열을 보유하고 확인하는 object.type 속성을 만듭니다.
Omar Al-Ithawi

4
JS는 "foo" instanceof String=> false, 1 instanceof Number=> false, {} instanceof Object=> false 와 같은 의미가 없습니다 . 뭐라고?!
morbusg

12
@morbusg 귀하의 의견이 잘못되었습니다. 우선 "foo" instanceof String => false하기 때문에, 정확 typeof "foo" == 'string'. new String("foo") instanceof String => true왜냐하면 typeof String == 'function'-함수를 클래스 (클래스 정의)처럼 취급해야합니다. 로 할당하면 변수가 instanceof일부 function(클래스)가됩니다 var v = new AnythingWhatTypeofEqualsFunction(). 동일하게 적용됩니다 1. typeof 1 == 'number'- '수' '기능'아니다 : 다음 - {} instanceof ObjectTRUE노드와 현대적인 브라우저에서
FIDER

1
@fider : 그것은 루비리스트로부터 나온 언어 사양에 대한 논평이었습니다.
morbusg

@ morbusg- ({}) instanceof Object가 반환 true됩니다. 실제로 작성한 코드는 오류가 발생합니다.
DDM

답변:


279

대신에

LHS (Left Hand Side) 피연산자는 클래스의 실제 생성자 인 RHS (Right Hand Side) 피연산자로 테스트되는 실제 객체입니다. 기본 정의는 다음과 같습니다.

Checks the current object and returns true if the object
is of the specified object type.

다음은 좋은 예 이며 Mozilla 개발자 사이트 에서 직접 가져온 예 입니다 .

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

언급 할 가치가있는 것은 instanceof객체가 클래스의 프로토 타입에서 상속되면 true 로 평가됩니다.

var p = new Person("Jon");
p instanceof Person

즉는 p instanceof Person이후 사실 p에서 상속 Person.prototype.

OP의 요청에 따라

샘플 코드와 설명이있는 작은 예제를 추가했습니다.

변수를 선언하면 특정 유형을 지정합니다.

예를 들어 :

int i;
float f;
Customer c;

위의 변수 if, 및 일부 변수를 보여줍니다 c. 유형은 integer, float및 사용자 정의 Customer데이터 타입. 위와 같은 유형은 JavaScript뿐만 아니라 모든 언어에 대한 것일 수 있습니다. 그러나 JavaScript를 사용하면 변수를 선언 할 때 유형을 명시 적으로 정의하지 않으며 var xx는 숫자 / 문자열 / 사용자 정의 데이터 유형일 수 있습니다. 따라서 객체가 instanceof위에서 지정한 객체 인지 확인하여 객체가 지정된 유형인지 확인합니다 Customer.

var c = new Customer();
c instanceof Customer; //Returns true as c is just a customer
c instanceof String; //Returns false as c is not a string, it's a customer silly!

위에서 우리는 ctype으로 선언 된 것을 보았습니다 Customer. 우리는 그것을 새로 만들고 유형인지 여부를 확인했습니다 Customer. 물론, 그것은 true를 반환합니다. 그런 다음 여전히 Customer객체를 사용하여 객체인지 확인합니다 String. 아니, 확실히 String우리는 Customer객체가 아닌 객체를 새롭게했습니다 String. 이 경우 false를 반환합니다.

정말 간단합니다!


@Alon-나는 당신을 위해 예를 추가했습니다. 위의 color1은 문자열 유형 color1 instanceof String;이므로 color1이 문자열이기 때문에 true를 반환합니다.
JonH

@Alon-객체를 검사하여 어떤 유형의 객체인지 확인합니다. 개인 / 고객 대상을 고려하십시오. 따라서 person p = new person()p는 문자열 유형이 아닌 개인 유형입니다.
JonH

JavaScript에서는 변수의 수명 기간 동안 다른 유형을 가질 수있는 유연성이 있음을 이해하는 것이 까다로울 수 있습니다. 코드 예 : jsfiddle.net/sikusikucom/znSPv
moey

@ Siku-Siku.Com- var zero = 0; alert(zero); zero = "0"; alert(zero)우리가 아무런 문제없이 기본에서 기본 int으로 갔다는 트릭은 없습니다 string.
JonH

아, 나는 까다로운 / 새로운하는 것을 의미 이해 (안 ) 자바 스크립트에서 "유연성", ESP있다. 변수 유형을 변경하기 위해 명시 적 캐스팅이 필요한 언어에 익숙한 일부 사람들에게 적합합니다. 지적했듯이 유형을 예를 들어 기본 int에서 기본 으로 변경하는 것은 매우 쉽습니다 string.
moey

95

지금까지 어떤 주석에서도 다루지 않은 것으로 보이는 인스턴스의 중요한 측면이 있습니다 : 상속. instanceof를 사용하여 평가되는 변수는 프로토 타입 상속으로 인해 여러 "유형"에 대해 true를 리턴 할 수 있습니다.

예를 들어, 타입과 서브 타입을 정의 해 봅시다 :

function Foo(){ //a Foo constructor
    //assign some props
    return this;
}

function SubFoo(){ //a SubFoo constructor
    Foo.call( this ); //inherit static props
    //assign some new props
    return this;
}

SubFoo.prototype = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;

이제 몇 개의 "클래스"가 있으므로 인스턴스를 만들고 인스턴스가 무엇인지 알아볼 수 있습니다.

var 
    foo = new Foo()
,   subfoo = new SubFoo()
;

alert( 
    "Q: Is foo an instance of Foo? "
+   "A: " + ( foo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is foo an instance of SubFoo? " 
+   "A: " + ( foo instanceof SubFoo ) 
); // -> false

alert( 
    "Q: Is subfoo an instance of Foo? "
+   "A: " + ( subfoo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of SubFoo? "
+   "A: " + ( subfoo instanceof SubFoo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of Object? "
+   "A: " + ( subfoo instanceof Object ) 
); // -> true

마지막 줄 보여? 함수에 대한 모든 "새"호출은 Object에서 상속 된 오브젝트를 리턴합니다. 이것은 객체 생성 속기를 사용할 때도 마찬가지입니다.

alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true

"클래스"정의 자체는 어떻습니까? 그들은 무엇입니까?

alert( 
    "Q: Is Foo an instance of Object? "
+   "A:" + ( Foo instanceof Object) 
); // -> true

alert( 
    "Q: Is Foo an instance of Function? "
+   "A:" + ( Foo instanceof Function) 
); // -> true

필자는 객체를 MULTIPLE 유형의 인스턴스가 될 수 있다는 것을 이해하는 것이 중요하다고 생각합니다 instanceof. 이 마지막 예에서 함수 객체 라는 것을 분명히 보여줍니다 .

상속 패턴을 사용하고 있고 오리 타이핑 이외의 방법으로 개체의 자손을 확인하려는 경우에도 중요합니다.

누군가가 탐험하는 데 도움이되기를 바랍니다 instanceof.


더 멋진 점은 프로토 타입에서 상속 한 후에 SubFoo.prototype = new Foo();더 많은 메소드를 추가 할 수 있으며 subfoo instanceof Foo검사도 여전히 통과한다는 것입니다.subfoo instanceof SubFoo
Cory Danielson

87

여기에있는 다른 대답은 정확하지만 instanceof실제로 어떻게 작동 하는지 알지 못 하므로 일부 언어 변호사가 관심을 가질 수 있습니다.

JavaScript의 모든 객체에는 __proto__속성을 통해 액세스 할 수있는 프로토 타입이 있습니다. 함수에는 prototype속성 이 있습니다.이 속성은 __proto__객체에 의해 생성 된 객체 의 초기 값 입니다. 함수가 작성되면에 대한 고유 한 오브젝트가 제공됩니다 prototype. instanceof운영자는 당신에게 대답을 줄이 고유성을 사용합니다. 여기에 무슨 instanceof당신이 함수로 쓴 경우처럼 보일 수 있습니다.

function instance_of(V, F) {
  var O = F.prototype;
  V = V.__proto__;
  while (true) {
    if (V === null)
      return false;
    if (O === V)
      return true;
    V = V.__proto__;
  }
}

이것은 기본적으로 ECMA-262 판 5.1 (ES5라고도 함) 15.3.5.3 절을 설명합니다.

객체를 함수의 prototype속성에 재 할당 할 수 있으며 객체의 __proto__속성을 생성 한 후 다시 할당 할 수 있습니다 . 이것은 당신에게 흥미로운 결과를 줄 것입니다 :

function F() { }
function G() { }
var p = {};
F.prototype = p;
G.prototype = p;
var f = new F();
var g = new G();

f instanceof F;   // returns true
f instanceof G;   // returns true
g instanceof F;   // returns true
g instanceof G;   // returns true

F.prototype = {};
f instanceof F;   // returns false
g.__proto__ = {};
g instanceof G;   // returns false

5
__proto__IE에서 " "속성을 직접 조작하는 것은 허용되지 않습니다. 내가 올바르게 기억한다면, 재산의 직접적인 조작은 ECMA 사양에도 포함되어 있지 않기 때문에 학업 이외의 과제를 위해 그것을 사용하는 것은 좋지 않을 것입니다.
webnesto 2016 년

@webnesto 는 사실 프로토 가 사양에 없습니다. 나는 IE가 그것을 지원하지 않았다는 것을 몰랐다. 직접 조작 할 때 JS 코드에 전혀 노출되지 않았거나 쓰기 가능하지 않다는 의미입니까?
Jay Conrod 2016 년

2
이전 버전에서는 100 % 확실하지 않습니다. IE9에서는 적어도 읽을 수 있음 (변경 가능하지 않음) 과 같은 소리 ( stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10 ) 와 같습니다 . 또한 브라우저가 완전히 삭제하는 것처럼 들립니다.
webnesto

4
proto 속성 의 암시 적 존재를 이해하는 것은 사용자 코드에 액세스 할 수 있는지 여부에 중요합니다. 사양을 인용 할 수 있다면 +10, 이것이 바로 내가 찾던 것입니다.
Mike Edwards

3
프로토 타입 링크를 얻으려면을 사용하십시오 Object.getPrototypeOf(o). 이는 __proto__설명 과 동일 하지만 ECMAScript를 준수합니다.
froginvasion

45

objectof를 선언 할 때 "new"키워드를 사용하여 instanceof를 정의한다는 점에 주목할 가치가 있다고 생각합니다. JonH의 예제에서;

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

그가 언급하지 않은 것은 이것입니다.

var color1 = String("green");
color1 instanceof String; // returns false

"new"를 지정하면 실제로 문자열 생성자 함수의 종료 상태를 반환 값으로 설정하지 않고 color1 var에 복사했습니다. 새 키워드의 기능을 더 잘 보여줍니다.

function Test(name){
    this.test = function(){
        return 'This will only work through the "new" keyword.';
    }
    return name;
}

var test = new Test('test');
test.test(); // returns 'This will only work through the "new" keyword.'
test // returns the instance object of the Test() function.

var test = Test('test');
test.test(); // throws TypeError: Object #<Test> has no method 'test'
test // returns 'test'

"new"를 사용하면 함수 내의 "this"값이 선언 된 var에 할당되고, 사용하지 않으면 반환 값이 할당됩니다.


2
new자바 스크립트 유형과 함께 사용 하는 것은 이치에 맞지 않기 때문에 초보자에게 허용되는 답변을 훨씬 더 혼란스럽게 만듭니다. text = String('test')options = {}테스트에 갈 수 없습니다 instanceof와 함께, 오히려하지만, typeof대신에.
Ryan

3
Date.getTime () // 실패합니다. 예, 새로운 것이 중요합니다.
Stephen Belanger

1
콘솔에서 실행 해보십시오. getTime ()이 없기 때문에 오류가 발생합니다. 당신은 새로운 것을 사용해야합니다.
Stephen Belanger

8

다음과 같이 오류 처리 및 디버깅에 사용할 수 있습니다.

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

3
//Vehicle is a function. But by naming conventions
//(first letter is uppercase), it is also an object
//constructor function ("class").
function Vehicle(numWheels) {
    this.numWheels = numWheels;
}

//We can create new instances and check their types.
myRoadster = new Vehicle(4);
alert(myRoadster instanceof Vehicle);

3

무엇입니까?

자바 스크립트는 프로토 타입 언어로 '상속'에 프로토 타입을 사용합니다. instanceof생성자 함수의 경우 운전자는 테스트 prototypepropertype이에 존재 __proto__객체의 체인. 이것은 다음을 수행한다는 것을 의미합니다 (testObj가 함수 객체라고 가정).

obj instanceof testObj;
  1. 객체의 프로토 타입이 생성자의 프로토 타입과 같은지 확인하십시오 : obj.__proto__ === testObj.prototype >> if this is true instanceofreturn true.
  2. 프로토 타입 체인을 올라갈 것입니다. 예를 들면 다음과 같습니다. obj.__proto__.__proto__ === testObj.prototype >> if is is true instanceofreturn true.
  3. 전체 객체 프로토 타입이 검사 될 때까지 2 단계를 반복합니다. 아무 객체의 프로토 타입 체인이 일치하지 않을 경우 testObj.prototype다음 instanceof연산자를 반환합니다 false.

예:

function Person(name) {
  this.name = name;
}
var me = new Person('Willem');

console.log(me instanceof Person); // true
// because:  me.__proto__ === Person.prototype  // evaluates true

console.log(me instanceof Object); // true
// because:  me.__proto__.__proto__ === Object.prototype  // evaluates true

console.log(me instanceof Array);  // false
// because: Array is nowhere on the prototype chain

어떤 문제가 해결됩니까?

객체가 특정 프로토 타입에서 파생되는지 편리하게 확인하는 문제를 해결했습니다. 예를 들어, 함수가 다양한 프로토 타입을 가질 수있는 객체를 수신 할 때. 그런 다음 프로토 타입 체인의 메소드를 사용하기 전에 instanceof연산자를 사용 하여 이러한 메소드가 오브젝트에 있는지 여부를 확인할 수 있습니다 .

예:

function Person1 (name) {
  this.name = name;
}

function Person2 (name) {
  this.name = name;
}

Person1.prototype.talkP1 = function () {
  console.log('Person 1 talking');
}

Person2.prototype.talkP2 = function () {
  console.log('Person 2 talking');
}


function talk (person) {
  if (person instanceof Person1) {
    person.talkP1();
  }
  
  if (person instanceof Person2) {
    person.talkP2();
  }
  
  
}

const pers1 = new Person1 ('p1');
const pers2 = new Person2 ('p2');

talk(pers1);
talk(pers2);

여기서 talk()함수에서 프로토 타입이 객체에 있는지 먼저 확인합니다. 그런 다음 적절한 방법을 선택하여 실행합니다. 이 검사를 수행하지 않으면 존재하지 않는 메소드가 실행되어 참조 오류가 발생할 수 있습니다.

적절한시기와시기는?

우리는 이미 이것을 극복했습니다. 객체의 프로토 타입을 확인해야 할 때 사용하십시오.


1
난 당신이 "보다 다른 뭔가를 쓰고 싶다 생각 생성자 함수의 프로토 타입은 생성자의 프로토 타입 속성에 어딘가에 나타납니다 "
BERGI

당신은이 사람이 인터페이스를 공유하고 그 방법 모두 이름이 더 적합 할 것이라는 점을 언급 할 수 있습니다 PersonX.prototype.talk그렇게하는 것이, talk기능은 간단하게 할 수 있었다 person.talk().
Bergi

당신은 그것을 올바르게 업데이트 했으므로 정의가 더 좋습니다. 지적 해 주셔서 감사합니다!
Willem van der Veen

또한 __proto__문서에서 사용하지 마십시오. 더 이상 사용되지 않습니다. Object.getPrototype()대신 쓰기
Bergi

1

"적절한시기와 적절하지 않은시기"라는 질문에 대해 내 2 센트는 다음과 같습니다.

instanceof프로덕션 코드에는 거의 유용하지 않지만 코드가 올바른 유형의 객체를 반환 / 생성한다고 주장하는 테스트에는 유용합니다. 코드가 반환 / 생성하는 객체의 종류에 대해 명시함으로써 코드를 이해하고 문서화하는 도구로서 테스트가 더욱 강력 해집니다.


1

instanceof다음에 대한 구문 설탕입니다 isPrototypeOf.

function Ctor() {}
var o = new Ctor();

o instanceof Ctor; // true
Ctor.prototype.isPrototypeOf(o); // true

o instanceof Ctor === Ctor.prototype.isPrototypeOf(o); // equivalent

instanceof 객체 생성자의 프로토 타입에 따라 다릅니다.

생성자는 단지 정상적인 함수입니다. 엄밀히 말하면 모든 것이 자바 스크립트의 객체이기 때문에 함수 객체입니다. 모든 함수에는 프로토 타입이 있기 때문에이 함수 객체에는 프로토 타입이 있습니다.

프로토 타입은 일반 오브젝트 일 뿐이며 다른 오브젝트의 프로토 타입 체인 내에 있습니다. 즉, 다른 객체의 프로토 타입 체인에 있으면 객체를 프로토 타입으로 만듭니다.

function f() {} //  ordinary function
var o = {}, // ordinary object
 p;

f.prototype = o; // oops, o is a prototype now
p = new f(); // oops, f is a constructor now

o.isPrototypeOf(p); // true
p instanceof f; // true

instanceof는 자바 스크립트에 존재하지 않는 클래스, 가짜 때문에 운영자는 피해야한다. classES2015 에도 없는 키워드 에도 불구하고 class다시 구문상의 설탕 이기 때문에 ...하지만 그것은 또 다른 이야기입니다.


1
첫 번째 줄이 잘못되었습니다! 참조 여기 이상 "isPrototypeOf () 다릅니다 instanceof 연산자에서 표현에서."AFunction instanceof를 객체 ", 객체의 프로토 타입 체인이되지 AFunction 자체에 대해, AFunction.prototype에 대해 확인합니다."
Yan Foto

1
@Yan 그리고 여전히 instanceof에서 파생됩니다 isPrototypeOf. 나는 이것을 구문 설탕이라고 부릅니다. 그리고 당신의 MDN 소스는 농담이지 않습니까?

아닙니다. 농담이 아니어야 했지만 여전히 잘못된 연결입니다. 나는 이것을 게시 해야 했습니다. 나는 기술에 들어가고 싶지 않지만와 같은 일을 instanceof 하지 않습니다isPrototypeOf . 그게 다야.
Yan Foto

0

방금 실제 응용 프로그램을 찾았으므로 더 자주 사용할 것입니다.

jQuery 이벤트를 사용하는 경우 때로는 이벤트없이 직접 호출 될 수있는보다 일반적인 함수를 작성하려고 할 때가 있습니다. 당신이 사용할 수있는 instanceof함수의 첫 번째 매개 변수의 인스턴스의 경우는 확인 jQuery.Event하고 적절하게 반응한다.

var myFunction = function (el) {                
    if (el instanceof $.Event) 
        // event specific code
    else
        // generic code
};

$('button').click(recalc);    // Will execute event specific code
recalc('myParameter');  // Will execute generic code

필자의 경우 함수는 모든 것 (버튼의 클릭 이벤트를 통해) 또는 하나의 특정 요소 만 계산해야했습니다. 내가 사용한 코드 :

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.