進(jìn)擊的 JavaScript(四) 之 閉包與作用域

更改記錄:

19年 11月27日,修改!

上一節(jié)說(shuō)了執(zhí)行上下文,這節(jié)咱們就乘勝追擊來(lái)搞搞閉包!頭疼的東西讓你不再頭疼!

名詞解釋:

變量對(duì)象

變量對(duì)象是根據(jù)(Variable Object) 來(lái)翻譯過(guò)來(lái)的,也可以翻譯成可變對(duì)象, 就是保存變量的對(duì)象,活動(dòng)對(duì)象,閉包對(duì)象都保存著變量,因此也可以稱為變量對(duì)象。

注:這里解釋下,是因?yàn)楦鱾€(gè)書中對(duì)這幾個(gè)名詞的使用,搞的好遠(yuǎn)。

執(zhí)行上下文

是根據(jù)(Execution Context)翻譯過(guò)來(lái)的,也可譯為執(zhí)行環(huán)境
在函數(shù)執(zhí)行時(shí),就會(huì)首先創(chuàng)建執(zhí)行上下文來(lái)運(yùn)行代碼。

活動(dòng)對(duì)象

是根據(jù)(Activation Object)翻譯過(guò)來(lái)的,也可譯為激活的對(duì)象
在函數(shù)執(zhí)行時(shí),創(chuàng)建的變量對(duì)象,不僅含有變量,還有特殊的this,arguments。

閉包

是根據(jù)(closure) 翻譯過(guò)來(lái)的,也可譯為 閉合,使結(jié)束等,我認(rèn)為可以理解為 封閉的環(huán)境
把當(dāng)前作用域外的環(huán)境封閉起來(lái),以備 其他作用域環(huán)境使用。

總結(jié):好多名詞都是英譯過(guò)來(lái)的,看原著或根據(jù)上下文來(lái)理解才是這些單詞真正的意思,只可意會(huì)不可言傳。。。

一、函數(shù)也是引用類型的。

function f(){ console.log("not change") };

var ff = f;
 
function f(){ console.log("changed") };

ff();

//"changed"
//ff 保存著函數(shù) f 的引用,改變f 的值, ff也變了

//來(lái)個(gè)對(duì)比,估計(jì)你就明白了。
var f = "not change";

var ff = f;

f = "changed";

console.log(ff);

//"not change"
//ff 保存著跟 f 一樣的值,改變f 的值, ff 不會(huì)變

其實(shí),就是引用類型 和 基本類型的 區(qū)別。


二、函數(shù)創(chuàng)建一個(gè)參數(shù),就相當(dāng)于在其內(nèi)部聲明了該變量

function f(arg){
    console.log(arg)
}

f();

//undefined

function f(arg){
    arg = 5;
    console.log(arg);
}
f();

//5


三、參數(shù)傳遞,就相當(dāng)于變量復(fù)制(值的傳遞)

基本類型時(shí),變量保存的是數(shù)據(jù),引用類型時(shí),變量保存的是內(nèi)存地址。參數(shù)傳遞,就是把變量保存的值 復(fù)制給 參數(shù)。

var o = { a: 5 };

function f(arg){
    arg.a = 6;
}

f(o);

console.log(o.a);
//6


四、垃圾收集機(jī)制

JavaScript 具有自動(dòng)垃圾收集機(jī)制,執(zhí)行環(huán)境會(huì)負(fù)責(zé)管理代碼執(zhí)行過(guò)程中使用的內(nèi)存。函數(shù)中,正常的局部變量和函數(shù)聲明只在函數(shù)執(zhí)行的過(guò)程中存在,當(dāng)函數(shù)執(zhí)行結(jié)束后,就會(huì)釋放它們所占的內(nèi)存(銷毀變量和函數(shù))。

而js 中 主要有兩種收集方式:

  1. 標(biāo)記清除(常見) //給變量標(biāo)記為“進(jìn)入環(huán)境” 和 “離開環(huán)境”,回收標(biāo)記為“離開環(huán)境”的變量。
  2. 引用計(jì)數(shù) // 一個(gè)引用類型值,被賦值給一個(gè)變量,引用次數(shù)加1,通過(guò)變量取得引用類型值,則減1,回收為次數(shù)為0 的引用類型值。

知道個(gè)大概情況就可以了,《JavaScript高級(jí)程序設(shè)計(jì) 第三版》 4.3節(jié) 有詳解,有興趣,可以看下。.


五、作用域

在 JavaScript 中, 作用域(scope,或譯有效范圍)顧名思義就是變量和函數(shù)的作用范圍(可訪問(wèn)范圍)。

  • 作用域可以實(shí)體化為一個(gè) 可變對(duì)象(Variable Object 變量對(duì)象)

  • JavaScript中的作用域有:全局作用域局部作用域(函數(shù)作用域)。ES6 新增了塊級(jí)作用域

全局作用域(Global Scope)

(1)不在任何函數(shù)內(nèi)定義的變量就具有全局作用域。(非嚴(yán)格模式下)

(2)實(shí)際上,JavaScript默認(rèn)有一個(gè)全局對(duì)象window,全局作用域的變量實(shí)際上被綁定到window的一個(gè)屬性。

局部作用域(Local Scope)

(1)JavaScript的作用域是通過(guò)函數(shù)來(lái)定義的,在一個(gè)函數(shù)中定義的變量只對(duì)這個(gè)函數(shù)內(nèi)部可見,稱為函數(shù)(局部)作用域。

塊級(jí)作用域
塊級(jí)作用域指在If語(yǔ)句,switch語(yǔ)句,循環(huán)語(yǔ)句等語(yǔ)句塊中定義變量,這意味著變量不能在語(yǔ)句塊之外被訪問(wèn)。

六、函數(shù)跟作用域鏈間的關(guān)系

每個(gè)函數(shù)都有一個(gè)[[scope]] 的內(nèi)部屬性(可以通過(guò)console.dir(fn),來(lái)查看),它保存著作用域鏈(一個(gè)對(duì)象數(shù)組),而作用域鏈中是一個(gè)個(gè)可變對(duì)象(Variable Object 變量對(duì)象)(一個(gè)保存當(dāng)前作用域中用到的變量,函數(shù)等的對(duì)象)。當(dāng)函數(shù)創(chuàng)建時(shí),一個(gè)代表全局環(huán)境的可變對(duì)象會(huì)被插入到作用域的第一個(gè)位置。該全局可變對(duì)象保存著window,navigator,document 等。

例如如下 聲明一個(gè)全局函數(shù)

function add(num1, num2) {
    return num1 + num2
}
UTOOLS1575003062214.png

當(dāng)函數(shù)執(zhí)行時(shí),會(huì)創(chuàng)建執(zhí)行上下文(執(zhí)行環(huán)境),隨后創(chuàng)建一個(gè)執(zhí)行上下文對(duì)象,它有自己的作用鏈。剛開始,它會(huì)用函數(shù)自身的 [[scope]] 中的作用域鏈初始化自己(也就是復(fù)制)。

隨后一個(gè)活動(dòng)對(duì)象被創(chuàng)建(也可以說(shuō)是變量對(duì)象,可變對(duì)象),它保存著當(dāng)前函數(shù)作用域里的變量,arguments,this 等。最后,該活動(dòng)對(duì)象會(huì)被推到執(zhí)行上下文的作用域鏈的最前端。

_Blank UML (1).png

注:執(zhí)行上下文(執(zhí)行環(huán)境)在函數(shù)執(zhí)行完畢后就會(huì)被銷毀,里面的作用域鏈,變量,函數(shù),活動(dòng)對(duì)象,this 等也會(huì)一同銷毀。

七、作用域鏈查找

在函數(shù)執(zhí)行過(guò)程中,每遇到一個(gè)變量,都會(huì)經(jīng)歷一次標(biāo)識(shí)符解析過(guò)程以決定從那里獲取存儲(chǔ)數(shù)據(jù)。該過(guò)程搜索執(zhí)行環(huán)境的作用域鏈,查找同名的標(biāo)識(shí)符。搜索過(guò)程從作用域鏈頭部開始也就是當(dāng)前運(yùn)行的作用域。如果找到,就使用這個(gè)標(biāo)識(shí)符對(duì)應(yīng)的變量;如果沒(méi)找到,繼續(xù)搜索作用域鏈中的下一個(gè)對(duì)象。搜索過(guò)程會(huì)持續(xù)進(jìn)行,直到找到標(biāo)識(shí)符,若無(wú)法搜索到匹配的對(duì)象,那么標(biāo)識(shí)符將被視為未定義的。

八、閉包函數(shù) 與 閉包對(duì)象

當(dāng)函數(shù)嵌套時(shí),例如有一個(gè)A函數(shù),內(nèi)部有個(gè)v1 的變量,有一個(gè)B函數(shù),B 中使用了v1 變量。這時(shí),為了讓 B 執(zhí)行時(shí),能訪問(wèn) v1(其實(shí)就是為了形成作用域鏈),會(huì)有以下兩個(gè)變化:

  • 形成一個(gè)閉包函數(shù),生成一個(gè)閉包對(duì)象 A,包含了 B 中用到 v1 變量
  • 在B 閉包函數(shù)的[[scope]] 屬性中 推入 閉包對(duì)象A。
function A(){
    var v1 = 666
    
    function B() {
        return v1
    }
    
    console.dir(B)
    
    B()
}

A()

執(zhí)行結(jié)果,看函數(shù)的[[scope]] 屬性:


UTOOLS1575253977522.png

注:可以通過(guò) debugger 來(lái)在谷歌瀏覽器控制臺(tái)里看。具體怎么用,可以自行百度。

現(xiàn)在來(lái)分析一下過(guò)程:

1、首先,A 函數(shù)執(zhí)行,一開始 它的[[scope]] 內(nèi)的作用域鏈中只有全局的可變對(duì)象,然后 創(chuàng)建一個(gè)執(zhí)行上下文對(duì)象,有一個(gè)作用域鏈,根據(jù) [[scope]] 復(fù)制來(lái) 來(lái)初始化自己。

_Blank UML.png

2、創(chuàng)建 A 函數(shù)的活動(dòng)對(duì)象,并推到 執(zhí)行上下文對(duì)象的作用域鏈中。

UTOOLS1575253109483.png

3、當(dāng)發(fā)現(xiàn) B 中用到 v1 時(shí),B 就會(huì)變成一個(gè)封閉的函數(shù)(閉包函數(shù)),然后,生成一個(gè)關(guān)于A 函數(shù)的封閉對(duì)象(閉包對(duì)象),保存著 v1(因?yàn)樗嬖谟贏,在B中使用)。隨后,把這個(gè)封閉的對(duì)象推到 B 函數(shù) 的[[scope]] 作用域鏈中。

UTOOLS1575250075918.png

注:這時(shí),B 函數(shù)還沒(méi)有執(zhí)行。至于什么機(jī)制導(dǎo)致js 能夠發(fā)現(xiàn)未執(zhí)行的函數(shù)內(nèi)使用了 A 函數(shù)內(nèi)的變量,目前的知識(shí)還得不到答案。

4、當(dāng)B 函數(shù)執(zhí)行時(shí),創(chuàng)建執(zhí)行上下文,創(chuàng)建執(zhí)行上下文對(duì)象,初始化執(zhí)行上下文對(duì)象的作用域鏈(復(fù)制B 函數(shù)的[[scope]] 屬性)。

_Blank UML.png

5、隨后創(chuàng)建一個(gè)活動(dòng)對(duì)象,并推到 執(zhí)行上下文對(duì)象的作用域鏈中。

_Blank UML.png

這樣,B 在執(zhí)行時(shí),就可以訪問(wèn) v1 了,因?yàn)樵谝粋€(gè)作用域鏈中。

下面來(lái)總結(jié)下作用鏈的變化過(guò)程:

  1. 全局下的 A函數(shù)執(zhí)行時(shí),內(nèi)部的[[scope]] 保存的作用域鏈只有一個(gè)全局的變量對(duì)象。創(chuàng)建A 函數(shù)的執(zhí)行上下文對(duì)象,根據(jù) [[scope]] 復(fù)制初始化 A函數(shù)的 執(zhí)行上下文對(duì)象的作用域鏈。
  2. 創(chuàng)建 A 函數(shù)的活動(dòng)對(duì)象,推到 A函數(shù)執(zhí)行上下文對(duì)象的作用域鏈前端。
  3. 當(dāng)發(fā)現(xiàn) A 函數(shù)內(nèi)部(不管層級(jí)多深)有 一個(gè)函數(shù)使用了 A函數(shù)內(nèi)變量或函數(shù)
  4. A 內(nèi)(不管層級(jí)多深)所有函數(shù) 都會(huì)形成 閉包函數(shù)
  5. 然后創(chuàng)建一個(gè)關(guān)于 A 的閉包對(duì)象,對(duì)象內(nèi)含有被使用的變量或函數(shù)(通過(guò)復(fù)制)。
  6. 最后把該閉包對(duì)象 推到 所有閉包函數(shù)的 [[scope]] 內(nèi)

可以得出以下結(jié)論:

  • 有兩個(gè)作用域鏈,一個(gè)存與函數(shù)的[[scope]] 中,用來(lái)保存作用域,以備執(zhí)行上下文對(duì)象初始化自身作用域鏈。
  • 執(zhí)行上下文對(duì)象中的作用域鏈,會(huì)添加活動(dòng)函數(shù),作用域鏈的查找,查的就是這條作用域鏈。(一般我們說(shuō)的作用域鏈就是指這條)
  • 活動(dòng)函數(shù)只會(huì)存在于執(zhí)行上下文對(duì)象的作用域鏈中。
  • 有閉包函數(shù)和閉包對(duì)象,閉包函數(shù)的[[scope]] 保存閉包對(duì)象,而閉包對(duì)象,封閉的是 父或祖級(jí)函數(shù)作用域中的變量或?qū)ο?/strong>。
  • 閉包函數(shù)的存在是因?yàn)?執(zhí)行上下文環(huán)境 會(huì)在執(zhí)行完后銷毀,而其中的作用域鏈,活動(dòng)對(duì)象,變量等等就丟失了,通過(guò)閉包函數(shù) 就可以保存著作用域鏈,而鏈中的變量對(duì)象又保存著變量,函數(shù)等。

來(lái)一個(gè)難一點(diǎn)的例子,大家可以先自己分析分析。

function A(){
  var va = 'aaa'
  
  function B() {
    var vb = 'bbb'

    function C() {
      var vc1 = 'ccc'

      return va
    }

    function D() {
      var vd = 'ddd'
      
      return vb
    }

    console.dir(C)
    console.dir(D)

    C()

  }
  
  console.dir(B)

  function E () {
    var vd = 'eee'
  }

  console.dir(E)

  B()
}

console.dir(A)

A()

根據(jù)上面分析,可以得出各個(gè)函數(shù)的[[scope]]:

  • A 只有一個(gè)全局變量對(duì)象
  • B 和 E 有兩個(gè)變量對(duì)象,關(guān)于 A 的閉包對(duì)象,全局變量對(duì)象。
  • C 和 D 有三個(gè)變量對(duì)象,關(guān)于 B 的閉包對(duì)象,關(guān)于 A 的閉包對(duì)象,全局變量對(duì)象。

控制臺(tái):


未標(biāo)題-1.png

通過(guò) debugger 來(lái)單步調(diào)試,無(wú)非就是能看到每個(gè)執(zhí)行環(huán)境內(nèi)的作用域鏈中 含有 活動(dòng)對(duì)象。

有興趣的可以試試。

至于閉包的內(nèi)存泄漏,這里面牽扯到 js 的垃圾回收機(jī)制。不過(guò)可以看到,[[scope]] 中保存著 變量,如果 該變量 占的內(nèi)存不被釋放,一旦這樣的情況過(guò)多,內(nèi)存占用過(guò)大,就會(huì)造成內(nèi)存泄漏 和 性能問(wèn)題。

九、閉包的概念

一般說(shuō)的閉包指的都是閉包函數(shù)。

引用高程(《JavaScript高級(jí)程序設(shè)計(jì)》)中關(guān)于閉包說(shuō)法:

閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中變量的函數(shù)

通過(guò)上面說(shuō)的那么多,你品,你細(xì)品。。。


十、閉包的本質(zhì)

我認(rèn)為就是為了形成作用域鏈。你品,你細(xì)品。。。

再來(lái)個(gè)有趣經(jīng)典的例子:

function timer () {
  for (var i=1; i<=5; i++) {
    setTimeout(function(){
      console.log(i);
    },i*1000);
  }
}

timer()

//每隔一秒輸出一個(gè)6,共5個(gè)。

是不是跟你想的不一樣?其實(shí),這個(gè)例子重點(diǎn)就在setTimeout函數(shù)上,這個(gè)函數(shù)的第一個(gè)參數(shù)接受一個(gè)函數(shù)作為回調(diào)函數(shù),這個(gè)回調(diào)函數(shù)并不會(huì)立即執(zhí)行,它會(huì)在當(dāng)前代碼執(zhí)行完,并在給定的時(shí)間后執(zhí)行。這樣就導(dǎo)致了上面情況的發(fā)生。

注:這里用一個(gè)函數(shù)包裹起來(lái)了,這樣,你可以通過(guò) debugger,會(huì)發(fā)現(xiàn),這里也形成閉包了。閉包函數(shù)是每一個(gè)匿名函數(shù),閉包對(duì)象是是關(guān)于timer 的,保存著變量 i

可以下面對(duì)這個(gè)例子進(jìn)行變形,可以有助于你的理解把:

function timer () {
  var i = 1;
  while(i <= 5){
    setTimeout(function(){
      console.log(i);
    },i*1000)

    i = i+1;
  }
}

timer()

正因?yàn)椋?code>setTimeout里的第一個(gè)函數(shù)不會(huì)立即執(zhí)行,當(dāng)這段代碼執(zhí)行完之后,i 已經(jīng) 被賦值為6了(等于5時(shí),進(jìn)入循環(huán),最后又加了1),所以 這時(shí)再執(zhí)行setTimeout 的回調(diào)函數(shù),讀取 i 的值,回調(diào)函數(shù)作用域內(nèi)沒(méi)有i,向上讀取,上級(jí)作用域內(nèi)i的值就是6了。但是 i * 1000,是立即執(zhí)行的,所以,每次讀的 i 值 都是對(duì)的。

這時(shí)候,就需要再用個(gè)閉包函數(shù)來(lái)保存每個(gè)循環(huán)時(shí) i 不同的值。

function makeClosures(i){     // 這個(gè)函數(shù)使用了 上級(jí)作用域中的 `i`,形成閉包函數(shù)。
    var i = i;    //這步是不需要的,為了讓看客們看的輕松點(diǎn)
    return function(){
        console.log(i);     //匿名沒(méi)有執(zhí)行,它可以訪問(wèn)i 的值,保存著這個(gè)i 的值。
    }
}

function timer() {
  for (var i=1; i<=5; i++) {
    setTimeout(makeClosures(i),i*1000);  
    
    //這里簡(jiǎn)單說(shuō)下,這里makeClosures(i), 是函數(shù)執(zhí)行,并不是傳參,不是一個(gè)概念
    //每次循環(huán)時(shí),都執(zhí)行了makeClosures函數(shù),形成一個(gè)閉包函數(shù),保存含有 `i` 的閉包對(duì)象(這個(gè)例子就是 5個(gè) 閉包函數(shù)保存各自的閉包對(duì)象)。
    //然后每次都返回了一個(gè)沒(méi)有被執(zhí)行的匿名函數(shù),(這里就是返回了5個(gè)匿名函數(shù))。
    //每個(gè)匿名函數(shù)都是一個(gè)局部作用域,它的上級(jí)作用域就是 makeClosures 閉包函數(shù)。
    //因此,每個(gè)匿名函數(shù)執(zhí)行時(shí),讀取`i`值,都是上級(jí)作用域內(nèi)保存的值,是不一樣的。所以,就得到了想要的結(jié)果
  }
}

timer()

//1
//2
//3
//4
//5

你可能在別處,或者自己想到了下面這種解法:

for (var i=1; i<=5; i++) {
    (function(i){
        setTimeout(function(){
            console.log(i);
        },i*1000);
    })(i);
}

這個(gè)例子不僅利用了閉包,而且還利用了立即執(zhí)行函數(shù) 來(lái)模擬 函數(shù)作用域 來(lái)解決的。

做下變形,你再看看:

for (var i=1; i<=5; i++) {
    function f(i){
        setTimeout(function(){
            console.log(i);
        },i*1000);
    };
    
    f(i);
}




附錄:

其實(shí)這道題,知道ES6let 關(guān)鍵詞,估計(jì)也想到了另一個(gè)解法:

for (let i=1; i<=5; i++) {   //這里的關(guān)鍵就是使用的let 關(guān)鍵詞,來(lái)形成塊級(jí)作用域
    setTimeout(function(){
        console.log(i);
    },i*1000);
}

我不知道,大家有沒(méi)有疑惑啊,為啥使用了塊級(jí)作用域就可以了呢。反正我當(dāng)初就糾結(jié)了半天。

18年 11月 2日修正:

這個(gè)答案的關(guān)鍵就在于 塊級(jí)作用域的規(guī)則了。它讓let聲明的變量只在{}內(nèi)有效,外部是訪問(wèn)不了的。

做下變形,這個(gè)是為了方便理解的,事實(shí)并非如此:

for (var i=1; i<=5; i++) {
    let j = i;
    setTimeout(function(){
        console.log(j);
    },j*1000);
}

當(dāng)for 的() 內(nèi)使用 let時(shí),for 循環(huán)就存在兩個(gè)作用域,() 括號(hào)里的父作用域,和 {} 中括號(hào)里的 子作用域。

每次循環(huán)都會(huì)創(chuàng)建一個(gè) 子作用域。保存著父作用域傳來(lái)的值,這樣,每個(gè)子作用域內(nèi)的值都是不同的。當(dāng)setTimeout 的匿名函數(shù)執(zhí)行時(shí),自己的作用域沒(méi)有i 的值,向上讀取到了該 子作用域i 值。因此每次的值才會(huì)不一樣。

你要是喜歡折騰,你會(huì)發(fā)現(xiàn),塊級(jí)作用域的表現(xiàn)跟函數(shù)作用域一樣,子作用域中使用它的變量,它也會(huì)形成一個(gè)塊級(jí)對(duì)象,被寫入到 函數(shù)的 [[scope]] 中。

最后編輯于
?著作權(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,156評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,401評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,069評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,635評(píng)論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,128評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,365評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,881評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,733評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,935評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,172評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,595評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,908評(píng)論 2 372

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