淺談JavaScript 模塊化

參考資料

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

前言

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

一、什么是模塊化

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

暈了,這是什么嘛单芜。

簡單的說就是蜕该,我們實(shí)現(xiàn)一個(gè)應(yīng)用時(shí)(不管是web、桌面還是移動(dòng)端)洲鸠,通常都會(huì)按照不同的功能堂淡,分割成不同的模塊來編寫,編寫完之后按照某種方式組裝起來成為一個(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等等編程語言本身就擁有可以實(shí)現(xiàn)模塊化的指令或方法,有了這些指令或方法梗顺,就可以把子功能寫在另外的文件上泡孩,需要用到的時(shí)候直接引入即可。舉下例子:

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

拋開C寺谤、C++仑鸥、Java、PHP這些不說变屁,就說前端領(lǐng)域眼俊,認(rèn)真想想,其實(shí) html css 也實(shí)現(xiàn)了模塊化粟关。

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


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

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

二澎灸、模塊化的優(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í)它只是作為一種客戶端腳本語言艺玲,目的是 將 不涉及后端數(shù)據(jù)的、簡單的 表單有效性驗(yàn)證 轉(zhuǎn)移到客戶端完成鞠抑,減少客戶端向服務(wù)端的請(qǐng)求數(shù)饭聚。那時(shí)的JavaScript只是服務(wù)端工程師在使用,他們或許只需在頁面上隨便寫幾句js代碼就能滿足需求搁拙。

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

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

3.2 模塊萌芽

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

  • 依賴關(guān)系不好管理狡赐。如果一個(gè)文件需要依賴另外一些文件中定義的東西時(shí),這個(gè)文件依賴的所有文件都要在它之前導(dǎo)入钦幔。過于復(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中修改過a的值。于是 if (a==0) { // ...... }食茎。(出事了5倨啤)

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

如果放著這些問題不解決喇伯,團(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í)(幾十人甚至上千人一起開發(fā)同一個(gè)項(xiàng)目),溝通就變得非常困難且低效了买喧。

于是捻悯,前人創(chuàng)造了很多方法來避免這些問題匆赃,盡最大的努力實(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) {
    // 通過給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)格雖然靈活了些唠倦,但并未解決根本問題:所需依賴還是得外部提前提供称鳞、還是增加了全局變量。

3.2.2 避免命名沖突的方法

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

  • 設(shè)置變量名的控制權(quán)讓渡函數(shù)候齿。
    有時(shí)候我們可能不只用到一種函數(shù)庫或插件熙暴,當(dāng)用到多個(gè)函數(shù)庫時(shí),由于庫并不是一個(gè)人編寫的慌盯,全局變量的命名沖突不是總能避免周霉。如:jquery.js庫 和 Prototype.js庫,它們都用了$符號(hào)作為全局變量亚皂。同時(shí)導(dǎo)入兩個(gè)庫肯定會(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è)問題,這個(gè)后續(xù)再說禁漓。

3.2.4 推薦

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

3.2.5 模塊化問題

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

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

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

4.1 nodejs

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

4.2 Modules/1.0

總結(jié)起來,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。無線循環(huán)爹殊,這就產(chǎn)生了依賴閉環(huán)的問題)蜕乡,為了避免這個(gè)問題,規(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ì)象來作為輸出的唯一表示

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í)符來進(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)速的快慢乏苦。若要等很長時(shí)間,瀏覽器會(huì)處于"假死"狀態(tài)尤筐。例如:
    // 第二行math.add(1, 1)汇荐,在第一行require('math')之后運(yùn)行,因此必須等math.js加載完成盆繁。
    // 如果加載時(shí)間很長掀淘,整個(gè)應(yīng)用就會(huì)停在那里等。
    var math = require('./math.js');
    math.add(1, 1);
    因此油昂,瀏覽器端的模塊革娄,不能采用 "同步加載"(Sync)倾贰,只能采用 "異步加載"(Async)。這就是 AMD規(guī)范(后面提及)誕生的背景拦惋。
  • 若瀏覽器加載資源的方式外層沒有 function 包裹躁染,變量會(huì)暴漏在全局上;而全局污染這個(gè)問題在服務(wù)端編程不如瀏覽器要求嚴(yán)格架忌。例如:
    // 變量math 和 math.js中定義在全局作用域上的變量、方法 都會(huì)污染到全局我衬。
    var math = require('./math.js');

既然如此叹放,問題要怎么解決?于是乎挠羔,就像黨派斗爭一樣井仰,分裂了三種解決方案。

5.1 Modules/1.x

這一派人的意見是:

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

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

browserify的簡單用法

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

5.2 Modules/2.0

這一派人的意見是:

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

CMD/seajs

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

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

5.3 Modules/Async

這一派人的意見是:

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

  • 既然瀏覽器必須異步加載代碼,那么模塊在定義的時(shí)候就必須 指明所依賴的模塊姨拥,然后 把本模塊的代碼寫在回調(diào)函數(shù)里绅喉。模塊的加載也是通過 下載—>回調(diào) 這樣的過程來進(jìn)行,這個(gè)思想就是AMD的基礎(chǔ)叫乌。
    // AMD也采用require()語句加載模塊柴罐,但是不同于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庫實(shí)現(xiàn)了AMD規(guī)范:require.jscurl.js寞奸。

AMD/RequireJs

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

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

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

ES6只要增加了 export 齐帚、import 妒牙、module 等命令。具體用法以后再補(bǔ)充童谒。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔫饰,隨后出現(xiàn)的幾起案子琅豆,更是在濱河造成了極大的恐慌,老刑警劉巖篓吁,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件茫因,死亡現(xiàn)場離奇詭異,居然都是意外死亡杖剪,警方通過查閱死者的電腦和手機(jī)冻押,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盛嘿,“玉大人洛巢,你說我怎么就攤上這事〈握祝” “怎么了稿茉?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長芥炭。 經(jīng)常有香客問我漓库,道長,這世上最難降的妖魔是什么园蝠? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任渺蒿,我火速辦了婚禮,結(jié)果婚禮上彪薛,老公的妹妹穿的比我還像新娘蘸嘶。我一直安慰自己良瞧,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布训唱。 她就那樣靜靜地躺著褥蚯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪况增。 梳的紋絲不亂的頭發(fā)上赞庶,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音澳骤,去河邊找鬼歧强。 笑死,一個(gè)胖子當(dāng)著我的面吹牛为肮,可吹牛的內(nèi)容都是我干的摊册。 我是一名探鬼主播,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼颊艳,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼茅特!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棋枕,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤白修,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后重斑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兵睛,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年窥浪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了祖很。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漾脂,死狀恐怖突琳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情符相,我是刑警寧澤拆融,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站啊终,受9級(jí)特大地震影響镜豹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蓝牲,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一趟脂、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧例衍,春花似錦昔期、人聲如沸已卸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽累澡。三九已至,卻和暖如春般贼,著一層夾襖步出監(jiān)牢的瞬間愧哟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工哼蛆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蕊梧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓腮介,卻偏偏與公主長得像肥矢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叠洗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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