淺談JavaScript 模塊化

參考資料

Modules/1.0——維基百科
CommonJS Modules/1.0——伯樂(lè)在線
js模塊化——博客園
Javascript模塊化編程系列——阮一峰
《ECMAScript 6 入門》——阮一峰

前言

本人菜鳥(niǎo),入IT只為當(dāng)鼓勵(lì)師。本編文章意在簡(jiǎn)單總結(jié)一下 什么是模塊化,模塊化的優(yōu)點(diǎn), js模塊化 的發(fā)展歷史,關(guān)于 js模塊化 的一些規(guī)范 等等。

一、什么是模塊化

根據(jù)百度百科說(shuō)法:模塊化是指解決一個(gè)復(fù)雜問(wèn)題時(shí)自頂向下逐層把系統(tǒng)劃分成若干模塊的過(guò)程,有多種屬性,分別反映其內(nèi)部特性。

暈了,這是什么嘛。

簡(jiǎn)單的說(shuō)就是,我們實(shí)現(xiàn)一個(gè)應(yīng)用時(shí)(不管是web、桌面還是移動(dòng)端),通常都會(huì)按照不同的功能,分割成不同的模塊來(lái)編寫,編寫完之后按照某種方式組裝起來(lái)成為一個(gè)整體,最終實(shí)現(xiàn)整個(gè)系統(tǒng)的功能。

所以,如果一個(gè)團(tuán)隊(duì)一起做一個(gè)復(fù)雜的應(yīng)用,肯定要分模塊分工合作(一個(gè)人戰(zhàn)斗不太現(xiàn)實(shí))。這時(shí),有很多需要注意的點(diǎn)就出現(xiàn)了:

  • 模塊中定義的資源不應(yīng)該污染全局環(huán)境,否則多人協(xié)作困難且容易出錯(cuò)。
  • 各個(gè)模塊可獨(dú)立工作,即便單組模塊出現(xiàn)故障也不影響整個(gè)系統(tǒng)工作
  • 各模塊不能全部預(yù)先加載,應(yīng)該實(shí)現(xiàn)按需自動(dòng)加載。確保每個(gè)模塊高效運(yùn)行,又能節(jié)約資源,提高效率。

C、C++、Java、PHP等等編程語(yǔ)言本身就擁有可以實(shí)現(xiàn)模塊化的指令或方法,有了這些指令或方法,就可以把子功能寫在另外的文件上,需要用到的時(shí)候直接引入即可。舉下例子:

  • c使用 #include 包含.h文件
  • php中使用 require_once 包含.php文件
  • java使用 import 導(dǎo)入包

拋開(kāi)C、C++、Java、PHP這些不說(shuō),就說(shuō)前端領(lǐng)域,認(rèn)真想想,其實(shí) html css 也實(shí)現(xiàn)了模塊化。

  • html 中的 <frame> <iframe> <frameset>(但好像不推薦使用)


  • css 中有 @import " /.css " 指令可以導(dǎo)入其他css

那 JavaScript 呢?帶著疑問(wèn),下面會(huì)介紹js模塊化的發(fā)展歷程。(大神請(qǐng)無(wú)視)

二、模塊化的優(yōu)點(diǎn)

可維護(hù)性:

  • 多人協(xié)作互不干擾
  • 靈活架構(gòu),焦點(diǎn)分離
  • 方便模塊間組合、分解 、解耦
  • 方便單個(gè)模塊功能調(diào)試、升級(jí)

可測(cè)試性:

  • 可分單元測(cè)試

三、前端的模塊化思想的發(fā)展

3.1 那年的誕生——1995

1995年,JavaScript正式發(fā)布,當(dāng)時(shí)它只是作為一種客戶端腳本語(yǔ)言,目的是 將 不涉及后端數(shù)據(jù)的、簡(jiǎn)單的 表單有效性驗(yàn)證 轉(zhuǎn)移到客戶端完成,減少客戶端向服務(wù)端的請(qǐng)求數(shù)。那時(shí)的JavaScript只是服務(wù)端工程師在使用,他們或許只需在頁(yè)面上隨便寫幾句js代碼就能滿足需求。

if (xxx) {
  // ......
} else {
  // ......
}
element.onsubmit= function () {
  //......
}

代碼可能像這樣子,從上到下執(zhí)行就行了,沒(méi)有什么模塊的規(guī)范。

3.2 模塊萌芽

隨著ajax的概念被提出,前端有了主動(dòng)發(fā)起請(qǐng)求的能力,一些業(yè)務(wù)開(kāi)始向客戶端方向偏移。網(wǎng)站逐漸變成“互聯(lián)網(wǎng)應(yīng)用程序”,嵌入網(wǎng)頁(yè)的Javascript代碼越來(lái)越龐大,越來(lái)越復(fù)雜。于是,一些問(wèn)題就暴漏出來(lái)了:

  • 依賴關(guān)系不好管理。如果一個(gè)文件需要依賴另外一些文件中定義的東西時(shí),這個(gè)文件依賴的所有文件都要在它之前導(dǎo)入。過(guò)于復(fù)雜的系統(tǒng),依賴關(guān)系可能出現(xiàn)相互交叉的情況,依賴關(guān)系的管理就更加難了。
    // 如果main.js中要用到gameBg.js中定義的屬性、方法或者對(duì)象時(shí)

    // 正確,gameBg.js要在main.js之前導(dǎo)入
    <script src="scripts/views/gameBg.js" type="text/javascript">
    <script src="scripts/main.js" type="text/javascript">
    
    // 報(bào)錯(cuò),cannot find xxx of undefined
    <script src="scripts/views/gameBg.js" type="text/javascript">
    <script src="scripts/main.js" type="text/javascript">
    
    // 如果js文件很多呢?
    
  • 全局環(huán)境的污染。
    我在a.js中定義了一個(gè)全局變量 var a = 0,相當(dāng)于定義在window上。
    你在b.js中用了我定義的全局變量,給它賦值 a = 1
    我又在c.js中用了這個(gè)全局變量,但我不知道你在b.js中修改過(guò)a的值。于是 if (a==0) { // ...... }。(出事了!)

  • 命名沖突
    項(xiàng)目中通常會(huì)把一些通用的函數(shù)封裝成一個(gè)文件。
    我定義了一個(gè)函數(shù):function func ( // ...... ) { }
    你也想實(shí)現(xiàn)類似功能,于是:function func2 ( // ...... ) { }
    他又想實(shí)現(xiàn)類似功能,于是:function func3 ( // ...... ) { }
    要避免命名沖突,只能靠你我他之間的溝通協(xié)作。

如果放著這些問(wèn)題不解決,團(tuán)隊(duì)的工作重點(diǎn)與關(guān)注點(diǎn)就不只是系統(tǒng)的業(yè)務(wù)邏輯,還包括隊(duì)內(nèi)的溝通,這會(huì)阻礙著項(xiàng)目進(jìn)度。而且當(dāng)人數(shù)一多時(shí)(幾十人甚至上千人一起開(kāi)發(fā)同一個(gè)項(xiàng)目),溝通就變得非常困難且低效了。

于是,前人創(chuàng)造了很多方法來(lái)避免這些問(wèn)題,盡最大的努力實(shí)現(xiàn)模塊化:

3.2.1 避免全局環(huán)境污染的方法

  • 只創(chuàng)建一個(gè)全局變量作為當(dāng)前應(yīng)用的容器,把其他變量、方法加到該命名空間下。
    var Myapp = {};
    Myapp.location = "login";
    Myapp.info = {
    name: "flappybird",
    creator: "Dong Nguyen"
    };
    Myapp.startGame = function () {
    // ......
    };

  • 將代碼寫在一個(gè)匿名函數(shù)內(nèi)部
    ( function () {
    // 局部變量和方法
    var variable1 = "I'm a variable in part";
    var func1 = function () {
    // ......
    };
    // 全局變量和方法
    window.variable2 = "I'm a variable in global";
    window.func2 = function () {
    // ......
    };
    })();

  • jquery風(fēng)格匿名函數(shù)
    ( function (window) {
    // 通過(guò)給window添加屬性而暴漏到全局
    window.jQuery = window.$ = jQuery;

        // 定義全局對(duì)象jQuery($)的相關(guān)內(nèi)容
    })(window);
    

jQuery的封裝風(fēng)格曾被很多框架模仿。
這種方式用到了匿名函數(shù)包裝代碼(即第二種方法)。多出的點(diǎn)是,所依賴的外部變量可以傳給這個(gè)函數(shù),在函數(shù)內(nèi)部就可以使用這些依賴了,然后把模塊自身暴漏給window。
如果需要添加擴(kuò)展,則可以作為jQuery的插件,把它掛載到$上。例如:fullpage.js插件。
這種風(fēng)格雖然靈活了些,但并未解決根本問(wèn)題:所需依賴還是得外部提前提供、還是增加了全局變量。

3.2.2 避免命名沖突的方法

  • java風(fēng)格的命名空間,用多級(jí)命名空間來(lái)進(jìn)行管理。于是編寫代碼和調(diào)用代碼就變得這么長(zhǎng)了。
    Myapp.utils.func1 = xxx;
    Myapp.tools.func1 = xxx;
    Myapp.tools.another.func1 = xxx;

  • 設(shè)置變量名的控制權(quán)讓渡函數(shù)。
    有時(shí)候我們可能不只用到一種函數(shù)庫(kù)或插件,當(dāng)用到多個(gè)函數(shù)庫(kù)時(shí),由于庫(kù)并不是一個(gè)人編寫的,全局變量的命名沖突不是總能避免。如:jquery.js庫(kù) 和 Prototype.js庫(kù),它們都用了$符號(hào)作為全局變量。同時(shí)導(dǎo)入兩個(gè)庫(kù)肯定會(huì)產(chǎn)生影響。
    但是jquery提供了noConflict()方法,可以讓渡變量名的控制權(quán)。
    // 將變量$的控制權(quán)讓渡給prototype.js
    jQuery.noConflict();
    // 使用jQuery
    jQuery("h1").text("我是標(biāo)題");

    // 自定義一個(gè)更短的命名
    var jq = jQuery.noConflict();       
    jq("p").text("我是段落");
    

3.2.3 完善依賴關(guān)系的管理

后面提到的 require.js、sea.js 等 可以解決這個(gè)問(wèn)題,這個(gè)后續(xù)再說(shuō)。

3.2.4 推薦

想了解更多實(shí)現(xiàn)模塊化的方法,可以拜讀一下峰哥的文章:
Javascript模塊化編程(一):模塊的寫法

3.2.5 模塊化問(wèn)題

當(dāng)人們覺(jué)得再這樣下去寫代碼槽糕透了的時(shí)候,他們就想運(yùn)用模塊化的思想,寫好一個(gè)模塊,要用就導(dǎo)入,導(dǎo)入后毫不影響原先的代碼。這樣就引發(fā)很多需要思考的問(wèn)題:

  • 怎樣安全地包裝一個(gè)模塊的代碼?
  • 怎樣唯一地標(biāo)識(shí)一個(gè)模塊?
  • 怎樣優(yōu)雅地把模塊的API暴漏出去?
  • 怎樣方便地使用所依賴的模塊?

四、服務(wù)端 js 的誕生

4.1 nodejs

2009年,nodejs誕生,我們可以用 js 編寫服務(wù)端的代碼了。
在瀏覽器環(huán)境下,沒(méi)有模塊也不是特別大的問(wèn)題,畢竟網(wǎng)頁(yè)程序的復(fù)雜性有限;但是在服務(wù)器端,一定要有模塊,與操作系統(tǒng)和其他應(yīng)用程序互動(dòng),否則根本沒(méi)法編程。
于是,CommonJS 社區(qū)制定了 Modules/1.0 規(guī)范(現(xiàn)在已經(jīng)被1.1取代)。nodejs 采用了該規(guī)范,故以下用 nodejs 作為例子。

4.2 Modules/1.0

總結(jié)起來(lái),Modules/1.0規(guī)范指出:

  • 模塊需要提供頂級(jí)作用域的私有性。
  • 提供從其他模板導(dǎo)入單例對(duì)象到自身的能力
  • 提供導(dǎo)出自身API的能力

Modules/1.0規(guī)范的內(nèi)容如下:

4.2.1 模塊上下文

  • 在模塊中存在一個(gè)自由變量"require",它是一個(gè)函數(shù)。這個(gè)"require"函數(shù):
    ① 接收參數(shù)為:一個(gè)模塊標(biāo)識(shí)符。
    var example = require('./example.js');
    ② 返回:外部模塊輸出的API。
    // 變量example即為外部模塊example.js輸出的內(nèi)容
    ③ 如果出現(xiàn)依賴閉環(huán)(正常情況,加載main.js時(shí),遇到 var a = require(./a.js); 則去加載a.js;加載a.js時(shí),遇到 var b = require(./b.js); 則去加載b.js;加載b.js時(shí),遇到 var a = require(./a.js); 則去加載a.js。無(wú)線循環(huán),這就產(chǎn)生了依賴閉環(huán)的問(wèn)題),為了避免這個(gè)問(wèn)題,規(guī)定每個(gè)模塊只會(huì)被加載執(zhí)行一次
    // main.js
    console.log("main start");
    var a = require(./a.js);
    var b = require(./b.js);
    console.log("main end");

    // a.js
    console.log("a start");
    var b = require(./b.js);
    console.log("a end");
    
    // b.js
    console.log("b start");
    var a = require(./a.js);
    console.log("b end");  
    
    /* 輸出結(jié)果為:
    main start
    a start
    b start
    b end
    a end
    */
    
程序執(zhí)行順序

④ 如果請(qǐng)求模塊失敗,require函數(shù)應(yīng)拋出一個(gè)錯(cuò)誤。

  • 模塊中存在一個(gè)名為"exports"的自由變量,它是一個(gè)對(duì)象,模板可把自身API加到其中。
    // 暴露message變量
    exports.message = "hi";
    // 暴露hello方法
    exports.say= function () {
    console.log("hello!");
    };
  • 模塊必須使用"exports"對(duì)象來(lái)作為輸出的唯一表示

4.2.2 模塊標(biāo)識(shí)符

  • 模塊標(biāo)識(shí)符是一個(gè)以正斜杠分隔的多個(gè)”term”組成的字符串。
  • 一個(gè)term必須是一個(gè) 駝峰格式的標(biāo)識(shí)符,.字符(表示當(dāng)前目錄) 或者 ..字符串(表示上一級(jí)目錄)。
  • 模塊標(biāo)識(shí)符可以不加文件擴(kuò)展名,比如”.js”。
    var a = require(./a);
    // 相當(dāng)于 var a = require(./a.js);
  • 模塊標(biāo)識(shí)符可以是 相對(duì)的 或者 頂級(jí)的 (top-level)。如果一個(gè)模塊標(biāo)識(shí)符的第一個(gè)term是 .字符(表示當(dāng)前目錄)或者 ..字符串(表示上一級(jí)目錄),那么它是 相對(duì)的
  • 頂級(jí)標(biāo)識(shí)符是概念上的模塊命名空間的根。
  • 相對(duì)標(biāo)識(shí)符是相對(duì)于在其內(nèi)部調(diào)用了 require() 的模塊的標(biāo)識(shí)符來(lái)進(jìn)行解析的。

五、服務(wù)端的模塊化在前端領(lǐng)域的應(yīng)用

既然服務(wù)端出了模塊化方案 Modules/1.0 ,那么是不是可以把這個(gè)規(guī)范直接用在客戶端啊?
只可惜,不能。出于以下原因:

  • 資源的加載方式與服務(wù)端完全不同。
    ① 服務(wù)端 require 一個(gè)模塊,是直接從 硬盤 或 內(nèi)存 中讀取的。可以同步加載完成,等待時(shí)間就是硬盤的讀取時(shí)間,那速度是很快的。
    ② 客戶端,瀏覽器需要從服務(wù)端下載資源,花費(fèi)的是請(qǐng)求所花的時(shí)間,取決于網(wǎng)速的快慢。若要等很長(zhǎng)時(shí)間,瀏覽器會(huì)處于"假死"狀態(tài)。例如:
    // 第二行math.add(1, 1),在第一行require('math')之后運(yùn)行,因此必須等math.js加載完成。
    // 如果加載時(shí)間很長(zhǎng),整個(gè)應(yīng)用就會(huì)停在那里等。
    var math = require('./math.js');
    math.add(1, 1);
    因此,瀏覽器端的模塊,不能采用 "同步加載"(Sync),只能采用 "異步加載"(Async)。這就是 AMD規(guī)范(后面提及)誕生的背景。
  • 若瀏覽器加載資源的方式外層沒(méi)有 function 包裹,變量會(huì)暴漏在全局上;而全局污染這個(gè)問(wèn)題在服務(wù)端編程不如瀏覽器要求嚴(yán)格。例如:
    // 變量math 和 math.js中定義在全局作用域上的變量、方法 都會(huì)污染到全局。
    var math = require('./math.js');

既然如此,問(wèn)題要怎么解決?于是乎,就像黨派斗爭(zhēng)一樣,分裂了三種解決方案。

5.1 Modules/1.x

這一派人的意見(jiàn)是:

  • 在現(xiàn)有基礎(chǔ)上改進(jìn)來(lái)滿足瀏覽器端的需要(function包裝不污染全局、異步加載)。所以,他們制定了 Modules/Transport規(guī)范,提出:先通過(guò)工具,把現(xiàn)有模塊代碼轉(zhuǎn)化為瀏覽器上使用的模塊代碼,然后再使用的方案。

典型的工具有:browserify。Browserify 可以讓你使用類似于 node 的 require() 的方式來(lái)組織瀏覽器端的 Javascript 代碼,通過(guò) 預(yù)編譯 讓前端 Javascript 可以直接使用 Node NPM 安裝的一些庫(kù)。難懂,那就直接看它的例子吧:

browserify的簡(jiǎn)單用法

所以,若采用這一派的規(guī)范,我們就可以直接像服務(wù)端一樣編寫代碼了,編寫完后,只需要用工具把它編譯成瀏覽器使用的代碼即可。

5.2 Modules/2.0

這一派人的意見(jiàn)是:

  • Modules/1.0固然不適合瀏覽器,但它里面的一些理念還是很好的,如:通過(guò) require 來(lái)聲明依賴。新的規(guī)范應(yīng)該兼容這些。
  • AMD規(guī)范(請(qǐng)看 5.3) 也有它好的地方,如:模塊的預(yù)先加載、通過(guò)
    return 可暴漏任意類型的數(shù)據(jù),而不像 commonjs 那樣 exports 只能為
    object。故 其中的一些觀點(diǎn) 也應(yīng)采納。
  • 最終他們制定了一個(gè) Modules/Wrappings規(guī)范,此規(guī)范指出了一個(gè)模塊應(yīng)該如何"包裝",包含以下內(nèi)容:
    ① 全局有一個(gè) module 變量,用來(lái)定義模塊。
    ② 通過(guò)module.declare方法來(lái)定義一個(gè)模塊。
    ③ module.declare方法 只接收一個(gè)參數(shù),那就是模塊的 factory,它可以是函數(shù),也可以是對(duì)象(如果是對(duì)象,那么模塊輸出就是此對(duì)象)。
    ④ 模塊的 factory函數(shù) 傳入三個(gè)參數(shù):require、exports、module,用來(lái)引入其他依賴和導(dǎo)出本模塊API。
    ⑤ 如果 factory函數(shù) 最后明確寫有return數(shù)據(jù),那么 return 的內(nèi)容即為模塊的輸出;不寫 return 默認(rèn)返回undefined。

CMD/seajs

seajs 的作者 是 國(guó)內(nèi)大牛 淘寶前端步道者 玉伯。seajs 全面擁抱
Modules/Wrappings規(guī)范,不用 RequireJS 那樣回調(diào)的方式來(lái)編寫模塊。

它的特色和用法以后再來(lái)補(bǔ)充。(待續(xù))

5.3 Modules/Async

這一派人的意見(jiàn)是:

  • 瀏覽器與服務(wù)器環(huán)境差別太大,不能沿用舊的模塊標(biāo)準(zhǔn)。

  • 既然瀏覽器必須異步加載代碼,那么模塊在定義的時(shí)候就必須 指明所依賴的模塊,然后 把本模塊的代碼寫在回調(diào)函數(shù)里。模塊的加載也是通過(guò) 下載—>回調(diào) 這樣的過(guò)程來(lái)進(jìn)行,這個(gè)思想就是AMD的基礎(chǔ)。
    // AMD也采用require()語(yǔ)句加載模塊,但是不同于CommonJS,它要求兩個(gè)參數(shù)
    // 第一個(gè)參數(shù)[module],是一個(gè)數(shù)組,里面的成員就是要加載的模塊
    // 第二個(gè)參數(shù)callback,則是加載成功之后的回調(diào)函數(shù)
    require([module], callback);

    // math.add()與math模塊加載不是同步的,瀏覽器不會(huì)發(fā)生假死。AMD比較適合瀏覽器環(huán)境。
    require(['math'], function (math) {
        math.add(2, 3);
    });
    
  • 由于與原規(guī)范不合,最終從 CommonJs 中分裂了出去,獨(dú)立制定了瀏覽器端的js模塊化規(guī)范 AMD(Asynchronous Module Definition)

  • 目前,主要有兩個(gè)Javascript庫(kù)實(shí)現(xiàn)了AMD規(guī)范:require.jscurl.js

AMD/RequireJs

這里主要介紹 RequireJs,若想了解其用法,可以看我的另一篇文章:AMD/RequireJS 使用入門

六、ES6模塊化標(biāo)準(zhǔn)

既然模塊化開(kāi)發(fā)的呼聲這么高,作為官方的ECMA必然要有所行動(dòng),js模塊化很早就列入草案,終于在2015年6月份發(fā)布了ES6正式版。

ES6只要增加了 exportimportmodule 等命令。具體用法以后再補(bǔ)充。

想了解更多關(guān)于ES6的東西,推薦大家閱讀《ECMAScript 6 入門》,這是這本書的 網(wǎng)上教程

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評(píng)論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,740評(píng)論 3 420
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,856評(píng)論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,175評(píng)論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,931評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,321評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評(píng)論 3 443
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,533評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,082評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,891評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,067評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,319評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,732評(píng)論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,987評(píng)論 1 289
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,794評(píng)論 3 394
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,076評(píng)論 2 375

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