Loading...

Класс текшерүү: "instanceof"

Класс текшерүү: "instanceof"

 

Оператор instanceofмурасты эске алуу менен объекттин көрсөтүлгөн класска таандык экендигин текшерүүгө мүмкүндүк берет.

Мындай текшерүү көп учурларда талап кылынышы мүмкүн. Бул жерде биз аргументтерди түрүнө жараша ар кандай чечмелеген полиморфтук функцияны түзүү үчүн колдонобуз.

instanceof оператор

Синтаксис:

@A@obj instanceof Class@A@

Оператор класска таандык болсо trueже класстан мураска калса кайтып келет.objClass

Мисалы:

@A@class Rabbit {}
let rabbit = new Rabbit();

// это объект класса Rabbit?
alert( rabbit instanceof Rabbit ); // true@A@

Ал ошондой эле конструктор функциялары менен иштейт:

 
 
@A@// вместо класса
function Rabbit() {}

alert( new Rabbit() instanceof Rabbit ); // true@A@

…Жана камтылган класстар үчүн Array:

 
 
@A@let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true@A@

Сураныч, бул arrкласска таандык экенин эске алыңыз Object, анткени Arrayал класстан мураска алат Object.

Адатта, оператор instanceofтекшерүү үчүн прототиби чынжыр аркылуу карайт. Бирок бул жүрүм-турумду статикалык ыкма менен өзгөртүүгө болот Symbol.hasInstance.

Алгоритм obj instanceof Classтөмөнкүдөй иштейт:

  1. Эгерде статикалык ыкма бар болсо Symbol.hasInstance, анда аны чакырыңыз: Class[Symbol.hasInstance](obj)trueБул же , же кайтарылышы керек false, ушуну менен бүттү. Бул жөн гана кол менен орнотуу мүмкүнчүлүгү instanceof.

    Мисал:

    @A@// проверка instanceof будет полагать,
    // что всё со свойством canEat - животное Animal
    class Animal {
      static [Symbol.hasInstance](obj) {
        if (obj.canEat) return true;
      }
    }
    
    let obj = { canEat: true };
    alert(obj instanceof Animal); // true: вызван Animal[Symbol.hasInstance](obj)@A@
  2. Көпчүлүк класстарда жок Symbol.hasInstanceClass.prototypeБул учурда стандарттык логика колдонулат: анын прототип чынжырындагы прототиптердин бирине барабар экендиги текшерилет obj.

    Башка сөз менен айтканда, ал салыштырат:

    @A@obj.__proto__ === Class.prototype?
    obj.__proto__.__proto__ === Class.prototype?
    obj.__proto__.__proto__.__proto__ === Class.prototype?
    ...
    // если какой-то из ответов true - возвратить true
    // если дошли до конца цепочки - false@A@

    Жогорудагы мисалда rabbit.__proto__ === Rabbit.prototype, натыйжа ошол замат алынат.

    Мурастык учурда дал келүү экинчи этапта болот:

    @A@class Animal {}
    class Rabbit extends Animal {}
    
    let rabbit = new Rabbit();
    alert(rabbit instanceof Animal); // true
    
    // rabbit.__proto__ === Animal.prototype (нет совпадения)
    // rabbit.__proto__.__proto__ === Animal.prototype (совпадение!)@A@

Бул жерде анын кантип rabbit instanceof Animalсалыштырылат Animal.prototype:

Айтмакчы, objA.isPrototypeOf(objB) ыкмасы бар , ал trueобъект objAобъекттин прототипинин чынжырында бир жерде болсо, кайтарып берет objB. Ошентип, obj instanceof Classаны кайра деп айтууга болот Class.prototype.isPrototypeOf(obj).

Бул күлкүлүү, бирок конструктор өзү Classвалидация процессине катышпайт! Прототип чынжыр гана маанилүү Class.prototype.

prototypeБул объект түзүлгөндөн кийин мүлктү өзгөртүүдө кызыктуу кесепеттерге алып келиши мүмкүн .

Мисалы, бул жерде:

@A@function Rabbit() {}
let rabbit = new Rabbit();

// заменяем прототип
Rabbit.prototype = {};

// ...больше не rabbit!
alert( rabbit instanceof Rabbit ); // false@A

Бонус: Object.prototype.toString түрүн кайтарат

Кадимки объекттер төмөнкүдөй сапка айландырылаарын билебиз [object Object]:

@A@let obj = {};

alert(obj); // [object Object]
alert(obj.toString()); // то же самое@A@

Бул ыкманы ишке ашыруу кандай иштейт toString. Бирок toStringыкманы алда канча күчтүү кылган жашыруун өзгөчөлүктөр бар. Биз аны кеңейтилген версия typeofжана альтернатива катары колдоно алабыз instanceof.

Кызык угулат? Бул чыныгы. Мистиканы жок кылалы.

Спецификацияга ылайык , орнотулган ыкма toStringобъекттен карызга алынышы мүмкүн жана башка баалуулуктардын контекстинде чакырылышы мүмкүн. Ал эми натыйжа бул баалуулуктун түрүнө жараша болот.

  • Сан үчүн бул болмок[object Number]
  • Буль үчүн бул болмок[object Boolean]
  • үчүн null:[object Null]
  • үчүн undefined:[object Undefined]
  • Массивдер үчүн:[object Array]
  • …жана башкалар. (Жүрүм-турум ыңгайлаштырылган).

демонстрация кылалы:

@A@// скопируем метод toString в переменную для удобства
let objectToString = Object.prototype.toString;

// какой это тип?
let arr = [];

alert( objectToString.call(arr) ); // [object Array]@A@

Мисалда биз контекстте функцияны аткаруу үчүн Декораторлор жана Чалууларды багыттоо, чалуу/колдонуу бөлүмүндө сүрөттөлгөндөй call колдондук .objectToStringthis=arr

Ички ыкманын алгоритми toStringчалуу контекстин талдап this, тиешелүү натыйжаны берет. Көбүрөөк мисалдар:

 
 
@A@let s = Object.prototype.toString;

alert( s.call(123) ); // [object Number]
alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]@A@

Symbol.toStringTag

Объекттин методунун жүрүм-турумун toStringобъекттин атайын касиетин колдонуу менен ыңгайлаштырууга болот Symbol.toStringTag.

Мисалы:

@A@let user = {
  [Symbol.toStringTag]: "User"
};

alert( {}.toString.call(user) ); // [object User]@A

Көпчүлүк айлана-чөйрөгө тиешелүү объекттер бул касиетке ээ. Бул жерде кээ бир браузер мисалдары:

@A@// toStringTag для браузерного объекта и класса
alert( window[Symbol.toStringTag]); // window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest

alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]@A@

Symbol.toStringTagКөрүнүп тургандай, натыйжада оролгон маани (эгер бар болсо) [object ...].

Жыйынтыгында "стероиддик типтеги тип" болуп саналат, ал жөн гана примитивдүү маалымат түрлөрү менен иштебестен, орнотулган объекттер менен да иштейт жана ал тургай, ыңгайлаштырылышы мүмкүн.

Типти сап катары алгыбыз келгенде, анын {}.toString.callордуна орнотулган объекттер үчүн колдонсо болот , жөн гана текшерүү эмес.instanceof

Бардыгы

Келгиле, биз биле турган текшерүү ыкмаларын кыскача карап көрөлү:

  иштөө үчүн кайтып келет
typeof примитивдер линия
{}.toString примитивдер, орнотулган объекттер, объектилер мененSymbol.toStringTag линия
instanceof объектилер чын/жалган

Көрүнүп тургандай, техникалык жактан {}.toStringкараганда typeof.

instanceofБиз класс иерархиялары менен иштегенде жана мурасты эске алуу менен текшерүүлөрдү жүргүзгүбүз келгенде оператор эң сонун тандоо.

Tasks

маанилүүлүгү: 5

Эмне үчүн instanceofтөмөндөгү мисал кайтып келет trueaколдонуу менен жаралбаганын көрүп жатабыз B().

@A@function A() {}
function B() {}

A.prototype = B.prototype = {};

let a = new A();

alert( a instanceof B ); // true@A@