Loading...

Кайталануучу объекттер

Кайталануучу объекттер

 

Кайталануучу (же кайталануучу ) объекттер массивдердин жалпылоосу болуп саналат. Ар кандай объектти циклде колдонууга мүмкүндүк берген түшүнүк for..of.

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

for..ofЭгерде объект массив эмес, кээ бир элементтердин (тизме, топтом) жыйындысы болсо, анда аларды кайталоо үчүн циклди колдонуу ыңгайлуу, андыктан муну кантип жасоо керектигин карап көрөлү.

Symbol.iterator

Кайталануучу объекттердин жайгашуу принцибин алардын бирин түзүү менен оңой түшүнө алабыз.

Мисалы, бизде объект бар. Бул массив эмес, бирок ал үчүн ылайыктуу окшойт for..of.

Мисалы, rangeсандардын диапазонун билдирген объект:

@A@let range = {
  from: 1,
  to: 5
};
// Мы хотим, чтобы работал for..of:
// for(let num of range) ... num=1,2,3,4,5@A@

Аны кайталануучу кылуу үчүн range(жана for..ofаны менен иштөөгө уруксат берүү) биз объектке аталган ыкманы кошуубуз керек ( бул үчүн гана түзүлгөн Symbol.iteratorатайын орнотулган ).Symbol

  1. Цикл for..ofиштегенде, бул ыкманы бир жолу чакырат (же метод табылбаса ката кетирет). Бул ыкма итераторду - методу бар объектти кайтарышы керек next.
  2. Андан ары бул кайтарылган объект менен ганаfor..of иштейт .
  3. for..ofКийинки маанини алгысы келгенде, ал объект next()боюнча методду чакырат.
  4. Чалуунун натыйжасы next()окшош болушу керек {done: Boolean, value: any}, бул done=trueцикл аяктаганын билдирет, антпесе valueал кийинки маанини камтыйт.

Бул жерде түшүндүрмөлөр менен толук ишке ашыруу болуп саналат range:

@A@let range = {
  from: 1,
  to: 5
};

// 1. вызов for..of сначала вызывает эту функцию
range[Symbol.iterator] = function() {

  // ...она возвращает объект итератора:
  // 2. Далее, for..of работает только с этим итератором, запрашивая у него новые значения
  return {
    current: this.from,
    last: this.to,

    // 3. next() вызывается на каждой итерации цикла for..of
    next() {
      // 4. он должен вернуть значение в виде объекта {done:.., value :...}
      if (this.current <= this.last) {
        return { done: false, value: this.current++ };
      } else {
        return { done: true };
      }
    }
  };
};

// теперь работает!
for (let num of range) {
  alert(num); // 1, затем 2, 3, 4, 5
}@A@

Итераторлордун негизги өзгөчөлүгүнө көңүл буруңуз: тынчсызданууларды бөлүү.

  • Анын өзүнүн rangeыкмасы жок next().
  • Анын ордуна, "итератор" деп аталган башка объект чалуу тарабынан түзүлөт range[Symbol.iterator]()жана бул next()баалуулуктарды жаратат.

Ошентип, итератор объекти кайталануучу объектинин өзүнөн өзүнчө.

rangeТехникалык жактан биз аларды бириктирип, кодду жөнөкөйлөтүү үчүн өзүн итератор катары колдоно алабыз .

Мисалы, бул сыяктуу:

@A@let range = {
  from: 1,
  to: 5,

  [Symbol.iterator]() {
    this.current = this.from;
    return this;
  },

  next() {
    if (this.current <= this.to) {
      return { done: false, value: this.current++ };
    } else {
      return { done: true };
    }
  }
};

for (let num of range) {
  alert(num); // 1, затем 2, 3, 4, 5
}@

Эми range[Symbol.iterator]()объекттин өзүн кайтарат range: анын талап кылынган ыкмасы бар next()жана ал итерациянын учурдагы абалын эстейт this.current. Кыскача айтканда? Ооба. Жана кээде бул да жакшы.

Бул ыкманын кемчилиги - азыр биз бул объектти эки параллелдүү циклде колдоно албайбыз for..of: алар жалпы учурдагы итерация абалына ээ болот, анткени азыр бир гана итератор бар - объекттин өзү. Бирок бир эле учурда аткарылуучу эки циклдин зарылдыгы for..ofасинхрондук операциялар болгондо да сейрек пайда болот.

Чексиз итераторлор

Сиз чексиз итератор жасай аласыз. Мисалы, rangeчексиз болот range.to = Infinity. Же псевдококустук сандардын чексиз ырааттуулугун жараткан кайталануучуну түзө алабыз. Пайдалуу болуп калат.

Метод nextэч кандай чектөөлөргө ээ эмес, ал барган сайын жаңы баалуулуктарды кайтара алат, бул нормалдуу көрүнүш.

Албетте, for..ofмындай кайталануучу объект менен цикл чексиз болот. Бирок биз аны колдонуу менен ар дайым үзгүлтүккө учурата алабыз break.

Стринг - кайталануучу объект

Эң кеңири колдонулган камтылган кайталануучулар массивдер жана саптар.

Сап for..ofсимволдордун үстүнөн кайталанат:

@A@for (let char of "test") {
  // срабатывает 4 раза: по одному для каждого символа
  alert( char ); // t, затем e, затем s, затем t
}@A@

Жана ал суррогат жуптары менен да туура иштейт!

@A@let str = '𝒳😂';
for (let char of str) {
    alert( char ); // 𝒳, а затем 😂
}@A@

Ачык итератор чалуу

Итераторлорду бир аз көбүрөөк түшүнүү үчүн, аларды кантип ачык колдонууну карап көрөлү.

Биз сапты циклдегидей эле кайталайбыз for..of, бирок кол менен түз чалуулар аркылуу. Төмөнкү код сап итераторун алып, андан баалуулуктарды алат:

@A@let str = "Hello";

// делает то же самое, что и
// for (let char of str) alert(char);

let iterator = str[Symbol.iterator]();

while (true) {
  let result = iterator.next();
  if (result.done) break;
  alert(result.value); // выводит символы один за другим
}@A@

Бул чанда гана керек, бирок ал бизге процессти көзөмөлдөөгө мүмкүнчүлүк берет for..of. Мисалы, биз итерация процессин бөлүктөргө бөлсөк болот: бир нече элементтерди кайталап, андан кийин токтоп, башка бир нерсе жасап, анан улантыңыз.

Итеративдер жана псевдо-массивдер

Абдан окшош, бирок ошол эле учурда абдан айырмаланган эки расмий термин бар. Андыктан баш аламандыкка жол бербөө үчүн аларды жакшы түшүнгөнүңүздү текшериңиз.

  • ИтеративдерSymbol.iterator - жогоруда сүрөттөлгөндөй ыкманы ишке ашыруучу объекттер .
  • Псевдомассивдер - бул индекстери жана касиети бар объекттер length, башкача айтканда, массивдерге окшош.

JavaScriptти браузерде же башка чөйрөлөрдө колдонгондо, биз кайталануучу же псевдо-массив же экөө тең объекттерге туш болушубуз мүмкүн.

Мисалы, саптар кайталануучу (алар үчүн иштейт for..of) жана псевдо-массивдер (алар индекстелген жана length).

Бирок кайталануучу объект псевдо-массив болбошу мүмкүн. Тескерисинче, псевдо-массив кайталанбашы мүмкүн.

rangeМисалы, жогорудагы мисалдагы объект кайталануучу, бирок ал псевдо-массив эмес, анткени анын индекстелген касиеттери жана length.

Жана бул жерде псевдо-массив болгон объект, бирок кайталанбайт:

 
 
let arrayLike = { // есть индексы и свойство length => псевдомассив
  0: "Hello",
  1: "World",
  length: 2
};

// Ошибка (отсутствует Symbol.iterator)
for (let item of arrayLike) {}

Алардын кандай жалпылыгы бар? Итеративдер да, псевдо-массивдер да адатта массив эмесpush , алардын методдору жок popж.б.у.с. Эгерде бизде мындай объект бар болсо жана аны менен массив катары иштегибиз келсе, абдан ыңгайсыз. rangeМисалы, биз массив ыкмаларын колдонуу менен иштегибиз келет . Буга кантип жетишсе болот?

Array.from

Array.from жалпы ыкмасы бар , ал кайталануучу объектти же псевдо-массивди алып, аны "чыныгы" кылат Array. Андан кийин, биз буга чейин массив ыкмаларын колдоно алабыз.

Мисалы:

@A@let arrayLike = {
  0: "Hello",
  1: "World",
  length: 2
};

let arr = Array.from(arrayLike); // (*)
alert(arr.pop()); // World (метод работает)@A@

Array.fromобъектти inline алат (*), анын кайталануучу объект же псевдо-массив экендигин текшерет, андан кийин жаңы массив түзүп, ал жердеги бардык элементтерди көчүрөт.

Ошол эле нерсе кайталануучу объект менен болот:

@A@// range взят из примера выше
let arr = Array.from(range);
alert(arr); // 1,2,3,4,5 (преобразование массива через toString работает)@A@

Толук синтаксис Array.fromкошумча "трансформациялоо" функциясын көрсөтүүгө мүмкүндүк берет:

@A@Array.from(obj[, mapFn, thisArg])@A@

Кошумча экинчи аргумент массивге кошулганга чейин ар бир элементке колдонула турган функция болушу мүмкүн жана ал функцияны коюуга thisArgмүмкүндүк берет .this

Мисалы:

@A@// range взят из примера выше

// возводим каждое число в квадрат
let arr = Array.from(range, num => num * num);

alert(arr); // 1,4,9,16,25@A@

Бул жерде биз Array.fromсапты анын элементтеринин массивине айландыруу үчүн колдонобуз:

@A@let str = '𝒳😂';

// разбивает строку на массив её элементов
let chars = Array.from(str);

alert(chars[0]); // 𝒳
alert(chars[1]); // 😂
alert(chars.length); // 2@A@

дан айырмаланып str.split, бул ыкма сап итерациясына таянат, ошондуктан, сыяктуу for..of, ал суррогат жуптары менен туура иштейт.

Техникалык жактан бул окшош:

 
 
@A@let str = '𝒳😂';

let chars = []; // Array.from внутри себя выполняет тот же цикл
for (let char of str) {
  chars.push(char);
}

alert(chars);@A@

...Бирок алда канча кыскараак.

@A@sliceАл тургай , биз суррогат жуптарды колдогон , түзө алабыз :

 
 
function slice(str, start, end) {
  return Array.from(str).slice(start, end).join('');
}

let str = '𝒳😂𩷶';

alert( slice(str, 1, 3) ); // 😂𩷶

// а вот встроенный метод не поддерживает суррогатные пары
alert( str.slice(1, 3) ); // мусор (две части различных суррогатных пар)@A@

Бардыгы

Циклде колдонула турган объекттер кайталануучуfor..of деп аталат .

  • Техникалык жактан, кайталануучуларда Symbol.iterator.
    • Чалуунун натыйжасы итераторobj[Symbol.iterator] деп аталат . Ал итерация процессин башкарат.
    • next()Итераторда объектти кайтаруучу метод болушу керек, {done: Boolean, value: any}ал жерде done:trueал кайталоо процессинин аяктаганын, антпесе valueкийинки маанини берет.
  • Метод Symbol.iteratorцикл тарабынан автоматтык түрдө чакырылат for..of, бирок сиз аны түз чакырсаңыз да болот.
  • Саптар же массивдер сыяктуу орнотулган кайталануучулар да Symbol.iterator.
  • Саптын итератору суррогат жуптары жөнүндө билет.

Индекстелген касиеттерге ээ жана псевдо-массивдерlength деп аталган объекттер . Алар ошондой эле башка касиеттерге жана ыкмаларга ээ болушу мүмкүн, бирок аларда камтылган массив ыкмалары жок.

Эгерде биз спецификацияны карай турган болсок, анда орнотулган ыкмалардын көбү "чыныгы" массивдердин ордуна кайталануучуларга же псевдо-массивдерге таянарын көрө алабыз, анткени ал объекттер абстракттуураак.

Array.from(obj[, mapFn, thisArg])Arrayкайталануучу же псевдо-массивден чыныгыны түзөт obj, анан биз ага массив ыкмаларын колдоно алабыз. Кошумча аргументтер mapFnжана thisArgар бир элементке берилген контекст менен функцияны колдонууга мүмкүндүк берет.