ES2018 最新 理解Javascript中的執(zhí)行上下文和執(zhí)行棧

寫(xiě)在前頭

最近看執(zhí)行上下文吞滞,一直沒(méi)有找到很好的文章或者書(shū)籍。大多數(shù)都是ES3的舊解釋了扁凛。

執(zhí)行上下文在 ES3 中忍疾,包含三個(gè)部分。

scope:作用域谨朝,也常常被叫做作用域鏈卤妒。

variable object:變量對(duì)象,用于存儲(chǔ)變量的對(duì)象字币。

this value:this 值则披。

在 ES5 中,我們改進(jìn)了命名方式洗出,把執(zhí)行上下文最初的三個(gè)部分改為下面這個(gè)樣子士复。

lexical environment:詞法環(huán)境,當(dāng)獲取變量時(shí)使用翩活。

variable environment:變量環(huán)境阱洪,當(dāng)聲明變量時(shí)使用。

this value:this 值菠镇。

在 ES2018 中冗荸,執(zhí)行上下文又變成了這個(gè)樣子,this 值被歸入 lexical environment利耍,但是增加了不少內(nèi)容蚌本。

lexical environment:詞法環(huán)境,當(dāng)獲取變量或者 this 值時(shí)使用隘梨。

variable environment:變量環(huán)境程癌,當(dāng)聲明變量時(shí)使用

code evaluation state:用于恢復(fù)代碼執(zhí)行位置。

Function:執(zhí)行的任務(wù)是函數(shù)時(shí)使用轴猎,表示正在被執(zhí)行的函數(shù)席楚。

ScriptOrModule:執(zhí)行的任務(wù)是腳本或者模塊時(shí)使用,表示正在被執(zhí)行的代碼税稼。

Realm:使用的基礎(chǔ)庫(kù)和內(nèi)置對(duì)象實(shí)例烦秩。

Generator:僅生成器上下文有這個(gè)屬性,表示當(dāng)前生成器郎仆。

下面是我推薦的不同版本的執(zhí)行上下文的文章

  • ES3

冴羽老師的
JavaScript深入之執(zhí)行上下文

  • ES5

掘金翻譯計(jì)劃
[譯] 理解 JavaScript 中的執(zhí)行上下文和執(zhí)行棧

  • ES2018

原文地址:Understanding Execution Context and Execution Stack in Javascript (要翻墻) 下面的內(nèi)容就是我翻譯的這篇文章(四級(jí)水平加機(jī)翻只祠,yyds)

了解JavaScript程序是如何內(nèi)部執(zhí)行的

如果您是或想成為一名JavaScript開(kāi)發(fā)人員,那么您必須知道JavaScript程序是如何在內(nèi)部執(zhí)行的扰肌。理解執(zhí)行上下文和執(zhí)行堆棧對(duì)于理解其他JavaScript概念(如提升抛寝、作用域和閉包)至關(guān)重要。

正確理解執(zhí)行上下文和執(zhí)行堆棧的概念將使您成為更好的JavaScript開(kāi)發(fā)人員曙旭。

閑話少說(shuō)盗舰,讓我們開(kāi)始吧:)

什么是執(zhí)行上下文?

簡(jiǎn)單地說(shuō),執(zhí)行上下文是評(píng)估和執(zhí)行Javascript代碼的環(huán)境的一個(gè)抽象概念桂躏。任何代碼在JavaScript中運(yùn)行時(shí)钻趋,都在執(zhí)行上下文中運(yùn)行。

執(zhí)行上下文的類型(Types of Execution Context)

在JavaScript中有三種類型的執(zhí)行上下文剂习。

  • 全局執(zhí)行上下文——這是默認(rèn)的或基本的執(zhí)行上下文蛮位。任何不在函數(shù)內(nèi)部的代碼位于全局執(zhí)行上下文中。它執(zhí)行兩件事:它創(chuàng)建一個(gè)全局對(duì)象鳞绕,它是一個(gè)window對(duì)象(在瀏覽器的情況下)失仁,并將this的值設(shè)置為等于全局對(duì)象。一個(gè)程序中只能有一個(gè)全局執(zhí)行上下文们何。

  • 函數(shù)執(zhí)行上下文——每次調(diào)用函數(shù)時(shí)萄焦,都會(huì)為該函數(shù)創(chuàng)建一個(gè)全新的執(zhí)行上下文。每個(gè)函數(shù)都有自己的執(zhí)行上下文冤竹,但它是在調(diào)用或調(diào)用(原文是it’s created when the function is invoked or called)函數(shù)時(shí)創(chuàng)建的拂封。可以有任意數(shù)量的函數(shù)執(zhí)行上下文贴见。每當(dāng)創(chuàng)建一個(gè)新的執(zhí)行上下文時(shí)烘苹,它都會(huì)按照已定義的順序執(zhí)行一系列步驟,我將在本文后面討論這些步驟片部。

  • Eval函數(shù)執(zhí)行上下文——在Eval函數(shù)內(nèi)部執(zhí)行的代碼也會(huì)獲得它自己的執(zhí)行上下文镣衡,但JavaScript開(kāi)發(fā)人員通常不使用Eval,所以我在這里不討論它档悠。

執(zhí)行棧(Execution Stack)

執(zhí)行棧廊鸥,在其他編程語(yǔ)言中也被稱為“調(diào)用棧”辖所,是一個(gè)具有后進(jìn)先出結(jié)構(gòu)的棧惰说,它用于存儲(chǔ)代碼執(zhí)行期間創(chuàng)建的所有執(zhí)行上下文。

當(dāng)JavaScript引擎第一次遇到腳本時(shí)缘回,它會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文吆视,并將其推入當(dāng)前執(zhí)行棧典挑。每當(dāng)引擎發(fā)現(xiàn)一個(gè)函數(shù)調(diào)用時(shí),它就會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文啦吧,并將其推到棧的頂部您觉。

引擎會(huì)執(zhí)行那些執(zhí)行上下文位于棧頂部的函數(shù)。當(dāng)這個(gè)函數(shù)完成時(shí)授滓,它的執(zhí)行棧從棧中彈出琳水,控件到達(dá)當(dāng)前棧中被彈出的上下文的下面的上下文。

讓我們通過(guò)下面的代碼示例來(lái)理解這一點(diǎn):

let a = 'Hello World!';
function first() {
  console.log('Inside first function');
  second();
  console.log('Again inside first function');
}
function second() {
  console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');

圖片就是上面代碼的執(zhí)行上下文堆棧般堆。

當(dāng)瀏覽器加載上述代碼時(shí)在孝,Javascript引擎會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文,并將其推入當(dāng)前執(zhí)行棧淮摔。當(dāng)遇到對(duì)first()的調(diào)用時(shí)私沮,Javascript引擎會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文(函數(shù)執(zhí)行上下文),并將其推到當(dāng)前執(zhí)行堆棧的頂部噩咪。

當(dāng)在first()函數(shù)中調(diào)用second()函數(shù)時(shí)顾彰,Javascript引擎會(huì)為該函數(shù)創(chuàng)建一個(gè)新的執(zhí)行上下文,并將其推到當(dāng)前執(zhí)行棧的頂部胃碾。當(dāng)second()函數(shù)結(jié)束時(shí)涨享,它的執(zhí)行上下文從當(dāng)前棧中彈出,控件到達(dá)它下面的執(zhí)行上下文仆百,也就是first()函數(shù)的執(zhí)行上下文厕隧。

如何創(chuàng)建執(zhí)行上下文?

到目前為止,我們已經(jīng)看到了JavaScript引擎是如何管理執(zhí)行上下文的俄周,現(xiàn)在讓我們來(lái)理解JavaScript引擎是如何創(chuàng)建執(zhí)行上下文的吁讨。

執(zhí)行上下文的創(chuàng)建分為兩個(gè)階段:1)創(chuàng)建階段和2)執(zhí)行階段。

組件創(chuàng)建階段(The Creation Phase)

執(zhí)行上下文在創(chuàng)建階段創(chuàng)建峦朗。在創(chuàng)建階段會(huì)發(fā)生以下事情:

  1. 創(chuàng)建LexicalEnvironment組件建丧。
  2. 創(chuàng)建VariableEnvironment組件。

因此波势,執(zhí)行上下文可以在概念上表示為:

ExecutionContext = {
  LexicalEnvironment = <ref. to LexicalEnvironment in memory>,
  VariableEnvironment = <ref. to VariableEnvironment in  memory>,
}

詞法環(huán)境(Lexical Environment)

官方ES6文檔將詞匯環(huán)境定義為

(詞法環(huán)境)Lexical Environment是一種規(guī)范類型翎朱,用于根據(jù)ECMAScript代碼的詞法嵌套結(jié)構(gòu)定義標(biāo)識(shí)符與特定變量和函數(shù)的關(guān)聯(lián)。詞法環(huán)境由一個(gè)環(huán)境記錄和一個(gè)可能為空的外部詞匯環(huán)境引用組成尺铣。

簡(jiǎn)單地說(shuō)拴曲,詞法環(huán)境是一個(gè)保存標(biāo)識(shí)符-變量映射的結(jié)構(gòu)。(這里標(biāo)識(shí)符指的是變量/函數(shù)的名稱凛忿,變量是對(duì)實(shí)際對(duì)象[包括函數(shù)對(duì)象和數(shù)組對(duì)象]或原始數(shù)據(jù)的引用)澈灼。

例如,考慮下面的代碼片段:

var a = 20;
var b = 40;
function foo() {
  console.log('bar');
}

所以上面代碼片段的詞法環(huán)境是這樣的:

lexicalEnvironment = {
  a: 20,
  b: 40,
  foo: <ref. to foo function>
}

每個(gè)詞法環(huán)境有三個(gè)組成部分:

  1. Environment Record(環(huán)境記錄器)
  2. Reference to the outer environment(指向外部環(huán)境的引用)
  3. This binding. (this綁定)

Environment Record (環(huán)境記錄器)

環(huán)境記錄器是變量和函數(shù)聲明存儲(chǔ)在詞法環(huán)境中的位置。

此外叁熔,環(huán)境記錄器亦有兩類:

  • 聲明性環(huán)境記錄(Declarative environment record)——顧名思義委乌,它存儲(chǔ)變量和函數(shù)聲明。函數(shù)代碼的詞法環(huán)境包含一個(gè)聲明性環(huán)境記錄者疤。

  • 對(duì)象環(huán)境記錄(Object environment record)——全局代碼(global code)的詞法環(huán)境包含一個(gè)客觀環(huán)境記錄(objective environment record)福澡。除了變量和函數(shù)聲明,對(duì)象環(huán)境記錄(the object environment record)還存儲(chǔ)了一個(gè)全局綁定對(duì)象(瀏覽器中的window對(duì)象)驹马。因此,對(duì)于每個(gè)綁定對(duì)象的屬性(在瀏覽器中除秀,它包含瀏覽器提供給window對(duì)象的屬性和方法)糯累,記錄中會(huì)創(chuàng)建一個(gè)新條目(new entry)。

注意:對(duì)于函數(shù)代碼(function code)册踩,環(huán)境記錄還包含一個(gè)參數(shù)對(duì)象(argument對(duì)象)泳姐,該對(duì)象包含傳遞給函數(shù)的索引和參數(shù)之間的映射,以及傳遞給函數(shù)的參數(shù)的長(zhǎng)度(數(shù)量)暂吉。例如胖秒,下面函數(shù)的參數(shù)對(duì)象是這樣的:

function foo(a, b) {
  var c = a + b;
}
foo(2, 3);
// argument object
Arguments: {0: 2, 1: 3, length: 2},

Reference to the Outer Environment(指向外部環(huán)境的引用)

Reference to the Outer Environment指的是它能夠接觸到外部的詞法環(huán)境。這意味著慕的,如果在當(dāng)前詞法環(huán)境中沒(méi)有找到想要查找的變量阎肝,JavaScript引擎可以在外部環(huán)境中查找它們。

This Binding (this綁定)

在此組件中肮街,this的值被確定或設(shè)置(determined or set)风题。

在全局執(zhí)行上下文中,this的值指向全局對(duì)象嫉父。(在瀏覽器中沛硅,它指的是Window對(duì)象)。

在函數(shù)執(zhí)行上下文中绕辖,this的值取決于函數(shù)的調(diào)用方式摇肌。如果它是通過(guò)對(duì)象引用調(diào)用的,那么this的值被設(shè)置為該對(duì)象仪际,否則围小,this的值被設(shè)置為全局對(duì)象或未定義(在嚴(yán)格模式下)。例如:

const person = {
  name: 'peter',
  birthYear: 1994,
  calcAge: function() {
    console.log(2018 - this.birthYear);
  }
}
person.calcAge(); 
// 'this' refers to 'person', because 'calcAge' was called with 'person' object reference
// 'this'指的是'person'弟头,因?yàn)?calcAge'是用'person'對(duì)象引用調(diào)用的
const calculateAge = person.calcAge;
calculateAge();
// 'this' refers to the global window object, because no object reference was given
// 'this'引用全局window對(duì)象吩抓,因?yàn)闆](méi)有給出對(duì)象引用

抽象地說(shuō),偽代碼中的詞法環(huán)境是這樣的:

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      // 標(biāo)識(shí)符綁定到這里
    }
    outer: <null>,
    this: <global object>
  }
}
FunctionExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      // 標(biāo)識(shí)符綁定到這里
    }
    outer: <Global or outer function environment reference>,
    this: <depends on how function is called>
  }
}

變量環(huán)境 (Variable Environment)

它也是一個(gè)詞法環(huán)境赴恨,它的環(huán)境記錄器(EnvironmentRecord)保存由VariableStatements 在執(zhí)行上下文中創(chuàng)建的綁定疹娶。

如上所述,變量環(huán)境也是一個(gè)詞法環(huán)境伦连,因此它具有上述定義的詞法環(huán)境的所有屬性和組件雨饺。

在ES6中钳垮,詞法環(huán)境(LexicalEnvironment)組件和變量環(huán)境(VariableEnvironment)組件之間的一個(gè)區(qū)別是,前者用于存儲(chǔ)函數(shù)聲明和變量(let和const)綁定额港,而后者僅用于存儲(chǔ)變量(var)綁定饺窿。

執(zhí)行程序階段(Execution Phase)

在這個(gè)階段,所有這些變量的賦值都完成了移斩,代碼也最終執(zhí)行了肚医。

Example (例子)

讓我們看一些例子來(lái)理解上述概念:

let a = 20;
const b = 30;
var c;
function multiply(e, f) {
  var g = 20;
  return e * f * g;
}
c = multiply(20, 30);

當(dāng)執(zhí)行上述代碼時(shí)(the above code is executed),JavaScript引擎創(chuàng)建一個(gè)全局執(zhí)行上下文來(lái)執(zhí)行全局代碼向瓷。所以在創(chuàng)建階段肠套,全局執(zhí)行上下文看起來(lái)像這樣:

GlobalExectionContext = {
  LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      a: < uninitialized > ,
      b: < uninitialized > ,
      multiply: < func >
    }
    outer: < null > ,
    ThisBinding: < Global Object >
  },
  VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Object",
      // Identifier bindings go here
      c: undefined,
    }
    outer: < null > ,
    ThisBinding: < Global Object >
  }
}

在執(zhí)行階段(During the execution phase),完成變量賦值猖任。因此你稚,在執(zhí)行階段,全局執(zhí)行上下文將類似于以下內(nèi)容朱躺。

GlobalExectionContext = {
  LexicalEnvironment: {
      EnvironmentRecord: {
        Type: "Object",
        // Identifier bindings go here
        a: 20,
        b: 30,
        multiply: < func >
      }
      outer: <null>,
      ThisBinding: <Global Object>
    },
  VariableEnvironment: {
      EnvironmentRecord: {
        Type: "Object",
        // Identifier bindings go here
        c: undefined,
      }
      outer: <null>,
      ThisBinding: <Global Object>
    }
  }

當(dāng)遇到對(duì)function multiply(20,30)的調(diào)用時(shí)刁赖,將創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文來(lái)執(zhí)行函數(shù)代碼。所以在創(chuàng)建階段长搀,函數(shù)執(zhí)行上下文看起來(lái)像這樣:

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: undefined
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

在此之后宇弛,執(zhí)行上下文將經(jīng)歷執(zhí)行階段(the execution phase),這意味著完成對(duì)函數(shù)內(nèi)變量的賦值盈滴。所以在執(zhí)行階段涯肩,函數(shù)的執(zhí)行上下文看起來(lái)像這樣:

FunctionExectionContext = {
LexicalEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      Arguments: {0: 20, 1: 30, length: 2},
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>,
  },
VariableEnvironment: {
    EnvironmentRecord: {
      Type: "Declarative",
      // Identifier bindings go here
      g: 20
    },
    outer: <GlobalLexicalEnvironment>,
    ThisBinding: <Global Object or undefined>
  }
}

函數(shù)完成后,返回值被存儲(chǔ)在c中巢钓。因此全局詞法環(huán)境被更新病苗。之后,全局代碼完成症汹,程序結(jié)束硫朦。

注意——你可能已經(jīng)注意到letconst定義的變量在創(chuàng)建階段沒(méi)有任何關(guān)聯(lián)的值,但是var定義的變量被設(shè)置為undefined背镇。

這是因?yàn)橐д梗趧?chuàng)建階段,代碼被掃描以查找變量和函數(shù)聲明瞒斩,而函數(shù)聲明被完整地存儲(chǔ)在環(huán)境中破婆,變量最初被設(shè)置為未定義(對(duì)于var)或保持未初始化(對(duì)于letconst)。

這就是為什么你可以在聲明之前訪問(wèn)var定義的變量(雖然未定義)胸囱,但在聲明之前訪問(wèn)letconst變量時(shí)會(huì)得到引用錯(cuò)誤的原因祷舀。

這就是我們所說(shuō)的變量提升(hoisting)。

注意:在執(zhí)行階段,如果JavaScript引擎無(wú)法在源代碼中聲明let變量的實(shí)際位置找到它的值裳扯,那么它將給它賦值為undefined抛丽。


總結(jié)(Conclusion)

我們已經(jīng)討論了JavaScript程序是如何在內(nèi)部執(zhí)行的。雖然要成為出色的JavaScript開(kāi)發(fā)人員并不需要學(xué)習(xí)所有這些概念饰豺,但充分理解上述概念將有助于您更容易亿鲜、更深入地理解其他概念,如變量聲明提升(hoisting)冤吨、作用域(Scope)和閉包(Closures)蒿柳。

就是這樣,如果你覺(jué)得這篇文章有幫助锅很,請(qǐng)點(diǎn)擊??按鈕其馏,并隨時(shí)在下面發(fā)表評(píng)論!我很樂(lè)意和??交流

本文由mdnice多平臺(tái)發(fā)布

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市爆安,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仔引,老刑警劉巖扔仓,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咖耘,居然都是意外死亡翘簇,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門儿倒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)版保,“玉大人,你說(shuō)我怎么就攤上這事夫否〕估纾” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵凰慈,是天一觀的道長(zhǎng)汞幢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)微谓,這世上最難降的妖魔是什么森篷? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮豺型,結(jié)果婚禮上仲智,老公的妹妹穿的比我還像新娘。我一直安慰自己姻氨,他們只是感情好钓辆,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般岩馍。 火紅的嫁衣襯著肌膚如雪碉咆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天蛀恩,我揣著相機(jī)與錄音疫铜,去河邊找鬼。 笑死双谆,一個(gè)胖子當(dāng)著我的面吹牛壳咕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播顽馋,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼谓厘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了寸谜?” 一聲冷哼從身側(cè)響起竟稳,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熊痴,沒(méi)想到半個(gè)月后他爸,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡果善,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年诊笤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巾陕。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡讨跟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鄙煤,到底是詐尸還是另有隱情晾匠,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布馆类,位于F島的核電站混聊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏乾巧。R本人自食惡果不足惜句喜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沟于。 院中可真熱鬧咳胃,春花似錦、人聲如沸旷太。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至存崖,卻和暖如春冻记,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背来惧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工冗栗, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人供搀。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓隅居,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親葛虐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子胎源,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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