前端面试基础题

解释下 promise 与 promise.all 扩展

  • 回调函数的定义:
    就是把任务的第二段放在一个函数中,等到重新执行这个任务的时候就直接调用
  • promise 是什么
    promise 函数是异步编程的一种解决方案,比传统的回调函数和事件的合理和强大.简单来说像是个容器,里面装着某个未来才会结束的事情
    (通常是个异步操作) 语法上说 promise 是个对象 从他可以获取异步操作的消息
  • 为什么会出现
    原因是处理异步请求的情况,在请求到成功回调函数中继续写函数,行程回调地狱
  • 特质:
    1.对象的状态不受外部影响
    2.一旦状态改变,就无法再改变
  • 缺点
    一旦创建 promise 就会立即执行
  • then 方法可以接受两个回调函数作为参数
    1. 状态为 resolved 的时候
    2. 状态为 rejected 的时候 第二个回调是可选的
  • catch
    用于指定发生错误时的回调函数
  • 错误是从哪里来的?
    只要指定了 reject 不管是什么都可以生成错误
  • promise.all 的使用
    可以将多个实例包装成一个新的 promise实例.成功是返回的是成功的结果数组,失败的时候返回最先被 reject 的值.如果其中有一个失败则此回调失败,原因是第一个失败的结果.只要有一个失败的话就没有输出
  • promise.race 的使用
    不管成功或失败,谁先返回就是其结果
  • 手撕 promise

generator

看上去像是一个函数,可以返回多次
函数在执行的时候如果没有 return 语句 则默认 return undefined
generator 由 function* 定义,除了return还可以有yield 返回多次(就是需要暂停的地方)
next()方法会执generator的方法.每次执行都会有个 value值 和 done表示是否结束

generator 与 promise 的却别

promise 适合处理一次读一堆的操作,而 generator适合在读的过程中可以分批有序的处理一些逻辑.可以说四 promise 的封装

async 函数

async 是 generator 的语法糖,*换成 async yield 换为 await

说一说盒子模型

  • 什么是盒模型
    是用来对元素进行布局,包括内边距,边框,外面局和实际内容这几个部分

  • 盒子模型的分类
    分为两种:标准盒模型和IE标准的怪盒模型

  • 标准盒模型与怪异盒模型有啥区别

    1. 标准盒模型中的width指的是内容区域content的宽度;height指的是内容区域的content的宽度.
      标准盒模型下盒子的大小包括:content border padding margin
    2. 怪异盒模型中的width指的是内容、边框、内边距总的宽度(content + border + padding); height指的是内容、边框、内边距的总高度
      其大小:width:包括(content + border + padding) + margin
  • 我们可以通过box-sizing来设置盒子模型的解析模式
    content-box -> 默认值 表示为标准盒模型
    border-box: border和padding会规划到width内,表示为怪异盒模型
    padding-box: 将padding算入width之内

    (当设置为box-sizing:content-box时,将采用标准模式解析计算(默认模式);当设置为box-sizing:border-box时,将采用怪异模式解析计算;)

BFC及其作用

  • 什么是BFC
    BFC就是块级格式上下文,相当于一个独立的容器。里面的元素和外面的元素互不影响
  • 创建BFC的方式有哪些(触发)
    1. body是根元素
    2. 浮动元素。
    3. 绝对定位元素: position (absolute/fixed)
    4. display为inline-block、table-cells、flex
    5. overflow: 除了visible以外的值(hidden/auto.scroll)
  • BFC的特性和运用
    1. 同一个BFC之下会有外边距会有折叠现象(避免方式:将其放在不同的BFC容器之下)
    2. BFC可以包含浮动元素即可以清除浮动 (举个栗子:一个div 里面包裹一个div.第一个div设置了边框。给第二个div使用浮动后,第一个div的高度只剩下上下边框的高度。我们给可以给父元素使用overflow: hidden)
    3. BFC可以阻止元素被浮动元素覆盖(两个元素并列 给其中一个设置浮动,另一个会对其产生压盖(文本信息不会被压盖)。可以给第二个元素设置overflow:hidden触发BFC使其不会被遮盖)
  • 拓展:清除浮动的方式
    1. 给父容器添加高度 但没有解决高度自适应的问题
    2. 给后面的元素添加clear属性 有left,right,both 清除浮动影响 但没有解决高度自适应的问题
    3. 外墙法:两个父盒子之间添加个有高度的墙。div 但没有解决高度自适应的问题
    4. 内墙法:在所有浮动元素后面添加一堵墙。解决了高度自适应问题以及清除浮动,但是增加了无意义标签
    5. 给父盒子设置overflow:hidden。会解决高度自适应以及清除浮动的问题。但是如果盒子内容过多,可能会导致隐藏过多内容的效果
    6. 设置伪元素 ::after { content: '' , clear: both } 好处:伪元素不属于文档,不会添加dom节点
  • 其他格式上下文
    1. GFC(网格布局格式化上下文) 当给元素设置display: grid的时候,此元素会获得独立的渲染空间,在网格上定义行和列并有其丰富的属性控制行列来渲染
    2. FFC(自适应格式上下文) display的值为flex或者inline-flex的时候会生成自适应容器

flex布局即弹性布局

1. 基本概念
  被设为flex的元素称之为容器,他的所有子元素称之为item 项目
  容器存在默认的两根轴,水平主轴和垂直交叉轴(main 和 cross)
2. 属性
  分为容器属性和项目属性两种
  容器属性有
  - flex-direction 决定主轴方向  有横向row,起点在左端; row-reverse: 水平方向,起点右端; column:纵向,上; column-reverse: 纵向,下
  - flex-warp 项目在一条线排不下如何换行。 nowrap不换行  warp换行,第一行在上  warp-reverse换行,第一行在下
  - flex-flow 表示flex-direction与flex-warp的属性简写
  - justify-content定义了项目在主轴上的对其方式 flex-start: 左对齐  flex-end: 右对齐  center: 居中  space-between: 两端顶头,项目之间间隔相等; space-around: 每个项目两侧之间的间距相等
  - align-items定义了项目再交叉轴上如何对其 flex-start: 起点对齐  flex-end: 终点对齐  center: 居中  baseline: 项目第一行文字的基线对齐   stretch: 默认值,沾满整个容器
  - align-content属性定义了多根轴线的对齐方式 flex-start: 交叉轴起点对齐  flex-end: 交叉轴终点对齐  center: 居中  space-between: 与交叉轴两端对齐,轴线之间间隔分布  space-around: 每根  轴线两侧间隔相等

  项目属性有
  - order 定义项目排列顺序 从小到大
  - flex-grow 定义项目放大比例,默认为0。
  - flex-shrink 定义项目缩小比例 默认是1 负值无效
  - flex-basis 定义了分配多余空间之前,项目占据主轴的空间。浏览器会根据该属性计算主轴是否有多余空间
  - align-self 可以覆盖align-item属性,默认为auto,允许该项目于其他项目有不一样的对齐方式

3. 常用布局
  - 左侧固定,右侧自适应
    1. 利用浮动或绝对定位加margin实现左右并排显示
    2. 左侧使用浮动,右侧使用overflow: hidden;
    3. 使用flex。右侧使用flex-grow: 1。实现自适应
  - 左右固定,中间自适应
    1. 使用浮动,左右都float,中间margin-left,margin-right设置。布局center必须在最后一个
    2. 使用绝对定位,中间使用margin
    3. 使用flex 中间那个设置flex-grow: 1放大
    4. 双飞翼布局: 把主列嵌套在一个新的父级块中利用主列的左右外边距进行布局调整(优先加载主列),三列盒子都浮动,左侧margin-left: -100%%; 右侧margin-left: 负的其宽度; 中间盒子外层套一个并设置左右外边距将其左右两边的空间让开
    5. 圣杯布局: 把主列嵌套在一个新的父级块中利用主列的左右外边距进行布局调整(优先加载主列)
        1.将三者都 float:left , 再加上一个position:relative (因为相对定位后面会用到)
        2.middle部分 width:100%占满
        3.此时middle占满了,所以要把left拉到最左边,使用margin-left:-100%
        4.这时left拉回来了,但会覆盖middle内容的左端,要把middle内容拉出来,所以在外围container加上 padding:0 220px 0 200px
        5.middle内容拉回来了,但left也跟着过来了,所以要还原,就对left使用相对定位 left:-200px  同理,right也要相对定位还原 right:-220px
        6.到这里大概就自适应好了。如果想container高度保持一致可以给left middle right都加上min-height:130px
  - div水平垂直居中
    1. 使用flex
    2. 使用绝对定位再使用transition: translate(-50%, -50%)  或者margin负的自身一半
    3. 绝对定位top right bottom left都设置为0 在使用margin:auto
    4. 父容器使用display: grid 子容器justify-self: center; align-self: center
    5. 父容器使用text-align: center; font-size: 0;设置基线。其父容器的伪元素::before 设置为行内块。宽度为0,高度百分百,再使用vertical-align: middle; 子容器:设置行内块,vertical-align: middle设置

rem

- rem 和 em的区别
  rem作用于非根元素时,相对于根元素字体大小;作用于根元素字体大小时,相对于其初始字体大小(16px)
- 如何计算rem
  逻辑尺寸是移动端的实际尺寸,物理尺寸是其2倍 通过window.dpr(devicePixRatio)找出当前物理像素分辨率和css像素分辨率的比率  例如750*1334是物理像素,375是逻辑像素
  假设750px = 10rem 十等分
  相当于window.clientWidth获取视口宽度 * window.dpr(几倍) / 等分 = 1rem   将其设置成根元素的大小

      $px         $rem
  ---------- == ---------
  design-width     10

es6新特性

  • const 和 let声明变量
    形成块级作用域 其变量也会陷入暂存死去,不能进行变量提升,必须先声明再使用
    let 声明的变量可以重新赋值,但是不能在同一作用于中重新声明
    const 声明的变量必须赋值和初始化 不能再同一作用域里重新声明也无法重新赋值。 注意,复合类型的const变量保存的是引用,不指向数据。所以const生命的复合尅性只能保证其地址引用不变,不能保证数据
  • 模板字面量
    之前将字符串连接到一起的方法是+或者是concat()方法。模板字面量用``表示,可以使用包含${}表示占位符
  • 解构
    可以使用解构将数组和对象提取值赋值给独特的变量
  • 对象字面量简写
    如果对象中的键和值一样,可是删除掉重复的变脸名称。 匿名函数不需要function关键字
  • for...of循环
    结合了for循环和for...in循环的优势
    for劣势:for循环我们需要跟踪计数条件和退出条件
    for...in劣势:for...in依然使用Index来访问数组的值
    for...of可以随时停止或退出for...of的循环
  • 展开运算符
    1. 可以合并数组
    2. 表示剩余参数
    3. 表示可变参数
  • 箭头函数
    普通函数可以使函数声明或者函数表达式,但是箭头函数始终都是表达式。当存储在变量中、当做参数传递给函数、存储在对象的属性中
    函数参数是一个不需要()包裹,但是多个需要包裹
    当箭头函数只有一个表达式作为函数主题,可以再函数主体外层不包裹花括号,自动返回表达式(不用return)
    箭头函数没有自己的this指向以及arguments,其值基于函数被谁调用的上下文
  • 设置默认参数
    当所需的参数没有提供的时候,为函数设置的默认的值

为什么Object.defineProperty

  • 属性分为两种类型: 数据属性和访问器属性
    1. 数据属性: configurable: 可配置性; enumerable:可枚举型; get: 取值; set:赋值
    2. 访问器属性: configurable: 可配置型; enumerable: 可枚举性; writable: 是否可写; value:属性的值
  • 属性创建的区别: 平时的obj.attributeName取值是修改的value属性;而该属性是修改通过get set去设置
  • object。defineProperty无法检测到数组长度的变化,准确的说是无法检测到通过改变数组长度而增加的属性
  • 此方法处理对象和数组一样,只是在初始化的时候改写get set达到检测数组或对象的变化。对于新增的属性,需要手动再初始化。对于数组来说比较特殊一点,push、unshift值会添加索引,对于新增的属性是可以添加observe从而达到监听的效果;pop,shift值会删除更新索引,也会触发get和set。对于重新赋值length的数组,不会新增索引,因为不清楚新增的索引有多少

浏览器缓存

  • 浏览器如何确定一个资源该不该缓存,如何缓存?
    浏览器第一次发送请求后拿到请求的结果,将请求结果和缓存标识存入浏览器缓存,浏览器对于缓存的处理是根据第一次请求资源时返回得响应头来确定的
    1. 浏览器每次发送请求,都会先在浏览器中查找该结果以及缓存标识 2. 浏览器每次拿到返回的请求结果都会将该结果和缓存标识存入浏览器缓存中
  • 分类 强缓存和协商缓存
    1. 强缓存是直接从浏览器中拿数据
      控制强缓存的字段有expires(过期时间)和cache-control。如当cache-control: max-age设置了时间 意思是告诉浏览器在这个时间段请求资源就回命中强缓存
      no-cache是说浏览器再使用缓存数据的时候需要确认一下数据是否还和服务器保持一致
    2. 协商缓存会先访问服务器看缓存是否过期,再决定是否从浏览器里面拿数据: 有两个属性Last-modified和ETag
  • 为啥会产生协商缓存
    因为强缓存是根据是否超出某个时间段来拉取新的内容,不能保证使用的是服务端最新的数据,所以我们怎么知道服务端内容是否是最新的呢 就使用到了协商缓存
  • 缓存机制
    强缓存会优先于协商缓存,如果强缓存生效就是用缓存,不生效则需要进行协商缓存。若协商缓存失效的话则表示魂村失效给200
  • 实际应用的缓存策略
    1. 频繁变动资源: cache-control: no-catch 使用这个的话则使每次都请求服务器,然后配合ETag来验证资源有效
  • 不常变化的资源 可以设置max-age为一年或者很多。只要浏览器请求携带相同的url就回命中强缓存。解决更新的话就在后面添加hash盘点
  • 用户行为对缓存的影响
    1. 打开网页
    2. 普通刷新
    3. 强制刷新

http请求头

http报文包括 请求行,请求头以及请求体
1. 请求行:  包括请求方式、路径以及版本
2. 请求头: 包括若干个属性,缓存相关的都在其中
   accept  接受什么类型的相应;   cookie:      ; referer:是从哪个url过来的; cache-control: 缓存
3. 报文体: 就是需要传递的信息

http响应头

1. 相应行, 协议及版本 以及状态和描述
2. 响应头, 
3. 响应体

cookie和token 储存位置以及价值,为什么只劫持cookie而并不劫持token,区别

  • cookie和session的区别
    1. cookie数据存放于客户端上 session存放于服务器上
    2. cookie不安全
    3. session都放在服务器,影响性能增加服务器压力
    4. 单个cookie保存的数据不能超过4k,一个站点最多保存20个cookie
  • cookie的字段
    name: 名称
    value: 值
    domain 可以访问此cookie的域名
    path: 是可以访问此cookie的页面路径
    expires/max-age: cookie的超时时间。设置的话按照设置的走,不设置的话则按照
    size: cookie的大小
    secure: 设置是否只能通过Https来传递cookie

跨域及解决方式

  • 什么是跨域
    是指浏览器允许想服务器发送跨域请求,从而克服ajax只能同源使用的限制
  • 同源策略
    要求url的协议、域名、端口号三者必须相同,有一个不同就是跨域
  • 解决方案
    1. jsonp解决
      通过动态生成的script标签的src属性,携带一个callback参数的get请求,服务端就会返回数据拼凑到callback中。 缺点是只能实现get一种请求
    2. 跨域资源共享(CORS)
      普通跨域请求: 只服务端设置Access-Control-Origin即可,前端无需设置。如果要携带cookie请求,则前后端都要设置。需要设置xhr.withCredentials = true
    3. document.domain + iframe跨域
      实现原理: 两个页面都通过js强制设置document.domain为举出主域,实现了同域
    4. location.hash + iframe跨域
      a要想与b通信,则通过中间的c来实现。三个页面质检不同于之间利用iframe的location.hash传值,相同于质检直接js来访问
    5. window.name + iframe
      window.name的属性独特之处,name值可以再不同的页面加载后仍然存在,兵器额可以支持非常长的name值
    6. webSocket实现跨域
      可以使用socket.io设置跨域
      使用io(链接)
      向服务端发送信息 socket.emit()
      通过on获取服务端发来的信息
    7. nginx代理跨域
      1. 配置iconfont跨域
        location / { add_header Access-control-allow-origin: * }å
      2. nginx反向代理接口
        通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机.反向代理访问domain2接口,并且可以顺便修改cookie中的domain信息方便cookie写入,实现跨域登录

http相关知识

  • http请求中的options方法: 查询相应URL支持的Http方法

  • http和https的区别
    一个是Http,一个是https; 一个不安全,一个安全; 一个端口号是80,一个端口号是443; 一个是在应用层,一个是在传输层; 一个无法加密,一个对数据加密; 一个不需要证书,一个需要证书;

  • http如何能够保证安全
    重要的数据要加密,比如用户的密码等。越复杂越好。MD5加一些其他字符串
    非重要数据要签名。连接请求的时候在原链接上加一些sign参数
    登录状态由于http是无状态的,就是在数据库存储token字段。用户调用接口成功的时候给该字段加一个值。以此判断

  • http优化方案

    1. TCP复用:tcp链接复用是将多个客户端的http请求复用到一个服务薇端的TCP连接上。而http复用则是一个客户端的多个http请求通过一个tcp链接进行处理。前者是负载均衡设备的独特功能,后者是1.1版本支持的新功能。
    2. 内存缓存:将经常用到的内容缓存起来,那么客户端就可以直接在内存中获取相应的数据了
    3. 压缩: 将文本数据进行压缩,减少带宽
    4. ssl加速:使用ssl协议对http协议进行加密以及在通道中加密并加速
    5. tcp缓冲:通过采用tcp缓冲技术可以提高服务端响应时间和处理效率,减少由于通信链路问题给服务器造成的连接负担
  • http2.0与1.0的区别

    1. 新的二进制格式: 1版本是基于文本的协议进行传递。2版本的话使用的是2进制的格式实现方便
    2. 多路复用:(连接共享)一个request对应一个Id,一个连接上就可以有多个request,每个链接的request混在在一起,接收方再根据request上的Id对应到不同的服务端请求中
    3. header压缩: 1版本header上有大量的信息,每次都会重复发送。2版本的话使用encoder减少需要传输的header大小。通讯双方都隐藏了一个header fields表,避免了重复header的传输,又减少了需要传输的大小

http2.0的多路复用与1版本中的长链接复用有什么区别

1.*:一次请求-响应,建立一个链接,用完关闭,每一个请求都要建立个链接
1.1长链接是将多个请求排队串行做单线程处理,有一个长链接管道。后面的请求等待前面的请求返回才能获得执行机会,一旦有请求超时,后面的请求就会被阻塞。即线头阻塞
2.0版本多个请求同时再一个连接上并行执行。某个请求耗时严重,不会影响其他请求

webpack和其他打包工具的不同

1. grunt和gulp是基于任务和流的。找到一类文件进行链式操作,更新流上的数据。而webpack是基于入口的,其会递归的解析入口所需要的资源文件。用不同的Loader处理不同的文件,用plugin来拓展webpack功能

有哪些常见的loader以及他们解决什么问题

1. file-loader: 把文件输出到一个文件夹中,可以在代码中通过URL去引用输入的文件
2. babel-loader: 将es6转换为es5
3. css-loader: 加载css,支持模块化、压缩、文件导入等特性
4. style-loader: 把css代码注入到js中,通过dom操作去加载css
5. eslint-loader: 通过eslint检查js代码

有哪些常见的plugin以及其解决什么问题

1. define-plugin: 定义环境变量
2. commons-chunk-plugin: 提取公共代码
3. uglifyjs-webpack-plugin: 压缩es6代码
4. tree-sharking: 通过分析静态的ES模块,来剔除未使用的代码

loader和plugin的不同

1. loader是加载机:webpack只能解析Js文件。如果想要其他文件也打包的时候就需要loader。其作用就是加载和解析非js文件
2. plugin是插件:对webpack的功能进行扩展

webpack的构建流程:

1. 初始化参数,将配置好的参数开始进行初始化
2. 开始编译:将使用的loader和其他依赖进行递归的编译,执行run
3. 找到入口:确定入口,将所有入口找出
4. 编译模块:从入口文件出发,调用所有配置loader的对模块进行编译,再找出模块依赖的模块,再递归本步骤直到所有的入口都经过本步骤
5. 完成模块编译
6. 输出资源: 将入口和模块之间的依赖关系组成一个个包含多个模块的chunk,再把每个chunk转换成一个单独的文件加入到输出列表。这步是修改输出资源的最后一个机会
7. 输出完成:在确定好输出后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统

bundle module chunk是什么

bundle: 是由多个不同的模块产生,他是已经加载完毕之后或者编译完毕之后源代码的最终版
chunk: bundle由许多chunk组成。比如说有‘入口’和‘子块’
module: 是一个模块

安全类的

登录

路由

闭包

setTimeout设置为0

面向对象原理

数据库设计优化

原型

路由切换及原理

v-model的原理

vue一共有几种watcher

1.说说es6的promise
2.flex大概了解哪些属性,有什么用
3.vue router有哪些模式,原理(hash,history)
4.手写:用户搜索框输入结束实时搜索(其实就是防抖的手写)
5.二分查找
6.二叉树层序遍历(bfs)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,602评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,442评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,878评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,306评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,330评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,071评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,382评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,006评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,512评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,965评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,094评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,732评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,283评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,286评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,512评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,536评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,828评论 2 345

推荐阅读更多精彩内容