你不懂JS:作用域與閉包 第二章:詞法作用域

官方中文版原文鏈接

感謝社區(qū)中各位的大力支持西土,譯者再次奉上一點(diǎn)點(diǎn)福利:阿里云產(chǎn)品券讶舰,享受所有官網(wǎng)優(yōu)惠,并抽取幸運(yùn)大獎(jiǎng):點(diǎn)擊這里領(lǐng)取

在第一章中需了,我們將“作用域”定義為一組規(guī)則跳昼,它主宰著 引擎 如何通過標(biāo)識符名稱在當(dāng)前的 作用域,或者在包含它的任意 嵌套作用域 中來查詢一個(gè)變量肋乍,

作用域的工作方式有兩種占統(tǒng)治地位的模型鹅颊。其中的第一種是最最常見,在絕大多數(shù)的編程語言中被使用的住拭。它稱為 詞法作用域挪略,我們將深入檢視它。另一種仍然被一些語言(比如Bash腳本滔岳,Perl中的一些模式杠娱,等等)使用的模型,稱為 動(dòng)態(tài)作用域谱煤。

動(dòng)態(tài)作用域在附錄A中講解摊求。我在這里提到它僅僅是為詞法作用域提供一個(gè)對比,而詞法作用域是JavaScript采用的作用域模型刘离。

詞法分析時(shí)

正如我們在第一章中討論的室叉,標(biāo)準(zhǔn)語言編譯器的第一個(gè)傳統(tǒng)步驟稱為詞法分析(也就是分詞)。如果你回憶一下硫惕,詞法分析處理是檢查一串源代碼字符茧痕,并給token賦予語法含義作為某種有狀態(tài)解析的輸出。

正是這個(gè)概念給理解詞法作用域是什么提供了基礎(chǔ)恼除,也是這個(gè)名詞的淵源踪旷。

要定義它有點(diǎn)兒兜圈子曼氛,詞法作用域是在詞法分析時(shí)被定義的作用域。換句話說令野,詞法作用域是基于舀患,你,在寫程序時(shí)气破,變量和作用域的塊兒在何處被編寫決定的聊浅,因此它在詞法分析器處理你的代碼時(shí)(基本上)是固定不變的。

注意: 我們將會稍稍看到有一些方法可以騙過詞法作用域现使,從而在詞法分析器處理過后改變它低匙,但是這些方法都是使人皺眉頭的。事實(shí)上公認(rèn)的最佳實(shí)踐是朴下,將詞法作用域看作是僅僅依靠詞法的努咐,因此在本質(zhì)上完全是編寫時(shí)決定的。

讓我們考慮這段代碼:

function foo(a) {

    var b = a * 2;

    function bar(c) {
        console.log( a, b, c );
    }

    bar(b * 3);
}

foo( 2 ); // 2 4 12

在這個(gè)代碼實(shí)例中有三個(gè)固有的嵌套作用域殴胧。將這些作用域考慮為套在一起的氣泡可能有助于思考。

fig2.png

氣泡1 包圍著全局作用域佩迟,它里面只有一個(gè)標(biāo)識符:foo团滥。

氣泡2 包圍著作用域foo,它含有三個(gè)標(biāo)識符:a报强,barb灸姊。

氣泡3 包圍著作用域bar,它里面只包含一個(gè)標(biāo)識符:c秉溉。

作用域氣泡是根據(jù)作用域的塊兒被寫在何處定義的力惯,一個(gè)嵌套在另一個(gè)內(nèi)部,等等召嘶。在下一章中父晶,我們將討論作用域的不同單位,但是就現(xiàn)在來說弄跌,讓我們認(rèn)為每一個(gè)函數(shù)創(chuàng)建了一個(gè)新的作用域氣泡甲喝。

bar的氣泡完全被包含在foo的氣泡中,因?yàn)椋ǘ抑灰驗(yàn)椋┻@就是我們選擇定義函數(shù)bar的位置铛只。

注意這些嵌套的氣泡是嚴(yán)格嵌套的埠胖。我們沒有討論氣泡可以跨越邊界的維恩圖(Venn diagrams)。換句話說淳玩,沒有那個(gè)函數(shù)的氣泡可以同時(shí)(部分地)存在于另外兩個(gè)外部的作用域氣泡中直撤,就像沒有函數(shù)可以部分地存在于它的兩個(gè)父函數(shù)中一樣。

查詢

這些作用域氣泡的結(jié)構(gòu)和相對位置完全解釋了 引擎 在查找一個(gè)標(biāo)識符時(shí)蜕着,它需要查看的所有地方谋竖。

在上面的代碼段中,引擎 執(zhí)行語句console.log(..)并開始查找三個(gè)被引用的變量abc圈盔。它首先從最內(nèi)部的作用域氣泡開始豹芯,也就是bar(..)函數(shù)的作用域。在這里它找不到a驱敲,所以它向上走一層铁蹈,到外面下一個(gè)最近的作用域氣泡,foo(..)的作用域众眨。它在這里找到了a握牧,于是它就使用這個(gè)a。同樣的事情也發(fā)生在b上娩梨。但是對于c沿腰,它在bar(..)內(nèi)部就找到了。

如果在bar(..)內(nèi)部和foo(..)內(nèi)部都有一個(gè)c狈定,那么console.log(..)語句將會找到并使用bar(..)中的那一個(gè)颂龙,絕不會到達(dá)foo(..)中的那一個(gè)。

一旦找到第一個(gè)匹配纽什,作用域查詢就停止了措嵌。相同的標(biāo)識符名稱可以在嵌套作用域的多個(gè)層中被指定,這稱為“遮蔽(shadowing)”(內(nèi)部的標(biāo)識符“遮蔽”了外部的標(biāo)識符)芦缰。無論如何遮蔽企巢,作用域查詢總是從當(dāng)前被執(zhí)行的最內(nèi)側(cè)的作用域開始,向外/向上不斷查找让蕾,直到第一個(gè)匹配才停止浪规。

注意: 全局變量也自動(dòng)地是全局對象(在瀏覽器中是window,等等)的屬性探孝,所以不直接通過全局變量的詞法名稱笋婿,而通過將它作為全局對象的一個(gè)屬性引用來間接地引用,是可能的再姑。

window.a

這種技術(shù)給出了訪問全局變量的方法萌抵,沒有它全局變量將因?yàn)楸徽诒味豢稍L問。然而元镀,被遮蔽的非全局變量是無法訪問的绍填。

不管函數(shù)是從 哪里 被調(diào)用的,也不論它是 如何 被調(diào)用的栖疑,它的詞法作用域是由這個(gè)函數(shù)被聲明的位置 唯一 定義的讨永。

詞法作用域查詢 僅僅 在處理頭等標(biāo)識符時(shí)實(shí)施,比如a遇革,b卿闹,和c揭糕。如果你在一段代碼中擁有一個(gè)foo.bar.baz的引用,詞法作用域查詢將在查找foo標(biāo)識符時(shí)實(shí)施锻霎,但一旦定位這個(gè)變量著角,對象屬性訪問規(guī)則將會分別接管barbaz屬性的解析。

欺騙詞法作用域

如果詞法作用域僅僅是由函數(shù)被聲明的位置定義的旋恼,而且這個(gè)位置完全是一個(gè)編寫時(shí)的決定吏口,那么怎么可能有辦法在運(yùn)行時(shí)“修改”(也就是,作弊欺騙)詞法作用域呢冰更?

JavaScript有兩種這樣的機(jī)制产徊。在廣大的社區(qū)中它們都等同地被認(rèn)為是讓人皺眉頭的,在你代碼中使用它們是一種差勁兒的做法蜀细。但是關(guān)于它們的具有代表性的爭論經(jīng)常錯(cuò)過了最重要的一點(diǎn):欺騙詞法作用域會導(dǎo)致更低下的性能舟铜。

在我講解性能的問題以前,先讓我們看看這兩種機(jī)制是如何工作的奠衔。

eval

JavaScript中的eval(..)函數(shù)接收一個(gè)字符串作為參數(shù)值谆刨,并將這個(gè)字符串的內(nèi)容看作是好像它已經(jīng)被實(shí)際編寫在程序的那個(gè)位置上。換句話說涣觉,你可以用編程的方式在你編寫好的代碼內(nèi)部生成代碼痴荐,而且你可以運(yùn)行這個(gè)生成的代碼,就好像它在編寫時(shí)就已經(jīng)在那里了一樣官册。

如果以這種觀點(diǎn)來評價(jià)eval(..),那么eval(..)是如何允許你修改詞法作用域環(huán)境應(yīng)當(dāng)是很清楚的:欺騙并假裝這個(gè)編寫時(shí)(也就是难捌,詞法)代碼一直就在那里膝宁。

eval(..)被執(zhí)行的后續(xù)代碼行中,引擎 將不會“知道”或“關(guān)心”前面的代碼是被動(dòng)態(tài)翻譯的根吁,而且因此修改了詞法作用域環(huán)境员淫。引擎 將會像它一直做的那樣,簡單地進(jìn)行詞法作用域查詢击敌。

考慮如下代碼:

function foo(str, a) {
    eval( str ); // 作弊介返!
    console.log( a, b );
}

var b = 2;

foo( "var b = 3;", 1 ); // 1, 3

eval(..)調(diào)用的位置上,字符串"var b = 3"被看作是一直就存在在那里的代碼沃斤。因?yàn)檫@個(gè)代碼恰巧聲明了一個(gè)新的變量b圣蝎,它就修改了現(xiàn)存的foo(..)的詞法作用域。事實(shí)上衡瓶,就像上面提到的那樣徘公,這個(gè)代碼實(shí)際上在foo(..)內(nèi)部創(chuàng)建了變量b,它遮蔽了聲明在外部(全局)作用域中的b哮针。

當(dāng)console.log(..)調(diào)用發(fā)生時(shí)关面,它會在foo(..)的作用域中找到ab坦袍,而且絕不會找到外部的b。這樣等太,我們就打印出"1, 3"而不是一般情況下的"1, 2"捂齐。

注意: 在這個(gè)例子中,為了簡單起見缩抡,我們傳入的“代碼”字符串是固定的文字奠宜。但是它可以通過根據(jù)你的程序邏輯將字符拼接在一起,很容易地以編程方式創(chuàng)建缝其。eval(..)通常被用于執(zhí)行動(dòng)態(tài)創(chuàng)建的代碼挎塌,因?yàn)閯?dòng)態(tài)地對一段實(shí)質(zhì)上源自字符串字面值的靜態(tài)代碼進(jìn)行求值,并不會比直接編寫這樣的代碼帶來更多真正的好處内边。

默認(rèn)情況下榴都,如果eval(..)執(zhí)行的代碼字符串包含一個(gè)或多個(gè)聲明(變量或函數(shù))的話,這個(gè)動(dòng)作就會修改這個(gè)eval(..)所在的詞法作用域漠其。技術(shù)上講嘴高,eval(..)可以通過種種技巧(超出了我們這里的討論范圍)被“間接”調(diào)用,而使它在全局作用域的上下文中執(zhí)行和屎,如此修改全局作用域拴驮。但不論那種情況,eval(..)都可以在運(yùn)行時(shí)修改一個(gè)編寫時(shí)的詞法作用域柴信。

注意: 當(dāng)eval(..)被用于一個(gè)操作它自己的詞法作用域的strict模式程序時(shí)套啤,在eval(..)內(nèi)部做出的聲明不會實(shí)際上修改包圍它的作用域。

function foo(str) {
   "use strict";
   eval( str );
   console.log( a ); // ReferenceError: a is not defined
}

foo( "var a = 2" );

在JavaScript中還有其他的工具擁有與eval(..)非常類似的效果随常。setTimeout(..)setInterval(..)可以 為它們各自的第一個(gè)參數(shù)值接收一個(gè)字符串潜沦,其內(nèi)容將會被eval為一個(gè)動(dòng)態(tài)生成的函數(shù)的代碼。這種老舊的绪氛,遺產(chǎn)行為早就被廢棄了唆鸡。別這么做!

new Function(..)函數(shù)構(gòu)造器類似地為它的 最后 一個(gè)參數(shù)值接收一個(gè)代碼字符串枣察,來把它轉(zhuǎn)換為一個(gè)動(dòng)態(tài)生成的函數(shù)(前面的參數(shù)值争占,如果有的話,將作為新函數(shù)的命名參數(shù))序目。這種函數(shù)構(gòu)造器語法要比eval(..)稍稍安全一些臂痕,但在你的代碼中它仍然應(yīng)當(dāng)被避免。

在你的代碼中動(dòng)態(tài)生成代碼的用例少的不可思議宛琅,因?yàn)樵谛阅苌系牡雇耸沟眠@種能力幾乎總是得不償失刻蟹。

with

JavaScript的另一個(gè)使人皺眉頭(而且現(xiàn)在被廢棄了!)嘿辟,而且可以欺騙詞法作用域的特性是with關(guān)鍵字舆瘪。有許多種合法的方式可以講解with片效,但是我在此選擇從它如何與詞法作用域互動(dòng)并影響詞法作用域的角度來講解它。

講解with的典型方式是作為一種縮寫英古,來引用一個(gè)對象的多個(gè)屬性淀衣,而 不必 每次都重復(fù)對象引用本身忌傻。

例如:

var obj = {
    a: 1,
    b: 2,
    c: 3
};

//  重復(fù)“obj”顯得更“繁冗”
obj.a = 2;
obj.b = 3;
obj.c = 4;

// “更簡單”的縮寫
with (obj) {
    a = 3;
    b = 4;
    c = 5;
}

然而扔罪,這里發(fā)生的事情要比只是一個(gè)對象屬性訪問的便捷縮寫要多得多≌闾撸考慮如下代碼:

function foo(obj) {
    with (obj) {
        a = 2;
    }
}

var o1 = {
    a: 3
};

var o2 = {
    b: 3
};

foo( o1 );
console.log( o1.a ); // 2

foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2 -- 哦唠叛,全局作用域被泄漏了只嚣!

在這個(gè)代碼示例中,創(chuàng)建了兩個(gè)對象o1o2艺沼。一個(gè)有a屬性册舞,而另一個(gè)沒有。foo(..)函數(shù)接收一個(gè)對象引用obj作為參數(shù)值障般,并在這個(gè)引用上調(diào)用with (obj) {..}调鲸。在with塊兒內(nèi)部,我們制造了一個(gè)變量a的看似是普通詞法引用的東西挽荡,實(shí)際上是一個(gè)LHS引用(見第一章)藐石,并將值2賦予它。

當(dāng)我們傳入o1時(shí)定拟,賦值a = 2找到屬性o1.a并賦予它值2于微,正如在后續(xù)的console.log(o1.a)語句反應(yīng)的那樣。然而青自,當(dāng)我們傳入o2角雷,因?yàn)樗鼪]有a屬性,沒有這樣的屬性被創(chuàng)建性穿,所以o2.a還是undefined

但是之后我們注意到一個(gè)特別的副作用雷滚,賦值a = 2創(chuàng)建了一個(gè)全局變量a需曾。這怎么可能?

with語句接收一個(gè)對象祈远,這個(gè)對象有0個(gè)或多個(gè)屬性呆万,并 將這個(gè)對象視為好像它是一個(gè)完全隔離的詞法作用域,因此這個(gè)對象的屬性被視為在這個(gè)“作用域”中詞法定義的標(biāo)識符车份。

注意: 盡管一個(gè)with塊兒將一個(gè)對象視為一個(gè)詞法作用域谋减,但是在with塊兒內(nèi)部的一個(gè)普通var聲明將不會歸于這個(gè)with塊兒的作用域,而是歸于包含它的函數(shù)作用域扫沼。

如果eval(..)函數(shù)接收一個(gè)含有一個(gè)或多個(gè)聲明的代碼字符串出爹,它就會修改現(xiàn)存的詞法作用域庄吼,而with語句實(shí)際上是從你傳遞給它的對象中憑空制造了一個(gè) 全新的詞法作用域

以這種方式理解的話严就,當(dāng)我們傳入o1時(shí)with語句聲明的“作用域”就是o1总寻,而且這個(gè)“作用域”擁有一個(gè)對應(yīng)于o1.a屬性的“標(biāo)識符”。但當(dāng)我們使用o2作為“作用域”時(shí)梢为,它里面沒有這樣的a“標(biāo)識符”渐行,于是LHS標(biāo)識符查詢(見第一章)的普通規(guī)則發(fā)生了。

“作用域”o2中沒有铸董,foo(..)的作用域中也沒有祟印,甚至連全局作作用域中都沒有找到標(biāo)識符a,所以當(dāng)a = 2被執(zhí)行時(shí)粟害,其結(jié)果就是自動(dòng)全局變量被創(chuàng)建(因?yàn)槲覀儧]有在strict模式下)蕴忆。

with在運(yùn)行時(shí)將一個(gè)對象和它的屬性轉(zhuǎn)換為一個(gè)帶有“標(biāo)識符”的“作用域”,這個(gè)奇怪想法有些燒腦我磁。但是對于我們看到的結(jié)果來說孽文,這是我能給出的最清晰的解釋。

注意: 除了使用它們是個(gè)壞主意意外夺艰,eval(..)with都受Strict模式的影響(制約)芋哭。with干脆就不允許使用,而雖然eval(..)還保有其核心功能郁副,但各種間接形式的或不安全的eval(..)是不允許的减牺。

性能

通過在運(yùn)行時(shí)修改,或創(chuàng)建新的詞法作用域存谎,eval(..)with都可以欺騙編寫時(shí)定義的詞法作用域拔疚。

你可能會問,那又有什么大不了的既荚?如果它們提供了更精巧的功能和編碼靈活性稚失,那它們不是 好的 特性嗎?不恰聘。

JavaScript 引擎 在編譯階段期行許多性能優(yōu)化工作句各。其中的一些優(yōu)化原理都?xì)w結(jié)為實(shí)質(zhì)上在進(jìn)行詞法分析時(shí)可以靜態(tài)地分析代碼,并提前決定所有的變量和函數(shù)聲明都在什么位置晴叨,這樣在執(zhí)行期間就可以少花些力氣來解析標(biāo)識符凿宾。

但如果 引擎 在代碼中找到一個(gè)eval(..)with,它實(shí)質(zhì)上就不得不 假定 自己知道的所有的標(biāo)識符的位置可能是不合法的兼蕊,因?yàn)樗豢赡茉谠~法分析時(shí)就知道你將會向eval(..)傳遞什么樣的代碼來修改詞法作用域初厚,或者你可能會向with傳遞的對象有什么樣的內(nèi)容來創(chuàng)建一個(gè)新的將被查詢的詞法作用域。

換句話說孙技,悲觀地看产禾,如果eval(..)with出現(xiàn)排作,那么它 做的幾乎所有的優(yōu)化都會變得沒有意義,所以它就會簡單地根本不做任何優(yōu)化下愈。

你的代碼幾乎肯定會趨于運(yùn)行的更慢纽绍,只因?yàn)槟阍诖a的任何地方引入了一個(gè)了eval(..)with。無論 引擎 將在努力限制這些悲觀臆測的副作用上表現(xiàn)得多么聰明势似,都沒有任何辦法可以繞過這個(gè)事實(shí):沒有優(yōu)化拌夏,代碼就運(yùn)行的更慢。

復(fù)習(xí)

詞法作用域意味著作用域是由編寫時(shí)函數(shù)被聲明的位置的決策定義的履因。編譯器的詞法分析階段實(shí)質(zhì)上可以知道所有的標(biāo)識符是在哪里和如何聲明的障簿,并如此在執(zhí)行期間預(yù)測它們將如何被查詢。

在JavaScript中有兩種機(jī)制可以“欺騙”詞法作用域:eval(..)with栅迄。前者可以通過對一個(gè)擁有一個(gè)或多個(gè)聲明的“代碼”字符串進(jìn)行求值站故,來(在運(yùn)行時(shí))修改現(xiàn)存的詞法作用域。后者實(shí)質(zhì)上是通過將一個(gè)對象引用看作一個(gè)“作用域”毅舆,并將這個(gè)對象的屬性看作作用域中的標(biāo)識符西篓,(同樣,也是在運(yùn)行時(shí))創(chuàng)建一個(gè)全新的詞法作用域憋活。

這些機(jī)制的缺點(diǎn)是岂津,它壓制了 引擎 在作用域查詢上進(jìn)行編譯期優(yōu)化的能力,因?yàn)?引擎 不得不悲觀地假定這樣的優(yōu)化是不合法的悦即。這兩種特性的結(jié)果就是代碼 會運(yùn)行的更慢吮成。不要使用它們。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辜梳,一起剝皮案震驚了整個(gè)濱河市粱甫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌作瞄,老刑警劉巖茶宵,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異宗挥,居然都是意外死亡节预,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門属韧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蛤吓,你說我怎么就攤上這事宵喂。” “怎么了会傲?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵锅棕,是天一觀的道長拙泽。 經(jīng)常有香客問我,道長裸燎,這世上最難降的妖魔是什么顾瞻? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮德绿,結(jié)果婚禮上荷荤,老公的妹妹穿的比我還像新娘。我一直安慰自己移稳,他們只是感情好蕴纳,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著个粱,像睡著了一般古毛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上都许,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天稻薇,我揣著相機(jī)與錄音,去河邊找鬼胶征。 笑死塞椎,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的弧烤。 我是一名探鬼主播忱屑,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼暇昂!你這毒婦竟也來了莺戒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤急波,失蹤者是張志新(化名)和其女友劉穎从铲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澄暮,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡名段,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了泣懊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片伸辟。...
    茶點(diǎn)故事閱讀 38,163評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖馍刮,靈堂內(nèi)的尸體忽然破棺而出信夫,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布静稻,位于F島的核電站警没,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏振湾。R本人自食惡果不足惜杀迹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望押搪。 院中可真熱鬧树酪,春花似錦、人聲如沸嵌言。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摧茴。三九已至绵载,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間苛白,已是汗流浹背娃豹。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留购裙,地道東北人懂版。 一個(gè)月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像躏率,于是被迫代替她去往敵國和親躯畴。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評論 2 344

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