Что такое оператор instanceof в JavaScript? - PullRequest
296 голосов
/ 15 марта 2010

Ключевое слово instanceof в JavaScript может быть довольно запутанным, когда оно встречается впервые, поскольку люди склонны считать, что JavaScript не является объектно-ориентированным языком программирования.1005 *

Какие проблемы это решает? Когда это уместно, а когда нет?

Ответы [ 10 ]

258 голосов
/ 15 марта 2010

1001 * InstanceOf * Операнд левой стороны (LHS) - это фактический объект, проверяемый операндом правой стороны (RHS), который является фактическим конструктором класса. Основное определение: 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, если объект наследуется от прототипа classe: var p = new Person("Jon"); p instanceof Person То есть p instanceof Person верно, поскольку p наследуется от Person.prototype. По запросу ОП Я добавил небольшой пример с примером кода и объяснением. Когда вы объявляете переменную, вы присваиваете ей определенный тип. Например: int i; float f; Customer c; Выше показаны некоторые переменные, а именно i, f и c. Типы integer, float и пользовательский тип данных Customer. Типы, подобные приведенным выше, могут быть для любого языка, а не только для JavaScript. Однако в JavaScript, когда вы объявляете переменную, вы явно не определяете тип, var x, x может быть числом / строкой / определяемым пользователем типом данных. Что делает 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! Выше мы видели, что c было объявлено с типом Customer. Мы new'd его и проверили, имеет ли он тип Customer или нет. Конечно, это возвращает истину. Затем, продолжая использовать объект Customer, мы проверяем, является ли он String. Нет, определенно не String мы обновили Customer объект, а не String объект. В этом случае возвращается false. Это действительно так просто!

91 голосов
/ 30 июня 2011

У экземпляра экземпляра есть важный аспект, который пока не рассматривается ни в одном из комментариев: наследование. Переменная, оцениваемая с использованием 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 = new Foo(); // Inherit prototype

Теперь, когда у нас есть пара «классов», давайте создадим несколько экземпляров и выясним, к чему они относятся:

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.

86 голосов
/ 10 февраля 2012

Другие ответы здесь верны, но они не касаются того, как на самом деле работает 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
45 голосов
/ 11 апреля 2011

Я думаю, что стоит отметить, что instanceof определяется использованием ключевого слова "new" при объявлении объекта. В примере от 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» фактически копировало конечное состояние функции конструктора String в переменную color1, а не просто устанавливало его в возвращаемое значение. Я думаю, что это лучше показывает, что делает новое ключевое слово;

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» внутри функции объявленной переменной, в то время как ее использование не присваивает возвращаемое значение.

8 голосов
/ 22 мая 2011

И вы можете использовать его для обработки ошибок и отладки, например:

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 голосов
/ 15 марта 2010
//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);
2 голосов
/ 05 сентября 2018

Что это?

Javascript - это язык прототипов, что означает, что он использует прототипы для «наследования». оператор instanceof проверяет, присутствует ли свойство prototype функции конструктора в цепочке __proto__ объекта. Это означает, что он будет делать следующее (при условии, что testObj является функциональным объектом):

obj instanceof testObj;
  1. Проверьте, равен ли прототип объекта прототипу конструктора: obj.__proto__ === testObj.prototype >> если это true instanceof, то вернется true.
  2. Поднимется по цепочке прототипов. Например: obj.__proto__.__proto__ === testObj.prototype >> если это true instanceof, то вернется 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 голос
/ 26 июля 2016

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 зависит только от прототипа конструктора объекта.

Конструктор - это просто нормальная функция. Строго говоря, это функциональный объект, поскольку в JavaScript все является объектом. И у этого функционального объекта есть прототип, потому что у каждой функции есть прототип.

Прототип - это обычный объект, который находится в цепочке прототипов другого объекта. Это означает, что нахождение в цепочке прототипов другого объекта превращает объект в прототип:

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 следует избегать, поскольку он подделывает классы, которых нет в Javascript. Несмотря на то, что ключевое слово class отсутствует в ES2015, так как class снова является просто синтаксическим сахаром для ..., но это другая история.

1 голос
/ 24 июля 2013

На вопрос «Когда это уместно, а когда нет?», Мои 2 цента:

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

0 голосов
/ 26 июля 2013

Я только что нашел реальное приложение и теперь буду использовать его чаще, я думаю.

Если вы используете события 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...
};
...