函數(shù)式編程

作者:酸菜牛肉 文章內(nèi)容輸出來源:拉勾教育大前端高薪訓(xùn)練營課程

函數(shù)式編程概念:

函數(shù)式編程是一種編程范式沐旨;還有面向?qū)ο缶幊唐椋兔嫦蜻^程編程

  • 面向?qū)ο缶幊痰乃季S方式:把現(xiàn)實世界中的事物抽象成程序世界中的類和對象,通過封裝枫疆、繼承和多態(tài)來演示事物事件的聯(lián)系
  • 面向?qū)ο缶幊痰乃季S方式:把現(xiàn)實世界的事物和事物之間的聯(lián)系抽象到程序世界(對運算過程進行抽象)
  1. 程序的本質(zhì): 根據(jù)輸入通過某種運算獲得相應(yīng)輸出吗讶,程序開發(fā)過程中會涉及很多有輸入和輸出的函數(shù)
  2. x -> f(聯(lián)系躺率、映射)-> y, y=f(x)
  3. 函數(shù)式編程中的函數(shù)指的不是程序中的函數(shù)(方法),而是數(shù)學(xué)中的函數(shù)即映射關(guān)系棵逊,例如:y = sin(x), x和y的關(guān)系
  4. 相同的輸入始終要得到相同的輸出(純函數(shù))
  5. 函數(shù)式編程用來描述數(shù)據(jù)(函數(shù))之間的映射
前置知識:
  • 函數(shù)是一等公民
  • 高階函數(shù)
  • 閉包
函數(shù)是一等公民
  • 函數(shù)可以存儲在變量中
  • 函數(shù)作為參數(shù)
  • 函數(shù)作為返回值
//把函數(shù)賦值給變量
let fn = function() {
  console.log('hello world')
}
fn()

const BlogController = {
  index(posts){return Views.index(posts) } // 函數(shù)的調(diào)用相同伤疙,可以將后邊函數(shù)本身賦值給變量,(而不是函數(shù)的調(diào)用)
}
// 優(yōu)化
const BlogController = {
  index: Views.index
}
高階函數(shù)
  • 可以把函數(shù)作為參數(shù)傳遞給兩一個函數(shù)
  • 可以把函數(shù)作為另一個函數(shù)的返回結(jié)果
//函數(shù)作為參數(shù)
const filter = (array, fn) => {
  let results = []
  for(let i =0; i< array.length; i++){
    if(fn(array[i]){
      results.push(array[i])
    }
  }
  return results
}
let arr = [1, 3, 4, 7, 8]
const a = filter(arr, (item)=>{
   return item % 2 === 0
})

//函數(shù)作為函數(shù)返回值 
const makeFn = () => {
  let msg = 'hello function'
  return function(){
   console.log(msg);  
 }
}
makeFn()()
//once
const once = (fn) => {
  let done  = false
  return function(){
    if(!done){
      done = true
      return fn.apply(this, arguments)
    }
  }
}

let pay = once(function(money)=>{
  consle.log(`支付:${money}RMB`)
})
pay(5)
pay(5)
pay(5)
pay(5)
使用高階函數(shù)的意義
  • 抽象可以幫我們屏蔽細(xì)節(jié), 只需要關(guān)注與我們的目標(biāo)
  • 高階函數(shù)是用來抽象通用的問題
常用高階函數(shù)
  • forEach
  • map
  • filter
  • every
  • some
  • find/findIndex
  • reduce
  • sort
  • ...
const map = (array, fn) => {
    let result = []
    for (let value of array) {
        result.push(fn(value))
    }
    return result
 } 
const every = (array, fn) => {
    let result = true
    for (let value of array) {
        result = fn(value)
        if(!result){
            break
        }
    }
    return result
}

const some = (array, fn) => {
    let result = false
    for (let value of array) {
        result = fn(value)
        if(result){
            break
        }
    }
    return result
}


let arr = [1, 2, 3, 4]
// arr = map(arr, v => v * v)
// a = every(arr, v => v > 0)
b = some(arr, v => v > 3)
console.log(b)
閉包

閉包: 函數(shù)和其周圍的狀態(tài)(詞法環(huán)境)的引用捆綁在一起形成閉包
可以在另一個作用域中調(diào)用一個函數(shù)的內(nèi)部函數(shù)并訪問到該函數(shù)的作用域中的成員

//閉包徒像;
//once

function once (fn) {
    let done = false   //此變量的作用范圍被延長黍特,用來標(biāo)記此函數(shù)是否被執(zhí)行
    return function () {
        if(!done){
            done = true
            return fn.apply(this, arguments)
        }
    }
}

let pay = once(function(money){
    console.log(`支付: ${money} RMB`)
})

pay(5)
// pay(5)
// pay(5)

閉包的本質(zhì):函數(shù)在執(zhí)行的時候會放在一個執(zhí)行棧上,當(dāng)函數(shù)執(zhí)行完畢之后會從執(zhí)行棧上移除锯蛀,但是堆上的作用域成員因為被外部引用不能被釋放灭衷,因此內(nèi)部函數(shù)依然可以訪問外部函數(shù)的成員。

純函數(shù)

純函數(shù)的定義是:

  • 如果函數(shù)的調(diào)用參數(shù)相同旁涤,則永遠(yuǎn)返回相同的結(jié)果翔曲,而且沒有可觀察的副作用
  • lodash是一個純函數(shù)的功能庫,提供了對數(shù)組劈愚、數(shù)字瞳遍、對象、字符串菌羽、函數(shù)等操作的一些方法
  • 數(shù)組中的slice和splice分別為: 純函數(shù)和不純函數(shù)掠械; slice 返回數(shù)組指定部分,不會改變原數(shù)組注祖; splice 對數(shù)組進行操作返回該數(shù)組猾蒂,會改變原數(shù)組
  • 函數(shù)式編程不會保留計算中間的結(jié)果,所以變量是不可變的(無狀態(tài)的)
  • 我們可以把一個函數(shù)的執(zhí)行結(jié)果交給兩一個函數(shù)去處理
lodash

lodash 官網(wǎng)

純函數(shù)的好處
  • 可緩存: 因為純函數(shù)對相同的輸入始終有相同的結(jié)果氓轰,所以可以把純函數(shù)的結(jié)果緩存起來 (memoize)
// 記憶函數(shù)
const _ = require('lodash')

function getArea (r) {
  console.log(r)
  return Math.PI * r * r
}

// let getAreaWithMemory = _.memoize(getArea)
// console.log(getAreaWithMemory(4))
// console.log(getAreaWithMemory(4))
// console.log(getAreaWithMemory(4))

// 模擬 memoize 方法的實現(xiàn)

function memoize (f) {
  let cache = {}
  return function () {
    let key = JSON.stringify(arguments)
    cache[key] = cache[key] || f.apply(f, arguments)
    return cache[key]
  }
}

let getAreaWithMemory = memoize(getArea)
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
console.log(getAreaWithMemory(4))
  • 可測試: 純函數(shù)讓測試更方便
  • 并行處理: 在多線程環(huán)境下操作系統(tǒng)共享的內(nèi)存數(shù)據(jù)很可能會出現(xiàn)意外情況
  • 純函數(shù)不需要訪問共享內(nèi)存數(shù)據(jù)婚夫,所以在并行環(huán)境下可以任意運行純函數(shù)(web Worker)
純函數(shù)副作用

如果函數(shù)依賴于外部的狀態(tài)就無法保證輸出相同,就會帶來副作用署鸡。
副作用來源:

  • 配置文件
  • 數(shù)據(jù)庫
  • 獲取用戶的輸入
  • ......
    所有的外部交互都有可能代理副作用案糙,副作用也使得方法通用性下降不適合擴展和可重用性,同時副作用會給程序中帶來安全隱患靴庆,給程序帶來不確定性时捌,但是副作用不可能完全禁止,盡可能控制他們在可控范圍內(nèi)發(fā)生炉抒。
柯里化 <Currying>
// 函數(shù)的柯里化
// function checkAge (min) {
//   return function (age) {
//     return age >= min
//   }
// }

// ES6
let checkAge = min => (age => age >= min)

let checkAge18 = checkAge(18)
let checkAge20 = checkAge(20)

console.log(checkAge18(20))
console.log(checkAge18(24))
  • 當(dāng)一個函數(shù)有多個參數(shù)的時候先傳遞一部分參數(shù)調(diào)用它(這部分參數(shù)以后永遠(yuǎn)不變)
  • 然后返回一個新的函數(shù)接收剩余的參數(shù)奢讨,返回結(jié)果

lodash 中柯里化
_.curry(func)

  • 功能:創(chuàng)建一個函數(shù),該函數(shù)接收一個或多個func的參數(shù)焰薄,如果func所需要的參數(shù)都被提供則執(zhí)行func并返回 執(zhí)行的結(jié)果, 否則繼續(xù)返回該函數(shù)并等待接收剰余的參數(shù).
  • 參數(shù):需要柯里化的函數(shù)
  • 返回值:柯里化后的函數(shù)
const _ = require('lodash')

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

const curried = _.curry(getSum)

console.log(curried(1, 2, 4))
console.log(curried(1, 4)(4))
console.log(curried(14)(4)(3))
// 模擬實現(xiàn) lodash 中的 curry 方法

function getSum (a, b, c) {
  return a + b + c
}

const curried = curry(getSum)

console.log(curried(1, 2, 3))
console.log(curried(1)(2, 3))
console.log(curried(1, 2)(3))


function curry (func) {
  return function curriedFn(...args) {
    // 判斷實參和形參的個數(shù)
    if (args.length < func.length) {
      return function () {
        return curriedFn(...args.concat(Array.from(arguments)))
      }
    }
    return func(...args)
  }
}
柯里化總結(jié)
  • 柯里化可以數(shù)傳遞較少的參數(shù)得到一個已經(jīng)記住了某些固定參數(shù)
  • 這是一種對函數(shù)參數(shù)的“緩存”
  • 讓函數(shù)變的更靈活拿诸,讓函數(shù)的粒度更小
  • 可以把多元函數(shù)轉(zhuǎn)換成一元函數(shù),可以組合使用函數(shù)產(chǎn)生強大的功能
函數(shù)組合
  • 函數(shù)組合(compose)如果一個函數(shù)要經(jīng)過多個函數(shù)處理才能得到最終值(這個時候可挪中間過程的函數(shù)合并成一 個函數(shù))
  • 函數(shù)就像是數(shù)據(jù)的管道塞茅,函數(shù)組合就是把這些営道連接起來亩码,讓數(shù)據(jù)穿過多個管道形成最終結(jié)果
  • 函數(shù)組合默認(rèn)從右致左執(zhí)行
// 函數(shù)組合演示
function compose (f, g) {
  return function (value) {
    return f(g(value))         
  }
}

function reverse (array) {
  return array.reverse()
}

function first (array) {
  return array[0]
}

const last = compose(first, reverse)

console.log(last([1, 2, 3, 4]))
lodash中的組合函數(shù)
  • lodash中組合函數(shù)flow()或者flowRight(),他們都可以組合多個函數(shù)
  • flow()是從左到右運行
  • flowRight()是從右到左運行,使用的更多一些
// lodash 中的函數(shù)組合的方法 _.flowRight()
const _ = require('lodash')

const reverse = arr => arr.reverse()
const first = arr => arr[0]
const toUpper = s => s.toUpperCase()

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

// 模擬 lodash 中的 flowRight
// function compose (...args) {
//   return function (value) {
//     return args.reverse().reduce(function (acc, fn) {
//       return fn(acc)
//     }, value)
//   }
// }

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é)合律
const _ = require('lodash')

// const f = _.flowRight(_.toUpper, _.first, _.reverse)
// const f = _.flowRight(_.flowRight(_.toUpper, _.first), _.reverse)
const f = _.flowRight(_.toUpper, _.flowRight(_.first, _.reverse))


console.log(f(['one', 'two', 'three']))

調(diào)試:

// 函數(shù)組合 調(diào)試 
// NEVER SAY DIE  --> never-say-die

const _ = require('lodash')

// const log = v => {
//   console.log(v)
//   return v
// }

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

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

// _.toLower()
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/fp
  • lodash的fp模塊提供了實用的對函數(shù)式編程友好的方法
  • 提供了不可變的auto-cuuried iteratee-first data-last 的方法
// lodash 的 fp 模塊
// NEVER SAY DIE  --> never-say-die
const fp = require('lodash/fp')

const f = fp.flowRight(fp.join('-'), fp.map(fp.toLower), fp.split(' '))

console.log(f('NEVER SAY DIE'))
// 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']))
Point Free

Point Free:我們可以把數(shù)據(jù)處理的過程定義成與數(shù)據(jù)無關(guān)的合成運算野瘦,不需要用到代表數(shù)據(jù)的那個參數(shù)描沟,只要把簡單的運算步驟合成到一起飒泻,在使用這種模式之前我們需要定義一些輔助的基本運算函數(shù).

  • 不需要指明處理的數(shù)據(jù)
  • 只需要合成運算過程
  • 需要定義一些輔助的基本運算函數(shù)
// point free
// Hello     World => hello_world
const fp = require('lodash/fp')

const f = fp.flowRight(fp.replace(/\s+/g, '_'), fp.toLower)

console.log(f('Hello     World'))
// 把一個字符串中的首字母提取并轉(zhuǎn)換成大寫, 使用. 作為分隔符
// world wild web ==> W. W. W
const fp = require('lodash/fp')

// const firstLetterToUpper = fp.flowRight(fp.join('. '), fp.map(fp.first), fp.map(fp.toUpper), fp.split(' '))
const firstLetterToUpper = fp.flowRight(fp.join('. '), fp.map(fp.flowRight(fp.first, fp.toUpper)), fp.split(' '))

console.log(firstLetterToUpper('world wild web'))
Functor 函子

到目前為止已經(jīng)已經(jīng)學(xué)習(xí)了函數(shù)式編程的一些基礎(chǔ),但是我們還沒有演示在函數(shù)式編程中如何把副作用控制在可控范圍內(nèi)吏廉、異常處理泞遗、異步操作等.
什么是函子:

  • 容器:包含值和值的變形關(guān)系(這個變形關(guān)系就是函數(shù))
  • 函 子 : 是一個特殊的容器,通過一個普通的對象來實現(xiàn)席覆,該對象具有map方法史辙,map方法可以運行一個函數(shù)對值進行處理(變形關(guān)系)
// // Functor 函子
// class Container {
//   constructor (value) {
//     this._value = value
//   }

//   map (fn) {
//     return new Container(fn(this._value))
//   }
// }

// let r = new Container(5)
//   .map(x => x + 1)
//   .map(x => x * x)

// console.log(r)


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 + 2)
//           .map(x => x * x)

// console.log(r)


// 演示 null undefined 的問題
Container.of(null)
  .map(x => x.toUpperCase())

總結(jié):

  • 函數(shù)式編程的運算不直接操作值,而是由函子完成
  • 函子就是一個實現(xiàn)了map契約的對象
  • 我們可以把函子想象成一個盒子娜睛,這個盒子里封裝了一值
  • 想要處理盒子的值髓霞,我們需要給盒子的map方法傳遞一個處理值的函數(shù)(純函數(shù)),由這個函數(shù)來對值進行處理
  • 最終map方法返回包含一個新值的盒子(函子)
MayBe 函子
  • 可以對外部的空值情況做處理(控制副作用在允許的范圍)
// MayBe 函子
class MayBe {
  static of (value) {
    return new MayBe(value)
  }

  constructor (value) {
    this._value = value
  }

  map (fn) {
    return this.isNothing() ? MayBe.of(null) : MayBe.of(fn(this._value))
  }

  isNothing () {
    return this._value === null || this._value === undefined
  }
}


// let r = MayBe.of('Hello World')
//           .map(x => x.toUpperCase())
// console.log(r)


// let r = MayBe.of(null)
//           .map(x => x.toUpperCase())
// console.log(r)


let r = MayBe.of('hello world')
          .map(x => x.toUpperCase())
          .map(x => null)
          .map(x => x.split(' '))
console.log(r)
Either 函子

Either 函子

  • Either 兩者中的任何一個畦戒,類似if...else...的處理
  • 異常會讓函數(shù)變得不純方库, Either函子可以用來做異常處理
   // Either 函子
class Left {
  static of (value) {
    return new Left(value)
  }

  constructor (value) {
    this._value = value
  }

  map (fn) {
    return this
  }
}

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

  constructor (value) {
    this._value = value
  }

  map (fn) {
    return Right.of(fn(this._value))
  }
}

// let r1 = Right.of(12).map(x => x + 2)
// let r2 = Left.of(12).map(x => x + 2)

// console.log(r1)
// console.log(r2)


function parseJSON (str) {
  try {
    return Right.of(JSON.parse(str))
  } catch (e) {
    return Left.of({ error: e.message })
  }
}

// let r = parseJSON('{ name: zs }')
// console.log(r)

let r = parseJSON('{ "name": "zs" }')
          .map(x => x.name.toUpperCase())
console.log(r)
IO函子
  • IO函子中的_value 是一個函數(shù),這里吧函數(shù)作為值來處理
  • IO函子可以把不純的動作儲存到_value中障斋,延遲執(zhí)行這個不純的操作(惰性執(zhí)行)纵潦,包裝當(dāng)前的操作純
  • 把不純的操作交給調(diào)用者來處理
// 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))
  }
}

// 調(diào)用
let r = IO.of(process).map(p => p.execPath)
// console.log(r)
console.log(r._value())
Task異步執(zhí)行
  • 異步任務(wù)的實現(xiàn)過于復(fù)雜,我們使用folktale中的Task來演示
  • folktale—個標(biāo)準(zhǔn)的函數(shù)式編程庫: 和lodash垃环、ramda不同的是邀层,他沒有提供很多功能函數(shù); 只提供了一些函數(shù)式處理的操作,例如:compose遂庄、curry等寥院,一些函子Task、Either涛目、MayBe等
// Task 處理異步任務(wù)
const fs = require('fs')
const { task } = require('folktale/concurrency/task')
const { split, find } = require('lodash/fp')

function readFile (filename) {
  return task(resolver => {
    fs.readFile(filename, 'utf-8', (err, data) => {
      if (err) resolver.reject(err)

      resolver.resolve(data)
    })
  })
}

readFile('package.json')
  .map(split('\n'))
  .map(find(x => x.includes('version')))
  .run()
  .listen({
    onRejected: err => {
      console.log(err)
    },
    onResolved: value => {
      console.log(value)
    }
  })
// IO 函子的問題
const fs = require('fs')
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))
  }
}

let readFile = function (filename) {
  return new IO(function () {
    return fs.readFileSync(filename, 'utf-8')
  })
}

let print = function (x) {
  return new IO(function () {
    console.log(x)
    return x
  })
}

let cat = fp.flowRight(print, readFile)
// IO(IO(x))
let r = cat('package.json')._value()._value()
console.log(r)
monad 函子

解決函子嵌套問題

// IO Monad
const fs = require('fs')
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))
  }

  join () {
    return this._value()
  }

  flatMap (fn) {
    return this.map(fn).join()
  }
}

let readFile = function (filename) {
  return new IO(function () {
    return fs.readFileSync(filename, 'utf-8')
  })
}

let print = function (x) {
  return new IO(function () {
    console.log(x)
    return x
  })
}

let r = readFile('package.json')
          // .map(x => x.toUpperCase())
          .map(fp.toUpper)
          .flatMap(print)
          .join()

console.log(r)
總結(jié):
總結(jié)

文章內(nèi)容輸出來源于:拉勾教育大前端高薪訓(xùn)練營

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末秸谢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子霹肝,更是在濱河造成了極大的恐慌估蹄,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沫换,死亡現(xiàn)場離奇詭異臭蚁,居然都是意外死亡,警方通過查閱死者的電腦和手機讯赏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門垮兑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人漱挎,你說我怎么就攤上這事甥角。” “怎么了识樱?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我怜庸,道長当犯,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任割疾,我火速辦了婚禮嚎卫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宏榕。我一直安慰自己拓诸,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布麻昼。 她就那樣靜靜地躺著奠支,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抚芦。 梳的紋絲不亂的頭發(fā)上倍谜,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機與錄音叉抡,去河邊找鬼尔崔。 笑死,一個胖子當(dāng)著我的面吹牛褥民,可吹牛的內(nèi)容都是我干的季春。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼消返,長吁一口氣:“原來是場噩夢啊……” “哼载弄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侦副,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤侦锯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后秦驯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尺碰,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年译隘,在試婚紗的時候發(fā)現(xiàn)自己被綠了亲桥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡固耘,死狀恐怖题篷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情厅目,我是刑警寧澤番枚,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布法严,位于F島的核電站,受9級特大地震影響葫笼,放射性物質(zhì)發(fā)生泄漏深啤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一路星、第九天 我趴在偏房一處隱蔽的房頂上張望溯街。 院中可真熱鬧,春花似錦洋丐、人聲如沸呈昔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堤尾。三九已至,卻和暖如春九榔,著一層夾襖步出監(jiān)牢的瞬間哀峻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工哲泊, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留剩蟀,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓切威,卻偏偏與公主長得像育特,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子先朦,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355