【JS】12--迭代器和生成器

迭代器和生成器

前置知識(shí)
JavaScrip已經(jīng)提供多個(gè)迭代集合的方法,從簡(jiǎn)單的for循環(huán)到map()filter()
迭代器和生成器將迭代的概念直接帶入核心語(yǔ)言,并提供一種機(jī)制來(lái)自定義for...of循環(huán)的行為渣蜗。

本文會(huì)將知識(shí)點(diǎn)分為兩大部分,簡(jiǎn)單介紹和詳細(xì)介紹
簡(jiǎn)單介紹旷祸,適合基礎(chǔ)入門會(huì)使用的目標(biāo)耕拷;
詳細(xì)介紹,會(huì)更加深入的做介紹托享,適合理解原理骚烧;

#1. 概述

當(dāng)我們使用循環(huán)語(yǔ)句迭代數(shù)據(jù)時(shí),需初始化一個(gè)變量來(lái)記錄每一次迭代在數(shù)據(jù)集合中的位置:

let a = ["aaa","bbb","ccc"];
for (let i = 0; i< a.length; i++){
    console.log(a[i]);
}

這邊的i就是我們用來(lái)記錄迭代位置的變量闰围,但是在ES6開(kāi)始赃绊,JavaScrip引入了迭代器這個(gè)特性,并且新的數(shù)組方法新的集合類型(如Set集合Map集合)都依賴迭代器的實(shí)現(xiàn)辫诅,這個(gè)新特性對(duì)于高效的數(shù)據(jù)處理而言是不可或缺的凭戴,在語(yǔ)言的其他特性中也都有迭代器的身影:新的for-of循環(huán)、展開(kāi)運(yùn)算符(...)炕矮,甚至連異步編程都可以使用迭代器么夫。

本文主要會(huì)介紹ES6中新增的迭代器(Iterator)和生成器(Generator)。

#2. 迭代器(簡(jiǎn)單介紹)

迭代器是一種特殊對(duì)象肤视,它具有一些專門為迭代過(guò)程設(shè)計(jì)的專有接口档痪,所有的迭代器對(duì)象都有一個(gè)next()方法,每次調(diào)用都會(huì)返回一個(gè)結(jié)果對(duì)象邢滑。
這個(gè)結(jié)果對(duì)象腐螟,有兩個(gè)屬性:

  • value: 表示下一個(gè)將要返回的值。
  • done: 一個(gè)布爾值,若沒(méi)有更多可返回的數(shù)據(jù)時(shí)乐纸,值為true衬廷,否則false

如果最后一個(gè)值返回后汽绢,再調(diào)用next()吗跋,則返回的對(duì)象的done值為true,而value值如果沒(méi)有值的話宁昭,返回的為undefined跌宛。

ES5實(shí)現(xiàn)一個(gè)迭代器:

function myIterator(list){
    var i = 0;
    return {
        next: function(){
            var done = i >= list.length;
            var value = !done ? list[i++] : undefined;
            return {
                done : done,
                value : value
            }
        }
    }
}

var iterator = myIterator([1,2,3]);
iterator.next();  // "{done: false, value: 1}"
iterator.next();  // "{done: false, value: 2}"
iterator.next();  // "{done: false, value: 3}"
iterator.next();  // "{done: true, value: undefined}"
// 以后的調(diào)用都一樣
iterator.next();  // "{done: true, value: undefined}"

從上面代碼可以看出,ES5的實(shí)現(xiàn)還是比較麻煩积仗,而ES6新增的生成器疆拘,可以使得創(chuàng)建迭代器對(duì)象的過(guò)程更加簡(jiǎn)單。

#3. 生成器(簡(jiǎn)單介紹)

生成器是一種返回迭代器的函數(shù)寂曹,通過(guò)function關(guān)鍵字后的星號(hào)(*)來(lái)表示哎迄,函數(shù)中會(huì)用到新的關(guān)鍵字yield。星號(hào)可以緊挨著function關(guān)鍵字稀颁,也可以在中間添加一個(gè)空格芬失。

function *myIterator(){
    yield 1;
    yield 2;
    yield 3;
}
let iterator = myIterator();
iterator.next();  // "{done: false, value: 1}"
iterator.next();  // "{done: false, value: 2}"
iterator.next();  // "{done: false, value: 3}"
iterator.next();  // "{done: true, value: undefined}"
// 以后的調(diào)用都一樣
iterator.next();  // "{done: true, value: undefined}"

生成器函數(shù)最有趣的部分是,每當(dāng)執(zhí)行完一條yield語(yǔ)句后函數(shù)就會(huì)自動(dòng)停止執(zhí)行匾灶,比如上面代碼棱烂,當(dāng)yield 1;執(zhí)行完后,便不會(huì)執(zhí)行任何語(yǔ)句阶女,而是等到再調(diào)用迭代器的next()方法才會(huì)執(zhí)行下一個(gè)語(yǔ)句颊糜,即yield 2;.
使用yield關(guān)鍵字可以返回任何值和表達(dá)式,因?yàn)榭梢酝ㄟ^(guò)生成器函數(shù)批量給迭代器添加元素:

function *myIterator(list){
    for(let  i = 0; i< list.length ; i ++){
        yield list[i];
    }
}

var iterator = myIterator([1,2,3]);
iterator.next();  // "{done: false, value: 1}"
iterator.next();  // "{done: false, value: 2}"
iterator.next();  // "{done: false, value: 3}"
iterator.next();  // "{done: true, value: undefined}"
// 以后的調(diào)用都一樣
iterator.next();  // "{done: true, value: undefined}"

生成器的適用返回很廣秃踩,可以將它用于所有支持函數(shù)使用的地方衬鱼。

#4. 迭代器(詳細(xì)介紹)

#4.1 Iterator迭代器概念

Iterator是一種接口,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制憔杨。任何數(shù)據(jù)結(jié)構(gòu)只要部署 Iterator 接口鸟赫,就可以完成迭代操作(即依次處理該數(shù)據(jù)結(jié)構(gòu)的所有成員)。

Iterator三個(gè)作用

  • 為各種數(shù)據(jù)結(jié)構(gòu)消别,提供一個(gè)統(tǒng)一的抛蚤、簡(jiǎn)便的訪問(wèn)接口;
  • 使得數(shù)據(jù)結(jié)構(gòu)的成員能夠按某種次序排列寻狂;
  • Iterator 接口主要供ES6新增的for...of消費(fèi)岁经;

#4.2 Iterator迭代過(guò)程

  1. 創(chuàng)建一個(gè)指針對(duì)象,指向當(dāng)前數(shù)據(jù)結(jié)構(gòu)的起始位置蛇券。也就是說(shuō)缀壤,迭代器對(duì)象本質(zhì)上樊拓,就是一個(gè)指針對(duì)象。
  2. 第一次調(diào)用指針對(duì)象的next方法塘慕,可以將指針指向數(shù)據(jù)結(jié)構(gòu)的第一個(gè)成員筋夏。
  3. 第二次調(diào)用指針對(duì)象的next方法,指針就指向數(shù)據(jù)結(jié)構(gòu)的第二個(gè)成員苍糠。
  4. 不斷調(diào)用指針對(duì)象的next方法叁丧,直到它指向數(shù)據(jù)結(jié)構(gòu)的結(jié)束位置。

每一次調(diào)用next方法岳瞭,都會(huì)返回?cái)?shù)據(jù)結(jié)構(gòu)的當(dāng)前成員的信息。具體來(lái)說(shuō)蚊锹,就是返回一個(gè)包含valuedone兩個(gè)屬性的對(duì)象瞳筏。

  • value屬性是當(dāng)前成員的值;
  • done屬性是一個(gè)布爾值,表示迭代是否結(jié)束;

模擬next方法返回值:

let f = function (arr){
    var nextIndex = 0;
    return {
        next:function(){
            return nextIndex < arr.length ?
            {value: arr[nextIndex++], done: false}:
            {value: undefined, done: true}
        }
    }
}

let a = f(['a', 'b']);
a.next(); // { value: "a", done: false }
a.next(); // { value: "b", done: false }
a.next(); // { value: undefined, done: true }

#4.3 默認(rèn)Iterator接口

若數(shù)據(jù)可迭代牡昆,即一種數(shù)據(jù)部署了Iterator接口姚炕。
ES6中默認(rèn)的Iterator接口部署在數(shù)據(jù)結(jié)構(gòu)的Symbol.iterator屬性,即如果一個(gè)數(shù)據(jù)結(jié)構(gòu)具有Symbol.iterator屬性丢烘,就可以認(rèn)為是可迭代柱宦。
Symbol.iterator屬性本身是函數(shù),是當(dāng)前數(shù)據(jù)結(jié)構(gòu)默認(rèn)的迭代器生成函數(shù)播瞳。執(zhí)行這個(gè)函數(shù)掸刊,就會(huì)返回一個(gè)迭代器。至于屬性名Symbol.iterator赢乓,它是一個(gè)表達(dá)式忧侧,返回Symbol對(duì)象的iterator屬性,這是一個(gè)預(yù)定義好的牌芋、類型為 Symbol 的特殊值蚓炬,所以要放在方括號(hào)內(nèi)(參見(jiàn)《Symbol》一章)。

原生具有Iterator接口的數(shù)據(jù)結(jié)構(gòu)有

  • Array
  • Map
  • Set
  • String
  • TypedArray
  • 函數(shù)的 arguments 對(duì)象
  • NodeList 對(duì)象

#4.4 Iterator使用場(chǎng)景

  • (1)解構(gòu)賦值
    對(duì)數(shù)組和 Set 結(jié)構(gòu)進(jìn)行解構(gòu)賦值時(shí)躺屁,會(huì)默認(rèn)調(diào)用Symbol.iterator方法肯夏。
let a = new Set().add('a').add('b').add('c');
let [x, y] = a;       // x = 'a'  y = 'b'
let [a1, ...a2] = a;  // a1 = 'a' a2 = ['b','c']

  • (2)擴(kuò)展運(yùn)算符
    擴(kuò)展運(yùn)算符(...)也會(huì)調(diào)用默認(rèn)的 Iterator 接口。
let a = 'hello';
[...a];            //  ['h','e','l','l','o']

let a = ['b', 'c'];
['a', ...a, 'd'];  // ['a', 'b', 'c', 'd']

  • (2)yield*
    yield*后面跟的是一個(gè)可迭代的結(jié)構(gòu)犀暑,它會(huì)調(diào)用該結(jié)構(gòu)的迭代器接口驯击。
let a = function*(){
    yield 1;
    yield* [2,3,4];
    yield 5;
}

let b = a();
b.next() // { value: 1, done: false }
b.next() // { value: 2, done: false }
b.next() // { value: 3, done: false }
b.next() // { value: 4, done: false }
b.next() // { value: 5, done: false }
b.next() // { value: undefined, done: true }

  • (4)其他場(chǎng)合
    由于數(shù)組的迭代會(huì)調(diào)用迭代器接口,所以任何接受數(shù)組作為參數(shù)的場(chǎng)合母怜,其實(shí)都調(diào)用了迭代器接口余耽。下面是一些例子。

  • for...of

  • Array.from()

  • Map(), Set(), WeakMap(), WeakSet()(比如new Map([['a',1],['b',2]])

  • Promise.all()

  • Promise.race()

#4.5 for...of循環(huán)

只要數(shù)據(jù)結(jié)構(gòu)部署了Symbol.iterator屬性苹熏,即具有 iterator 接口碟贾,可以用for...of循環(huán)迭代它的成員币喧。也就是說(shuō),for...of循環(huán)內(nèi)部調(diào)用的是數(shù)據(jù)結(jié)構(gòu)的Symbol.iterato方法袱耽。
使用場(chǎng)景
for...of可以使用在數(shù)組杀餐,SetMap結(jié)構(gòu)類數(shù)組對(duì)象朱巨,Genetator對(duì)象字符串史翘。

  • 數(shù)組
    for...of循環(huán)可以代替數(shù)組實(shí)例的forEach方法。
let a = ['a', 'b', 'c'];
for (let k of a){console.log(k)}; // a b c

a.forEach((ele, index)=>{
    console.log(ele);    // a b c
    console.log(index);  // 0 1 2 
})

for...in對(duì)比冀续,for...in只能獲取對(duì)象鍵名琼讽,不能直接獲取鍵值,而for...of允許直接獲取鍵值洪唐。

let a = ['a', 'b', 'c'];
for (let k of a){console.log(k)};  // a b c
for (let k in a){console.log(k)};  // 0 1 2

  • Set和Map
    可以使用數(shù)組作為變量钻蹬,如for (let [k,v] of b){...}
let a = new Set(['a', 'b', 'c']);
for (let k of a){console.log(k)}; // a b c

let b = new Map();
b.set('name','leo');
b.set('age', 18);
b.set('aaa','bbb');
for (let [k,v] of b){console.log(k + ":" + v)};
// name:leo
// age:18
// aaa:bbb

  • 類數(shù)組對(duì)象
// 字符串
let a = 'hello';
for (let k of a ){console.log(k)}; // h e l l o

// DOM NodeList對(duì)象
let b = document.querySelectorAll('p');
for (let k of b ){
    k.classList.add('test');
}

// arguments對(duì)象
function f(){
    for (let k of arguments){
        console.log(k);
    }
}
f('a','b'); // a b

  • 對(duì)象
    普通對(duì)象不能直接使用for...of會(huì)報(bào)錯(cuò)凭需,要部署Iterator才能使用问欠。
let a = {a:'aa',b:'bb',c:'cc'};
for (let k in a){console.log(k)}; // a b c
for (let k of a){console>log(k)}; // TypeError

#4.6 跳出for...of

使用break來(lái)實(shí)現(xiàn)。

for (let k of a){
    if(k>100)
        break;
    console.log(k);
}

#5. 生成器(詳細(xì)介紹)

#5.1 基本概念

Generator生成器函數(shù)是一種異步編程解決方案粒蜈。
原理
執(zhí)行Genenrator函數(shù)會(huì)返回一個(gè)遍歷器對(duì)象顺献,依次遍歷Generator函數(shù)內(nèi)部的每一個(gè)狀態(tài)。
Generator函數(shù)是一個(gè)普通函數(shù)枯怖,有以下兩個(gè)特征:

  • function關(guān)鍵字與函數(shù)名之間有個(gè)星號(hào)注整;
  • 函數(shù)體內(nèi)使用yield表達(dá)式,定義不同狀態(tài)嫁怀;

通過(guò)調(diào)用next方法设捐,將指針移向下一個(gè)狀態(tài),直到遇到下一個(gè)yield表達(dá)式(或return語(yǔ)句)為止塘淑。簡(jiǎn)單理解萝招,Generator函數(shù)分段執(zhí)行,yield表達(dá)式是暫停執(zhí)行的標(biāo)記存捺,而next恢復(fù)執(zhí)行槐沼。

function * f (){
    yield 'hi';
    yield 'leo';
    return 'ending';
}
let a = f();
a.next();  // {value: 'hi', done : false}
a.next();  // {value: 'leo', done : false}
a.next();  // {value: 'ending', done : true}
a.next();  // {value: undefined, done : false}

#5.2 yield表達(dá)式

yield表達(dá)式是暫停標(biāo)志,遍歷器對(duì)象的next方法的運(yùn)行邏輯如下:

  1. 遇到yield就暫停執(zhí)行捌治,將這個(gè)yield后的表達(dá)式的值岗钩,作為返回對(duì)象的value屬性值。
  2. 下次調(diào)用next往下執(zhí)行肖油,直到遇到下一個(gè)yield兼吓。
  3. 直到函數(shù)結(jié)束或者return為止,并返回return語(yǔ)句后面表達(dá)式的值森枪,作為返回對(duì)象的value屬性值视搏。
  4. 如果該函數(shù)沒(méi)有return語(yǔ)句审孽,則返回對(duì)象的valueundefined

注意:

  • yield只能用在Generator函數(shù)里使用浑娜,其他地方使用會(huì)報(bào)錯(cuò)佑力。
// 錯(cuò)誤1
(function(){
    yiled 1;  // SyntaxError: Unexpected number
})()

// 錯(cuò)誤2  forEach參數(shù)是個(gè)普通函數(shù)
let a = [1, [[2, 3], 4], [5, 6]];
let f = function * (i){
    i.forEach(function(m){
        if(typeof m !== 'number'){
            yield * f (m);
        }else{
            yield m;
        }
    })
}
for (let k of f(a)){
    console.log(k)
}

  • yield表達(dá)式如果用于另一個(gè)表達(dá)式之中,必須放在圓括號(hào)內(nèi)筋遭。
function * a (){
    console.log('a' + yield);     //  SyntaxErro
    console.log('a' + yield 123); //  SyntaxErro
    console.log('a' + (yield));     //  ok
    console.log('a' + (yield 123)); //  ok
}

  • yield表達(dá)式用做函數(shù)參數(shù)或放在表達(dá)式右邊打颤,可以不加括號(hào)
function * a (){
    f(yield 'a', yield 'b');    //  ok
    lei i = yield;              //  ok
}

#5.3 next方法

yield本身沒(méi)有返回值漓滔,或者是總返回undefined编饺,next方法可帶一個(gè)參數(shù),作為上一個(gè)yield表達(dá)式的返回值次和。

function * f (){
    for (let k = 0; true; k++){
        let a = yield k;
        if(a){k = -1};
    }
}
let g =f();
g.next();    // {value: 0, done: false}
g.next();    // {value: 1, done: false}
g.next(true);    // {value: 0, done: false}

這一特點(diǎn)反肋,可以讓Generator函數(shù)開(kāi)始執(zhí)行之后,可以從外部向內(nèi)部注入不同值踏施,從而調(diào)整函數(shù)行為。

function * f(x){
    let y = 2 * (yield (x+1));
    let z = yield (y/3);
    return (x + y + z);
}
let a = f(5);
a.next();   // {value : 6 ,done : false}
a.next();   // {value : NaN ,done : false}  
a.next();   // {value : NaN ,done : true}
// NaN因?yàn)閥eild返回的是對(duì)象 和數(shù)字計(jì)算會(huì)NaN

let b = f(5);
b.next();     // {value : 6 ,done : false}
b.next(12);   // {value : 8 ,done : false}
b.next(13);   // {value : 42 ,done : false}
// x 5 y 24 z 13

#5.4 for...of循環(huán)

for...of循環(huán)會(huì)自動(dòng)遍歷罕邀,不用調(diào)用next方法畅形,需要注意的是,for...of遇到next返回值的done屬性為true就會(huì)終止诉探,return返回的不包括在for...of循環(huán)中日熬。

function * f(){
    yield 1;
    yield 2;
    yield 3;
    yield 4;
    return 5;
}
for (let k of f()){
    console.log(k);
}
// 1 2 3 4  沒(méi)有 5 

#5.5 Generator.prototype.throw()

throw方法用來(lái)向函數(shù)外拋出錯(cuò)誤,并且在Generator函數(shù)體內(nèi)捕獲肾胯。

let f = function * (){
    try { yield }
    catch (e) { console.log('內(nèi)部捕獲', e) }
}

let a = f();
a.next();

try{
    a.throw('a');
    a.throw('b');
}catch(e){
    console.log('外部捕獲',e);
}
// 內(nèi)部捕獲 a
// 外部捕獲 b

#5.6 Generator.prototype.return()

return方法用來(lái)返回給定的值竖席,并結(jié)束遍歷Generator函數(shù),如果return方法沒(méi)有參數(shù)敬肚,則返回值的value屬性為undefined毕荐。

function * f(){
    yield 1;
    yield 2;
    yield 3;
}
let g = f();
g.next();          // {value : 1, done : false}
g.return('leo');   // {value : 'leo', done " true}
g.next();          // {value : undefined, done : true}

#5.7 next()/throw()/return()共同點(diǎn)

相同點(diǎn)就是都是用來(lái)恢復(fù)Generator函數(shù)的執(zhí)行,并且使用不同語(yǔ)句替換yield表達(dá)式艳馒。

  • next()yield表達(dá)式替換成一個(gè)值憎亚。
let f = function * (x,y){
    let r = yield x + y;
    return r;
}
let g = f(1, 2); 
g.next();   // {value : 3, done : false}
g.next(1);  // {value : 1, done : true}
// 相當(dāng)于把 let r = yield x + y;
// 替換成 let r = 1;

  • throw()yield表達(dá)式替換成一個(gè)throw語(yǔ)句。
g.throw(new Error('報(bào)錯(cuò)'));  // Uncaught Error:報(bào)錯(cuò)
// 相當(dāng)于將 let r = yield x + y
// 替換成 let r = throw(new Error('報(bào)錯(cuò)'));

  • next()yield表達(dá)式替換成一個(gè)return語(yǔ)句弄慰。
g.return(2); // {value: 2, done: true}
// 相當(dāng)于將 let r = yield x + y
// 替換成 let r = return 2;

#5.8 yield* 表達(dá)式

用于在一個(gè)Generator中執(zhí)行另一個(gè)Generator函數(shù)第美,如果沒(méi)有使用yield*會(huì)沒(méi)有效果。

function * a(){
    yield 1;
    yield 2;
}
function * b(){
    yield 3;
    yield * a();
    yield 4;
}
// 等同于
function * b(){
    yield 3;
    yield 1;
    yield 2;
    yield 4;
}
for(let k of b()){console.log(k)}
// 3
// 1
// 2
// 4

#5.9 應(yīng)用場(chǎng)景

  1. 控制流管理
    解決回調(diào)地獄:
// 使用前
f1(function(v1){
    f2(function(v2){
        f3(function(v3){
            // ... more and more
        })
    })
})

// 使用Promise 
Promise.resolve(f1)
    .then(f2)
    .then(f3)
    .then(function(v4){
        // ...
    },function (err){
        // ...
    }).done();

// 使用Generator
function * f (v1){
    try{
        let v2 = yield f1(v1);
        let v3 = yield f1(v2);
        let v4 = yield f1(v3);
        // ...
    }catch(err){
        // console.log(err)
    }
}
function g (task){
    let obj = task.next(task.value);
  // 如果Generator函數(shù)未結(jié)束陆爽,就繼續(xù)調(diào)用
  if(!obj.done){
      task.value = obj.value;
      g(task);
  }
}
g( f(initValue) );

  1. 異步編程的使用 在真實(shí)的異步任務(wù)封裝的情況:
let fetch = require('node-fetch');
function * f(){
    let url = 'http://www.baidu.com';
    let res = yield fetch(url);
    console.log(res.bio);
}
// 執(zhí)行該函數(shù)
let g = f();
let result = g.next();
// 由于fetch返回的是Promise對(duì)象什往,所以用then
result.value.then(function(data){
    return data.json();
}).then(function(data){
    g.next(data);
})

#參考資料

1.MDN 迭代器和生成器
2.ES6中的迭代器(Iterator)和生成器(Generator)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市慌闭,隨后出現(xiàn)的幾起案子别威,更是在濱河造成了極大的恐慌躯舔,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件兔港,死亡現(xiàn)場(chǎng)離奇詭異庸毫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衫樊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門飒赃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人科侈,你說(shuō)我怎么就攤上這事载佳。” “怎么了臀栈?”我有些...
    開(kāi)封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵蔫慧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我权薯,道長(zhǎng)姑躲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任盟蚣,我火速辦了婚禮黍析,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘屎开。我一直安慰自己阐枣,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布奄抽。 她就那樣靜靜地躺著蔼两,像睡著了一般。 火紅的嫁衣襯著肌膚如雪逞度。 梳的紋絲不亂的頭發(fā)上额划,一...
    開(kāi)封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音第晰,去河邊找鬼锁孟。 笑死,一個(gè)胖子當(dāng)著我的面吹牛茁瘦,可吹牛的內(nèi)容都是我干的品抽。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼甜熔,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼圆恤!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤盆昙,失蹤者是張志新(化名)和其女友劉穎羽历,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體淡喜,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡秕磷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了炼团。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澎嚣。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖瘟芝,靈堂內(nèi)的尸體忽然破棺而出易桃,到底是詐尸還是另有隱情,我是刑警寧澤锌俱,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布晤郑,位于F島的核電站,受9級(jí)特大地震影響贸宏,放射性物質(zhì)發(fā)生泄漏造寝。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一吭练、第九天 我趴在偏房一處隱蔽的房頂上張望匹舞。 院中可真熱鬧,春花似錦线脚、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至晰绎,卻和暖如春寓落,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荞下。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工伶选, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人尖昏。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓仰税,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親抽诉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陨簇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,029評(píng)論 0 2
  • 一、Iterator(遍歷器)的概念 Iterator 是一種接口迹淌,為各種不同的數(shù)據(jù)結(jié)構(gòu)提供統(tǒng)一的訪問(wèn)機(jī)制河绽。 任何...
    magic_pill閱讀 314評(píng)論 0 1
  • 你不知道JS:異步 第四章:生成器(Generators) 在第二章己单,我們明確了采用回調(diào)表示異步流的兩個(gè)關(guān)鍵缺點(diǎn):...
    purple_force閱讀 957評(píng)論 0 2
  • pyspark.sql模塊 模塊上下文 Spark SQL和DataFrames的重要類: pyspark.sql...
    mpro閱讀 9,451評(píng)論 0 13
  • 本文作者就是我,簡(jiǎn)書的microkof耙饰。如果您覺(jué)得本文對(duì)您的工作有意義纹笼,產(chǎn)生了不可估量的價(jià)值,那么請(qǐng)您不吝打賞我苟跪,...
    microkof閱讀 23,730評(píng)論 16 78