ES6 イテレータと for.of ループ (詳細なチュートリアル)

亚连
リリース: 2018-06-06 17:34:05
オリジナル
1411 人が閲覧しました

この記事では主にES6イテレータ(Iterator)とfor.ofループの使い方の学習まとめを紹介しますので、参考にしてください。

1. イテレータとは何ですか?

ジェネレーターのコンセプトは Java、Python、その他の言語で利用でき、ES6 は JavaScript にも追加されました。 Iterator を使用すると、コレクション変数とインデックス変数を初期化する必要がなくなり、代わりに反復子オブジェクトの next メソッドを使用してコレクション内の次の項目の値を返します。これはプログラミングに特化しています。

イテレータは特別なインターフェイスを持つオブジェクトです。 next() メソッドが含まれます。この呼び出しは、value と Done という 2 つの属性を含むオブジェクトを返します。Value は現在の位置の値を表し、done が true の場合、next の呼び出しは無効になります。

ES5 のコレクションの走査は通常 for ループであり、配列にも forEach メソッドがあり、ES6 では Map と Set が追加され、イテレーターはすべてのコレクション データを統一的に処理できます。イテレータはインターフェイスです。データ構造がイテレータ インターフェイスを公開している限り、反復を完了できます。 ES6 では新しいトラバーサル コマンド for...of ループが作成され、Iterator インターフェイスは主に for...of による消費に使用されます。

2. イテレータの使い方

1. デフォルトのIteratorインターフェース

データ構造 Iteratorインターフェースがデプロイされている限り、このデータ構造は「Iterable」になります。 ES6 では、デフォルトの Iterator インターフェイスがデータ構造の Symbol.iterator プロパティに展開されることが規定されています。つまり、データ構造に Symbol.iterator データがある限り、それは「トラバース可能」(反復可能) であると見なされます。 ...of

    array
  1. map
  2. string
  3. typedArray(一般的な固定長バッファータイプ、バッファ内のバイナリデータを読み取る)
  4. 関数内の
  5. NodeListオブジェクト
  6. argumentsオブジェクト 上記のネイティブデータ構造にはオブジェクト(Object)が存在しないことがわかります。
  7. これは、オブジェクト属性の走査順序が不確実であり、開発者が手動で指定する必要があるためです。本質的に、トラバーサーは線形プロセスです。非線形データ構造の場合、トラバーサー インターフェイスの展開は線形変換の展開と同じです。

  8. 次の処理を実行して、オブジェクトを消費できるようにします:
// code1
function Obj(value) {
  this.value = value;
  this.next = null;
}
Obj.prototype[Symbol.iterator] = function() {
  var iterator = {
    next: next
  };
  var current = this;
  function next() {
    if (current) {
      var value = current.value;
      current = current.next;
      return {
        done: false,
        value: value
      };
    } else {
      return {
        done: true
      };
    }
  }
  return iterator;
}
var one = new Obj(1);
var two = new Obj(2);
var three = new Obj(3);
one.next = two;
two.next = three;
for (var i of one) {
  console.log(i);
}
// 1
// 2
// 3
ログイン後にコピー

2. Iteratorインターフェースを呼び出すとき

(1) 代入の構造化

// code2
let set = new Set().add('a').add('b').add('c');
let [x,y] = set;
// x='a'; y='b'
let [first, ...rest] = set;
// first='a'; rest=['b','c'];
ログイン後にコピー

(2) 演算子を展開

// code3
// 例一
var str = 'hello';
[...str] // ['h','e','l','l','o']
// 例二
let arr = ['b', 'c'];
['a', ...arr, 'd']
// ['a', 'b', 'c', 'd']
ログイン後にコピー
( 3 ) Generator 関数の yield* 式 (次の章で紹介します)

// code4
let generator = function* () {
yield 1;
yield* [2,3,4];
yield 5;
};
var iterator = generator();
iterator.next() // { value: 1, done: false }
iterator.next() // { value: 2, done: false }
iterator.next() // { value: 3, done: false }
iterator.next() // { value: 4, done: false }
iterator.next() // { value: 5, done: false }
iterator.next() // { value: undefined, done: true }
ログイン後にコピー

(4) その他の場合

for..of

    Array.from
  1. Map(), Set( )、WeakMap()、WeakSet()
  2. Promise.all()
  3. Promise.race()
  4. 3. for...ofループの利点

  5. まず見てみましょう、配列 forEach メソッド 欠点:
// code5
myArray.forEach(function (value) {
 console.log(value);
});
ログイン後にコピー

この書き方の問題点は、forEach ループを途中で抜け出すことができず、break コマンドも return コマンドも有効にならないことです。 オブジェクト for...in ループの欠点をもう一度見てください:

for (var index in myArray) {
 console.log(myArray[index]);
};
ログイン後にコピー

配列のキー名は数字ですが、for...in ループではキー名として文字列「0」、「」が使用されます。 1 」、「2」など

    for...in ループは、数値キー名を走査できるだけでなく、手動で追加されたピリオドの推奨事項 (プロトタイプ チェーン上のキーも含む) も走査できます。
  1. 場合によっては、for...in ループセッションはキー名を任意の順序で走査します
  2. for...in 走査は主にオブジェクトの走査用に設計されており、配列の走査には適していません
  3. 、for...of の重要な利点は何ですか?
  4. は、for...inと同じ簡潔な構文を持ちますが、for...inの欠点はありません

    forEachメソッドとは異なり、break、 continue、returnとともに使用できます
  1. すべてのデータ構造を横断するための統合操作インターフェイスを提供
  2. for (var n of fibonacci) {
     if (n > 1000) {
      break;
      console.log(n);
     }
    }
    ログイン後にコピー
  3. 4. 各データ型の for...of ループを使用するには?

  4. (1) Array

for...of ループを使用すると、配列を走査してキー値を取得できます

var arr = ['a', 'b', 'c', 'd'];
for (let a in arr) {
  console.log(a); // 0 1 2 3
}
for (let a of arr) {
  console.log(a); // a b c d
}
ログイン後にコピー
for...of ループはトラバーサー インターフェイスを呼び出します。配列のトラバーサー インターフェイスは数値のみを返します。 Index

let arr = [3, 5, 7];
arr.foo = 'hello';
for (let i in arr) {
  console.log(i); // "0", "1", "2", "foo"
}
for (let i of arr) {
  console.log(i); // "3", "5", "7"
}
ログイン後にコピー

(2) Map 構造体と Set 構造体

var engines = new Set(["Gecko", "Trident", "Webkit", "Webkit"]);
for (var e of engines) {
  console.log(e);
}
// Gecko
// Trident
// Webkit
var es6 = new Map();
es6.set("edition", 6);
es6.set("committee", "TC39");
es6.set("standard", "ECMA-262");
for (var [name, value] of es6) {
  console.log(name + ": " + value);
}
// edition: 6
// committee: TC39
// standard: ECMA-262
ログイン後にコピー

上記のコードから、for...of ループが Map 構造体と Set 構造体を走査するとき、走査の順序は各メンバーの順序であることがわかります。 Set 構造を走査すると値が返され、Map 構造を走査すると配列の 2 つのメンバーが返されます。マップメンバー。

(3) 配列状のオブジェクト

String

// 普通的字符串遍历
let str = "yuan";
for (let s of str) {
 console.log(s); // y u a n
}

// 遍历含有 32位 utf-16字符的字符串
for (let x of 'a\uD83D\uDC0A') {
 console.log(x);
}
// 'a'
// '\uD83D\uDC0A'
ログイン後にコピー

DOM NodeList オブジェクト

let paras = document.querySelectorAll("p");
for (let p of paras) {
 p.classList.add("test");
}
ログイン後にコピー

arguments オブジェクト

function printArgs() {
 for (let x of arguments) {
  console.log(x);
 }
}
printArgs("a", "n");
// "a"
// "n"
ログイン後にコピー

配列状のオブジェクトのトラバーサル処理用の Iterator インターフェースはありません

Array.from メソッドを借用して処理します

let arrayLike = {
  length: 2,
  0 : 'a',
  1 : 'b'
};
// 报错
for (let x of arrayLike) {
  console.log(x);
}
// 正确
for (let x of Array.from(arrayLike)) {
  console.log(x);
}
ログイン後にコピー

(4) オブジェクト

通常のオブジェクトの場合、for...of を直接使用してトラバースすることはできません。そうでない場合はエラーが報告され、これを使用するには Iterator インターフェイスをデプロイする必要があります。次の 2 つの方法でデプロイします:

// 方法一:使用 Object.keys 方法讲对象的键名生成一个数组
for (var key of Object.keys(someObject)) {
 console.log(key + ": " + someObject[key]);
}

// 方法二:使用Generator 函数将对象重新包装一下
function * entries(obj) {
  for (let key of Object.keys(obj)) {
    yield[key, obj[key]];
  }
}
for (let[key, value] of entries(obj)) {
  console.log(key, "->", value);
}
// a -> 1
// b -> 2
// c -> 3
ログイン後にコピー

三、迭代器应用实例

1、斐波那契数列

下面我们就使用迭代器来自定义自己的一个斐波那契数列组,我们直到斐波那契数列有两个运行前提,第一个前提是初始化的前两个数字为0,1,第二个前提是将来的每一个值都是前两个值的和。这样我们的目标就是每次都迭代输出一个新的值。

var it = { [Symbol.iterator]() {
    return this
  },
  n1: 0,
  n2: 1,
  next() {
    let temp1 = this.n1,
    temp2 = this.n2;
    [this.n1, this.n2] = [temp2, temp1 + temp2]
    return {
      value: temp1,
      done: false
    }
  }
}

for (var i = 0; i < 20; i++) {
  console.log(it.next())
}

// 
  "value": 0,
  "done": false
} {
  "value": 1,
  "done": false
} {
  "value": 1,
  "done": false
} {
  "value": 2,
  "done": false
} {
  "value": 3,
  "done": false
} {
  "value": 5,
  "done": false
}... {
  "value": 2584,
  "done": false
} {
  "value": 4181,
  "done": false
}
ログイン後にコピー

2、任务队列迭代器

我们可以定义一个任务队列,该队列初始化时为空,我们将待处理的任务传递后,传入数据进行处理。这样第一次传递的数据只会被任务1处理,第二次传递的只会被任务2处理… 代码如下:

var Task = {
  actions: [],
  [Symbol.iterator]() {
    var steps = this.actions.slice();
    return { [Symbol.iterator]() {
        return this;
      },
      next(...args) {
        if (steps.length > 0) {
          let res = steps.shift()(...args);
          return {
            value: res,
            done: false
          }
        } else {
          return {
            done: true
          }
        }
      }
    }
  }
}

Task.actions.push(function task1(...args) {
  console.log("任务一:相乘") return args.reduce(function(x, y) {
    return x * y
  })
},
function task2(...args) {
  console.log("任务二:相加") return args.reduce(function(x, y) {
    return x + y
  }) * 2
},
function task3(...args) {
  console.log("任务三:相减") return args.reduce(function(x, y) {
    return x - y
  })
});

var it = Task[Symbol.iterator]();
console.log(it.next(10, 100, 2));
console.log(it.next(20, 50, 100)) console.log(it.next(10, 2, 1))
 // 
任务一:相乘 {
  "value": 2000,
  "done": false
}任务二:相加 {
  "value": 340,
  "done": false
}任务三:相减 {
  "value": 7,
  "done": false
}
ログイン後にコピー

3、延迟执行

假设我们有一个数据表,我们想按大小顺序依次的获取数据,但是我们又不想提前给他排序,有可能我们根本就不去使用它,所以我们可以在第一次使用的时候再排序,做到延迟执行代码:

var table = {
  "d": 1,
  "b": 4,
  "c": 12,
  "a": 12
}
table[Symbol.iterator] = function() {
  var _this = this;
  var keys = null;
  var index = 0;

  return {
    next: function() {
      if (keys === null) {
        keys = Object.keys(_this).sort();
      }

      return {
        value: keys[index],
        done: index++>keys.length
      };
    }
  }
}

for (var a of table) {
  console.log(a)
} 
// a b c d
ログイン後にコピー

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中如何实现微信分享朋友圈,发送朋友

详解如何实现vuex(详细教程)

通过vue.js实现微信支付

以上がES6 イテレータと for.of ループ (詳細なチュートリアル)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!