函數(shù)式編程——學(xué)習(xí)筆記

函數(shù)式編程中的函數(shù)指的不是程序中的函數(shù)方法乍丈,而是數(shù)學(xué)中的函數(shù)即映射關(guān)系剂碴,是對(duì)運(yùn)算過(guò)程的抽象,是用來(lái)描述數(shù)據(jù)之間的映射

// 非函數(shù)式
let a = 1, b = 2, c = a + b;
console.log(c)

// 函數(shù)式
const aa = (a, b) => {
    return a + b
}
let c = aa(1, 2)
console.log(c)

函數(shù)式編程語(yǔ)言的特性

函數(shù)是一等公民

  1. 函數(shù)可以存儲(chǔ)在變量中
  2. 函數(shù)可以作為參數(shù)
  3. 函數(shù)可以作為返回值

高階函數(shù)

什么是高階函數(shù)轻专?
  1. 函數(shù)可以作為參數(shù)傳遞給另一個(gè)函數(shù)
  2. 函數(shù)可以作為另一個(gè)函數(shù)的返回結(jié)果
函數(shù)作為參數(shù)
// 模擬forEach,打印數(shù)組中的每一項(xiàng)
const forEach = (arr, fn) => {
    for (let i = 0; i < arr.length; i++) {
        fn(arr[i])
    }
}
let c = [1, 2, 3, 4, 5];
forEach(arr, (item) => {
    console.log(item)
})

// 模擬filter,把滿足條件的每一項(xiàng)存儲(chǔ)下來(lái)并返回
const filter = (arr, fn) => {
    let result = [];
    for (let i = 0; i < arr.length; i++) {
        if (fn(arr[i])) {
            result.push(arr[i])
        }
    }
    return result
}

// 測(cè)試
let arr = [1, 2, 4, 7, 8];
filter(arr, (item) => {
    return item % 2 === 0
})
函數(shù)作為返回值
const makeFn = () => {
    let msg = 'hello function';
    return () => {
        console.log(msg)
    }
}
makeFn()();

// 模擬lodash中的once,只執(zhí)行一次
const once = (fn) => {
    let done = false;
    return function () {
        if (!done) {
            done = true;
            return fn.apply(this, arguments);
        }
    }
}

let pay = once((money) => {
    console.log('gg', money)
    console.log(`支付了${money}RMB`)
});

pay(9);

使用高階函數(shù)的意義

高階函數(shù)是用來(lái)抽象通用問(wèn)題忆矛,抽象可以幫我們屏蔽細(xì)節(jié),我們只用關(guān)注實(shí)現(xiàn)的目標(biāo)

// 模擬常用的高階函數(shù):map请垛、every催训、some
// map 遍歷數(shù)組中的每一項(xiàng),將滿足條件的項(xiàng)存入新的數(shù)組并返回
const map = (array, fn) => {
    let result = [];
    for (let value of array) {
        result.push(fn(value))
    }
    return result
}

// 測(cè)試
console.log(map([1, 2, 3, 4], v => v * v))

// every 檢測(cè)數(shù)組所有元素是否都符合指定條件洽议,有一項(xiàng)不滿足條件就返回false,剩余的元素不會(huì)再進(jìn)行檢測(cè)漫拭。
const every = (array, fn) => {
    let result = true;
    for (let value of array) {
        if (!fn(value)) {
            result = false;
            break;
        }
    }
    return result
}
// 測(cè)試
console.log(every([5, 7, 6,], v => v > 10));

// some 檢測(cè)數(shù)組中的元素是否滿足指定條件绞铃,如果有一個(gè)元素滿足指定條件就返回true,剩余的元素不會(huì)再繼續(xù)檢測(cè)。
const some = (array, fn) => {
    let result = true;
    for (let value of array) {
        if (fn(value)) {
            result = true;
        }
    }
    return result
}
// 測(cè)試
console.log(some([5, 8, 9, 3], (v) => v > 2));

閉包

含義:

  1. 函數(shù)和其周圍的狀態(tài)(語(yǔ)法環(huán)境)的引用捆綁在一起形成閉包嫂侍。

  2. 可以在另一個(gè)作用域中調(diào)用一個(gè)函數(shù)的內(nèi)部函數(shù)并訪問(wèn)到該函數(shù)的作用域中的成員

本質(zhì):函數(shù)在執(zhí)行的時(shí)候會(huì)放到一個(gè)執(zhí)行棧上儿捧,當(dāng)函數(shù)執(zhí)行完畢會(huì)從執(zhí)行棧上移除,但是堆上的作用于成員因?yàn)楸煌獠恳貌荒茚尫盘舫瑁虼藘?nèi)部函數(shù)依然可以訪問(wèn)外部函數(shù)的成員菲盾。

function makePower(power) {
   return function (number) {
       return Math.pow(number, power)
   }
}

// 求平方
let power2 = makePower(2);
// 求立方
let power3 = makePower(3);

console.log(power2(2))
console.log(power2(3))
console.log(power3(4))

純函數(shù)

純函數(shù)的概念

相同的輸入永遠(yuǎn)會(huì)得到相同的輸出,而且沒(méi)有任何可觀察的副作用

  1. 純函數(shù)就類似數(shù)學(xué)中的函數(shù)各淀,用來(lái)描述輸入和輸出的關(guān)系

  2. lodash是一個(gè)純函數(shù)的功能庫(kù)懒鉴,提供了對(duì)數(shù)組,數(shù)字碎浇,對(duì)象临谱,字符串,函數(shù)等操作方法

  3. 數(shù)組的slice和splic分別是純函數(shù)和不純的函數(shù)

    slice返回?cái)?shù)組中的指定部分奴璃,不會(huì)改變?cè)瓟?shù)組

    splice對(duì)數(shù)組進(jìn)行操作返回該數(shù)組悉默,會(huì)改變?cè)瓟?shù)組

let numbers = [1, 2, 3, 4, 5] 
//純函數(shù) 
numbers.slice(0, 3) // => [1, 2, 3] 
numbers.slice(0, 3) // => [1, 2, 3] 
numbers.slice(0, 3) // => [1, 2, 3] 
    
// 不純的函數(shù) 
numbers.splice(0, 3) // => [1, 2, 3] 
numbers.splice(0, 3) // => [4, 5] 
numbers.splice(0, 3) // => []

純函數(shù)代表:lodash

純函數(shù)的好處:

1、可緩存苟穆,因?yàn)榧兒瘜?duì)于相同輸入始終具有相同輸出抄课,所以可以把純函數(shù)的結(jié)果緩存起來(lái)

2、可測(cè)試雳旅,純函數(shù)讓測(cè)試更方便

3跟磨、并行處理,在多線程環(huán)境下并行操作共享的內(nèi)存數(shù)據(jù)很有可能出現(xiàn)意外的情況攒盈;純函數(shù)只依賴參數(shù)抵拘,不需要訪問(wèn)共享的內(nèi)存數(shù)據(jù),所以在并行環(huán)境下可以任意運(yùn)行純函數(shù)(web worker)

函數(shù)的副作用:

// 不純的 
let mini = 18
function checkAge(age) {
    return age >= mini
}
// 純的(有硬編碼型豁,后續(xù)可以通過(guò)柯里化解決) 
function checkAge(age) {
    let mini = 18
    return age >= mini
}

副作用讓一個(gè)純函數(shù)變的不純僵蛛,如上例,純函數(shù)根據(jù)相同的輸入返回相同的輸出偷遗,如果函數(shù)依賴于外部的狀態(tài)就無(wú)法保證輸出相同墩瞳,就會(huì)帶來(lái)副作用

副作用的來(lái)源:配置文件驼壶、數(shù)據(jù)庫(kù)氏豌、獲取用戶的輸入...

所有的外部交互都有可能帶來(lái)副作用,副作用也使得方法通用性下降不適合擴(kuò)展和重用性热凹,同時(shí)副作用會(huì)給程序帶來(lái)安全隱患給程序帶來(lái)不確定性泵喘,但是副作用不可能完全禁止泪电,盡可能控制它們?cè)诳煽胤秶鷥?nèi)發(fā)生。

柯里化

當(dāng)一個(gè)函數(shù)有多個(gè)參數(shù)的時(shí)候先傳遞一部分參數(shù)調(diào)用它(這部分參數(shù)以后永遠(yuǎn)不變)纪铺,然后返回一個(gè)新的函數(shù)接收剩余的參數(shù)相速,返回結(jié)果

lodash中的柯里化

// 柯里化案例
''.match(/\s+/g);// 提取字符串中的空白字符
''.match(/\d+/g);// 提取字符串中的數(shù)字
const _ = require('lodash');

const match = _.curry((reg, str) => str.match(reg));

const haveSpace = match(/\s+/g);
const haveNumber = match(/\d+/g);

// console.log(haveSpace('hello  word'))
// console.log(haveNumber('333adg'))

// 操作數(shù)組

const filter = _.curry((func, array) => array.filter(func))

// 獲取數(shù)組中具有空白字符的元素
const findSpace = filter(haveSpace);

console.log(findSpace(['fsf,vvv ,kkk  l']));

柯里化實(shí)現(xiàn)原理


// 模擬柯里化實(shí)現(xiàn)原理

const getSum = (a, b, c) => a + b + c;

// 模擬lodash中curry方法
const curry = (func) => {
    return function curriedFn(...args) {
        // 判斷形參和實(shí)參的個(gè)數(shù)
        if (args.length < func.length) {
            return function () {
                return curriedFn(...args.concat(Array.from(arguments)))
            }
        }
        return func(...args)
    }
}
const curried = curry(getSum);
console.log(curried(1)(2, 3)); // 6
console.log(curried(1, 2)(3));// 6
console.log(curried(1, 2, 3));// 6
總結(jié)

柯里化可以讓我們給一個(gè)函數(shù)傳遞較少的參數(shù)得到一個(gè)已經(jīng)記住啦某些固定參數(shù)的新函數(shù)

這是一種對(duì)函數(shù)參數(shù)的緩存

讓函數(shù)變得更靈活,讓函數(shù)的粒度更小

可以把多元函數(shù)轉(zhuǎn)成一元函數(shù)鲜锚,可以組合使用函數(shù)產(chǎn)生強(qiáng)大的功能

函數(shù)組合

如果一個(gè)函數(shù)需要經(jīng)過(guò)多個(gè)函數(shù)處理才能得到最終只突诬,這個(gè)時(shí)候可以把中間過(guò)程的函數(shù)組合成一個(gè)函數(shù)

// 函數(shù)組合
const compose = (f, g) => {
    return function (value) {
        return f(g(value))
    }
}

// 反轉(zhuǎn)數(shù)組
const reverse = (array) => {
    return array.reverse()
}
// 獲取數(shù)組的第一個(gè)元素
const first = (array) => {
    return array[0]
}

const last = compose(first, reverse);

console.log(last([1, 2, 3, 4, 5, 6,]));

lodash中的組合函數(shù)

// 模擬lodash中的flowRight
// const _ = require('lodash');
const reverse = arr => arr.reverse();
const first = arr => arr[0];
const toUpper = s => s.toUpperCase();

// const compose = (...args) => {
//     return (value) => {
//         return args.reverse().reduce((acc, fn) => {
//             return fn(acc)
//         }, value)
//     }
// }
// ES6
const compose = (...args) => value => args.reverse().reduce((acc, fn) => fn(acc), value)

const f = compose(toUpper, first, reverse);
console.log(f(['one', 'two', 'three']));

函數(shù)結(jié)合律

// 函數(shù)結(jié)合需要滿足結(jié)合律
const _ = require('lodash');

const f = _.flowRight(_.toUpper, flowRight(_.first, _.reverse));
console.log(f(['one', 'two', 'three']));

函數(shù)組合調(diào)試

// 函數(shù)結(jié)合 調(diào)試
// NEVER SAY DIE --->never-say-die
const _ = require('lodash');

const trace = _.curry((tag, v) => {
    console.log(tag, v)
    return v
})

const split = _.curry((sep, str) => _.split(str, sep))

const join = _.curry((sep, array) => _.join(array, sep))
const map = _.curry((fn, array) => _.map(array, fn));

const f = _.flowRight(join('-'), trace('map之后'), map(_.toLower),trace('split之后'), split(' '));


console.log(f('NEVER SAY DIE'))

lodash模塊數(shù)據(jù)優(yōu)先,函數(shù)置后

lodash/fp模塊函數(shù)優(yōu)先芜繁,數(shù)據(jù)置后

// lodash和lodash/fp模塊中map方法的區(qū)別
const _ = require('lodash');
console.log(_map(["23", "8", "10"]), parseInt);
// parseInt("23",0,array)
// parseInt("8",1,array)
// parseInt("10",2,array)

const fp = require('lodash/fp');
console.log(fp.map(parseInt, ["23", "8", "10"]))

PointFree

我們可以把數(shù)據(jù)處理的過(guò)程定義成與數(shù)據(jù)無(wú)關(guān)的合成運(yùn)算旺隙,不需要用到代表數(shù)據(jù)的那個(gè)參
數(shù),只要把簡(jiǎn)單的運(yùn)算步驟合成到一起骏令,在使用這種模式之前我們需要定義一些輔助的基本運(yùn)算函數(shù)蔬捷。

1、不需要指明處理的數(shù)據(jù)

2榔袋、只需要合并運(yùn)算過(guò)程

3周拐、需要定義一些輔助的基本運(yùn)算函數(shù)

const f = fp.flowRight(fp.join('-'), trace('map之后'), fp.map(fp.toLower), trace('split之后'), fp.split(' '));

案例

// 非pointFree模式
// const f = (word) => word.toLowerCase().replace(/\s+/g, '_');

// pointFree模式
const fp = require('lodash/fp')
const f = fp.flowRight(fp.replace(/\s+/g, "_"), fp.toLower);
console.log(f('hello   word'))
//把一個(gè)字符串的首字符提取并轉(zhuǎn)換成大寫(xiě),使用. 作為分隔符
// word wild web ==>W. W. W

// pointFree模式
const fp = require('lodash/fp')
const firstLetterToUpper = fp.flowRight(fp.join('. '),fp.map(fp.flowRight(fp.first,fp.toUpper)),fp.split(' '))

console.log(firstLetterToUpper('word wild web'))

函子

函子的概念

函子是函數(shù)式編程里面最重要的數(shù)據(jù)類型凰兑,也是基本的運(yùn)算單位和功能單位妥粟。

函子首先是一個(gè)容器,它包含了值和值的變形關(guān)系吏够,這個(gè)變形關(guān)系就是函數(shù)罕容。

函子可以把函數(shù)式編程副作用控制在可控的范圍內(nèi),包括處理異常稿饰,異步操作等锦秒。
一般約定,函子的標(biāo)志就是容器具有map方法喉镰。該方法將容器里面的每一個(gè)值旅择,映射到另一個(gè)容器。

函子的基本構(gòu)造

函子就是一個(gè)特殊的容器侣姆,它可以由對(duì)象來(lái)實(shí)現(xiàn)生真,這個(gè)對(duì)象中包含了值,這個(gè)值永遠(yuǎn)不會(huì)對(duì)外公布捺宗,有一個(gè)map方法柱蟀,用來(lái)操作這個(gè)值。還有一個(gè)of方法蚜厉,用來(lái)生成一個(gè)新的容器长已。

// Functor
class Container {
    static of(value) {
        return new Container(value)
    }
    constructor(value) {
        this._value = value;
    }
    map(fn) {
        return Container.of((fn(this._value)))
    }
}
let r = Container.of(5).map(x => x + 1).map(x => x * x);
console.log('r', r);

這里總結(jié)一下函子的使用

  • 程序運(yùn)算不會(huì)直接操作值,而是通過(guò)函子來(lái)完成
  • 由map處理后返回的是一個(gè)新的對(duì)象,我們可以繼續(xù)鏈?zhǔn)降牟僮髦?/li>
  • 我們可以把函子想象成一個(gè)盒子术瓮,盒子中封裝著一個(gè)值康聂,當(dāng)我恩處理盒子中的值的時(shí)候我們要用到盒子專門(mén)改變值的工具:map,我們需要給盒子的map方法傳遞一個(gè)處理值的函數(shù)(純函數(shù))胞四,由這個(gè)函數(shù)來(lái)對(duì)值進(jìn)行處理恬汁,最終map方法返回一個(gè)包含新值的盒子(函子)。

MayBe函子

函子會(huì)接收各種函數(shù)來(lái)處理內(nèi)部的值辜伟,這里就有可能遇到錯(cuò)誤氓侧,我們需要對(duì)這些錯(cuò)誤做處理,MayBe函子的作用就是對(duì)外部的空值情況做處理导狡。

MayBe函子的構(gòu)造就是在map中設(shè)置空值檢查

class Maybe{
   static of(value){
     return new Maybe(value)
   }

   constructor(val){
     this._value = val
   }
   map(f) {
     return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
   }
 }

雖然 MayBe函子可以避免出現(xiàn)錯(cuò)誤甘苍,但是多次調(diào)用map時(shí)我們并不知道哪里出現(xiàn)了錯(cuò)誤

Either函子

Either函子與if...else處理很相似。它內(nèi)部有兩個(gè)值烘豌,左值和右值载庭。右值通常代表正常的值,左值是當(dāng)右值不存在或錯(cuò)誤時(shí)的默認(rèn)值

class Either {
     static of(left,right){
      return new Either (left,right))
    }
    constructor(left,right){
      this.left = left
      this.right = right
    }
    map(fn){
      return this.right ? Either.of(this.left,fn(this.right)) : Either.of(fn(this.left),right)
    }
  }

此外廊佩,Either函子另一個(gè)用途是替代try...catch囚聚,使用左值來(lái)表示錯(cuò)誤

 function parseJSON(json) {
  try {
    return Either.of(null, JSON.parse(json));
  } catch (e: Error) {
    return Either.of(e, null);
  }
}

ap函子

函子中的值有可能是數(shù)值,也有可能是一個(gè)函數(shù)标锄,我們想讓值為函數(shù)的函子用另一個(gè)函子中的值運(yùn)算顽铸,我們就可以用ap函子

 function add(x) {
    return x + 1
  }
  const A = Functor.of(2)
  const B = Functor.of(add)

  class Ap extends Functor {
    ap(F) {
      return Ap.of(this.val(F.val))
    }
  }
 //我們想讓B函子的值使用A函子的值
  Ap.of(add).ap(Functor.of(2))

凡是部署了ap方法的函子,就是ap函子料皇。ap函子的意義在于對(duì)多參數(shù)的函數(shù)谓松,可以從多個(gè)容器中取值,實(shí)現(xiàn)函子的鏈?zhǔn)秸{(diào)用践剂。

Monad 函子

函子中的值可以接受任何值鬼譬,所以函子之中可以包含另一個(gè)函子。這樣就會(huì)造成函子多層嵌套的問(wèn)題逊脯。取值時(shí)會(huì)很不方便优质。Monad函子的作用就是:總是返回一個(gè)單層的函子交排,它有一個(gè)FlatMap方法纠脾,與map方法作用相同,唯一的區(qū)別就是如果生成了一個(gè)嵌套函子大诸,它會(huì)取出后者的值匕争,保證返回的永遠(yuǎn)是一個(gè)單層的容器避乏,不會(huì)出現(xiàn)嵌套的情況。

 class Monad extends Functor {
    join() {
      return this.val;
    }
    flatMap(f) {//f是一個(gè)函子
      return this.map(f).join();
    }
  }

如果函數(shù)f返回的是一個(gè)函子甘桑,那么this.map(f)就會(huì)生成一個(gè)嵌套的函子拍皮。所以歹叮,join方法保證了flatMap方法總是返回一個(gè)單層的函子。這意味著嵌套的函子會(huì)被鋪平春缕。

IO函子

I/O是一個(gè)不純的操作盗胀,普通的函數(shù)式編程無(wú)法處理,所以使用IO函子操作

const fp = require('lodash/fp')
class IO {
    static of (value) {
        return new IO (function () {
            return value
        })
    }

    constructor(fn) {
        this._value = fn
    }

    map (fn){
        return new IO (fp.flowRight(fn,this._value));
    }
}
  • IO函子中的_value是一個(gè)一個(gè)函數(shù)艘蹋,這里是把函數(shù)作為值來(lái)處理
  • IO函子可以把不純的動(dòng)作存儲(chǔ)到_value中锄贼,延遲這個(gè)不純的操作(惰性執(zhí)行),包裝當(dāng)前的操作是純的操作
  • 把不純的操作交給調(diào)用者來(lái)處理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市女阀,隨后出現(xiàn)的幾起案子宅荤,更是在濱河造成了極大的恐慌,老刑警劉巖浸策,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冯键,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡庸汗,警方通過(guò)查閱死者的電腦和手機(jī)惫确,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)蚯舱,“玉大人改化,你說(shuō)我怎么就攤上這事⊥骰瑁” “怎么了陈肛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)兄裂。 經(jīng)常有香客問(wèn)我句旱,道長(zhǎng),這世上最難降的妖魔是什么晰奖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任谈撒,我火速辦了婚禮,結(jié)果婚禮上匾南,老公的妹妹穿的比我還像新娘港华。我一直安慰自己,他們只是感情好午衰,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布立宜。 她就那樣靜靜地躺著,像睡著了一般臊岸。 火紅的嫁衣襯著肌膚如雪橙数。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 50,043評(píng)論 1 291
  • 那天帅戒,我揣著相機(jī)與錄音灯帮,去河邊找鬼崖技。 笑死,一個(gè)胖子當(dāng)著我的面吹牛钟哥,可吹牛的內(nèi)容都是我干的迎献。 我是一名探鬼主播,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼腻贰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吁恍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起播演,我...
    開(kāi)封第一講書(shū)人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤冀瓦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后写烤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體翼闽,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年洲炊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了感局。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡暂衡,死狀恐怖询微,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情古徒,我是刑警寧澤拓提,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站隧膘,受9級(jí)特大地震影響代态,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疹吃,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一蹦疑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧萨驶,春花似錦歉摧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至核畴,卻和暖如春膝但,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背谤草。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工跟束, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留莺奸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓冀宴,卻偏偏與公主長(zhǎng)得像灭贷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子略贮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351