前端面试基础篇

技术

【一】css3: 相比css2新增的特性

. box-shadow text-shadow
. 背景的一些操作,多背景图 背景铺设起点
. border-radius
. box-sizing:border-box
. animation keyframe
. transition
. translate

【二】html5:相比 html4新增的

. 音视频- 兼容 source 引入各个格式的资源
. canvas 画布
. 本地存储 local session (大小 5M,区别,iframe扩容) cookie (4K,区别-数据通信每次都会带,所以尽量存必要短小信息,http-only:后台有权限直接锁定防止js写操作;异域操作cookie-根域设置成相同 document.domain = "baidu.com")
. 新的语义化元素,比如:<nav>, <header>, <footer> <section>
. 获得用户的当前位置-etCurrentPosition()
. 规定元素内容是否是可编辑的-全局属性,"contenteditable"
. web worker 是运行在后台的 JavaScript,独立于其他脚本,不会影响页面的性能
. 应用程序缓存-Application Cache-如需启用应用程序缓存,请在文档的 <html> 标签中包含 manifest 属性.三个优势:

离线浏览 - 用户可在应用离线时使用它们
速度 - 已缓存资源加载得更快
减少服务器负载 - 浏览器将只从服务器下载更新过或更改过的资源。

. 丰富了表单元素类型

email
url
number
range
Date pickers (date, month, week, time, datetime, datetime-local)
search
color

【三】原生js典型问题:

. 变量声明提升

if(true) {
  console.log(a)//TDZ,俗称临时死区,用来描述变量不提升的现象
  let a = 1
}

. 作用域:

管理变量的,分为局部作用域和全局作用域,变量定义在函数中,就称作是局部变量,只在当前函数内可以访问的到。(ES5中 没有块级作用域的说法,就是 for if 等大括号就能封闭作用域管理住变量)

作用域链:

作用域链就由一些列作用域嵌套形成,查询方向只能是由内到外单项走,比如在当前作用域下访问变量name,首先会在当前域下找,没有就到上一层,直到找到最顶层的window全局作用域。

. 对象的3个特性:封装,继承,多态。

封装:封装了细节和复杂度。
继承:复用。
多态:同一种属性方法,调用不同对象的,表现执行不一样。javascript的变量在运行期是可变的,一个js对象既可以表示既可以表示Duck类型的对象,又可以表示Chicken类型的对象,这意味着JavaScript对象的多态性是与生俱来的。
ex:本人家里养了一只鸡,一只鸭。当主人向他们发出‘叫’的命令时。鸭子会嘎嘎的叫,而鸡会咯咯的叫
多态的代码示例

var makeSound = function(animal) {
    animal.sound();
}

var Duck = function(){}
Duck.prototype.sound = function() {
    console.log('嘎嘎嘎')
}
var Chiken = function() {};
Chiken.prototype.sound = function() {
    console.log('咯咯咯')
}

makeSound(new Chicken());
makeSound(new Duck());

. 原型链:

是一种链表的结构。----产生原理:只要是实例对象就会有构造函数,构造函数就会有对应的原型对象,原型对象又会有构造函数,层层寻找,直到最顶层是object.prototype对应的值是--null

image.png

.原型的本质

一个对象实例化后必然产生一个默认的原型对象,有一个constructor属性指向它对应的构造函数,但是一般,这个默认原型里什么都没有,所以我们要改写原型库,这样你在重写的原型不会有constructor指向了,所以要手动修复指向问题,即只要你写原型库了,第一句就是constructor=对应的构造函数。

. 继承本质

当前对象想用(拷贝或是指向的方式)别人的属性和方法

. this 指的什么
当前运行时的环境

分几种情况:
全局下,this指的是window 
函数中,this指的是函数的调用者   ex:Person.say(this 指的是Person)
dom事件中,this指的是当前操作的dom 对象(元素) ex: navDom.onclick(function(){this 就是navDom})

. 跨域

浏览器为了安全出的一套同源策略机制,也就是 前端的js 代码 要和后台接口来自同一个域下,否则默认不安全,请求的接口数据不让用。
解决:常用的 也是项目中用到的 CORS 方式 -> 前后台分别配置下即可,后台具体字段名字: header("Access-Control-Allow-Origin:*"); 前端:withCredentials:true 即可通信。

. call apply 作用

可以实现借用,也即是继承到别人的工具方法。区别就是传参形式不同
【四】 reg正则

var pattern = / reg /
认识基本的即可

[] 任意一个 ex: [0-9] 从0 到9 中的任意一个
-  范围  ex: 0-9   从0到9
*  出现0次或是多次
+  出现1次或是多次
() 分组,也就是隔离作用,和我代码里作用一致的
|  或 ex: x|y 匹配x或y 
{} 出现的次数范围 ex: {n} 精确匹配n次 ;  {n,} 匹配n次以上;  {n,m} 匹配n-m次 
\w  等于[a-zA-Z0-9]
\W  等于[^a-zA-Z0-9]
\d 任何数字,等价于[0-9] 
\D 除了数字之外的任何字符,等价于[^0-9] 
^ 写的位置不同含义不一样,放到正则第一层  表示以什么开头,放到[] 里表示 不匹配这个集合中的任何一个字符 
 

image.png
【五】es6使用:
- const和let的异同点
相同点:const和let都是在当前块内有效,执行到块外会被销毁,也不存在变量提升(TDZ),不能重复声明。
不同点:const不能再赋值,let声明的变量可以重复赋值。 

- 最出名的一道面试题:循环中定时器闭包的考题
for(var i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log(i) //5, 5, 5, 5, 5
  }, 0)
} 
- 箭头函数
箭头函数中this的使用跟普通函数也不一样,在JavaScript的普通函数中,都会有一个自己的this值,主要分为:
普通函数:
1、函数作为全局函数被调用时,this指向全局对象
2、函数作为对象中的方法被调用时,this指向该对象
3、函数作为构造函数的时候,this指向构造函数new出来的新对象
4、还可以通过call,apply,bind改变this的指向
箭头函数:
1、箭头函数没有this,函数内部的this来自于父级最近的非箭头函数,并且不能改变this的指向。
2、箭头函数没有super
3、箭头函数没有arguments
4、箭头函数没有new.target绑定。
5、不能使用new
6、没有原型
7、不支持重复的命名参数。
- Object.assign()方法
用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
- arr 丰富了好多api
forEach filter  map
- symbol
ES6 以前,我们知道5种基本数据类型分别是Undefined,Null,Boolean,Number以及String,然后加上一种引用类型Object构成了JavaScript中所有的数据类型,但是ES6出来之后,新增了一种数据类型,名叫symbol,像它的名字表露的一样,意味着独一无二,意思是每个 Symbol类型都是独一无二的,不与其它 Symbol 重复。
可以通过调用 Symbol() 方法将创建一个新的 Symbol 类型的值,这个值独一无二,不与任何值相等。

- 模板字符串
`${var}const`   等同 :var + 'const'


promise :
解决的问题:多层异步回调嵌套问题。
实际应用:
a接口依赖b接口的数据先回来。
能看懂:


image.png

结果:start p1 end undefined p2 2 setTimeout

知识点:
1.代码依次从上到下
2.new Promise 这一步是同步的,then才是要等待的。
3.res 里没传递东西出去,then里也就拿不到东西
4. setTimeOut js 底层编译器默认处理就是放到所有代码之后执行。
【六】 arr -api
一、concat()
concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,仅会返回被连接数组的一个副本。

var arr1 = [1,2,3];
var arr2 = [4,5];
var arr3 = arr1.concat(arr2);
console.log(arr1); //[1, 2, 3]
console.log(arr3); //[1, 2, 3, 4, 5]
二、join()
join() 方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的,默认使用','号分割,不改变原数组。

var arr = [2,3,4];
console.log(arr.join());  //2,3,4
console.log(arr);  //[2, 3, 4]

七、slice()
返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。返回选定的元素,该方法不会修改原数组。

var arr = [2,3,4,5];
console.log(arr.slice(1,3));  //[3,4]
console.log(arr);  //[2,3,4,5]
八、splice()
splice() 方法可删除从 index 处开始的零个或多个元素,并且用参数列表中声明的一个或多个值来替换那些被删除的元素。如果从 arrayObject 中删除了元素,则返回的是含有被删除的元素的数组。splice() 方法会直接对数组进行修改。

var a = [5,6,7,8];
console.log(a.splice(1,0,9)); //[]
console.log(a);  // [5, 9, 6, 7, 8]
var b = [5,6,7,8];
console.log(b.splice(1,2,3));  //[6, 7]
console.log(b); //[5, 3, 8]

十、sort 排序
按照 Unicode code 位置排序,默认升序

var fruit = ['cherries', 'apples', 'bananas'];
fruit.sort(); // ['apples', 'bananas', 'cherries']

var scores = [1, 10, 21, 2];
scores.sort(); // [1, 10, 2, 21]
十一、reverse()
reverse() 方法用于颠倒数组中元素的顺序。返回的是颠倒后的数组,会改变原数组。

var arr = [2,3,4];
console.log(arr.reverse()); //[4, 3, 2]
console.log(arr);  //[4, 3, 2]
十二、indexOf 和 lastIndexOf
都接受两个参数:查找的值、查找起始位置
不存在,返回 -1 ;存在,返回位置。indexOf 是从前往后查找, lastIndexOf 是从后往前查找。
indexOf

var a = [2, 9, 9];
a.indexOf(2); // 0
a.indexOf(7); // -1

if (a.indexOf(7) === -1) {
  // element doesn't exist in array
}

十五、filter
对数组的每一项都运行给定的函数,返回 结果为 ture 的项组成的数组

var words = ["spray", "limit", "elite", "exuberant", "destruction", "present", "happy"];

var longWords = words.filter(function(word){
  return word.length > 6;
});
// Filtered array longWords is ["exuberant", "destruction", "present"]
十六、map
对数组的每一项都运行给定的函数,返回每次函数调用的结果组成一个新数组

var numbers = [1, 5, 10, 15];
var doubles = numbers.map(function(x) {
   return x * 2;
});
// doubles is now [2, 10, 20, 30]
// numbers is still [1, 5, 10, 15]
十七、forEach 数组遍历
const items = ['item1', 'item2', 'item3'];
const copy = [];    
items.forEach(function(item){
  copy.push(item)
});
【七】string 常用api
- 提取字符串中两个指定的索引号之间的字符。
 stringObject.substring(start,stop)

- 提取字符串的片断,并在新的字符串中返回被提取的部分。
stringObject.slice(start,end);和 substring 很像,都是传递起终点索引,知识slice可以传递负数,从字符串末尾算起

- 从起始索引号提取字符串中指定数目的字符。
stringObject.substr(start,length)。

- 把字符串分割为字符串数组。
str.split(' , ')

- 连接字符串。
str.concat('afasd')

- match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
var str="1 abc 2 def 3"
console.log(str.match(/\d+/g))//123

- replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。

var str="abc Def!"
console.log(str.replace(/abc/, "CBA"))//CBA Def!

【八】 obj 几个关键api
1.Object.defineProperty(obj, prop, descriptor)  给对象添加一个属性并指定该属性的配置。
 //Object 要在其定义属性的对象  
// prop 要定义或修改的属性  
// des 将被定义或修改的属性描述符
 Object.defineProperty(data, key, {
 
        enumerable: true, // 可被枚举
 
        configurable: false, // 不能再define
 
        get: function () {
 
          return val
 
        },
 
        set: function (newVal) {
 
          val = newVal
 
        }
 
      })

2.obj.hasOwnProperty('prop') 判断 x 对象里是否有 y 属性
3.Object.keys(obj)方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用[`for...in`]循环遍历该对象时返回的顺序一致 。如果对象的键-值都不可枚举,那么将返回由键组成的数组


. dom相关:获取,插入,删除


. css样式通过js api 操作:读取getComputedStyle(dom), 设置:style

【九】 vue:

. mvvm

m:model 
v:view
vm: control 协调m v 二者关系,也就是算法部分(执行逻辑)

. 双向数据绑定

采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

vue的数据双向绑定 将MVVM作为数据绑定的入口,整合Observer,Compile和Watcher三者,通过Observer来监听自己的model的数据变化,通过Compile来解析编译模板指令(vue中是用来解析 {{}}),最终利用watcher搭起observer和Compile之间的通信桥梁,达到数据变化 —>视图更新;视图交互变化(input)—>数据model变更双向绑定效果。

js 实现最简单的双绑定:
<body>
    <div id="app">
    <input type="text" id="txt">
    <p id="show"></p>
</div>
</body>
<script type="text/javascript">
    var obj = {}
    Object.defineProperty(obj, 'txt', {
        get: function () {
            return obj
        },
        set: function (newValue) {
            document.getElementById('txt').value = newValue
            document.getElementById('show').innerHTML = newValue
        }
    })
    document.addEventListener('keyup', function (e) {
        obj.txt = e.target.value
    })
</script>

. computed watch data . ¥set .sync

computed :关联其他属性的 ,一旦被关联的属性发生变化,这个结果也跟着变,而且不涉及缓存,每次读取都会重新计算执行一次
watch :和 computed 很像 ,区别是:computed 必须有返回值,watch 不必,可以只是一个执行过程
data  :声明用于双向绑定的数据属性
$set   :data中没有声明,后续想插入一条 具有双向绑定特质的 数据属性
sync :用于组件间 此属性在任何父或是子组件中发生了变化都会同步更新,也就是和 组件内部的 data 中声明的属性是一个道理

. 生命周期
从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期

一共:10个
常用的:
- created: (创建后)完成数据观测,属性和方法的运算,初始化事件; 常常在这里拿数据

- beforeMount(载入前)编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。

- mounted:(载入后)dom 加载上来了,等同 dom ready onlod。可以做一些dom 的初始化操作

- updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。

. 懒加载
. 动态组件渲染
. mixins的特性
. Virtual DOM
. vue路由的钩子函数

首页可以控制导航跳转,beforeEach,afterEach等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。

beforeEach主要有3个参数to,from,next:

to:route即将进入的目标路由对象,

from:route当前导航正要离开的路由

next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转。

. 组件通信 vuex prop $emit

1.父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;实现:在子中props中先声明好属性名字,在父组件中调用子组件时候,在其身上 给这个声明好的属性名字赋上值。等同,儿子里挖好坑,父亲调用时填好。
子组件传给父组件:$emit方法传递参数

2.非父子组件间的数据传递,兄弟组件传值
eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。大的用vuex

. vuex是什么?怎么使用?哪种功能场景使用它?

只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中,view 层通过 store.dispath 来分发 action。。
在main.js引入store,注入。新建了一个目录store,….. export 。
场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车

. 路由模式:hash history

hash:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,
history:此模式下,首次页面上来,不会请求后台页面路径,怕刷新,二次刷,会请求后台,由于后台此路径下没有对应资源 直接404;处理:前端的 URL 必须和实际向后端发起请求的 URL 一致,如 [http://www.xxx.com/items/id](http://www.xxx.com/items/id)。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。

. keep-alive

是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
. css只在当前组件起作用
答:在style标签中写入scoped即可 例如:<style scoped></style>

. v-if 和 v-show 区别
答:v-if按照条件是否渲染,做dom树的增删操作,耗性能,v-show是display的block或none;


 
. $route和$router的区别
答:$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等。

 . vue.js的两个核心是什么?
答:数据驱动、组件系统

. vue几种常用的指令
答:v-for 、 v-if 、v-bind、v-on、v-show、v-else

. vue常用的修饰符?
答:.prevent: 提交事件不再重载页面;.stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;.capture: 事件侦听,事件发生的时候会调用

. v-on 可以绑定多个方法吗?
答:可以

. vue中 key 值的作用?

答:当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。

. 什么是vue的计算属性?

答:在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。

angular:
. 脏值检测
. mvc
. vue angular异同:

1.与AngularJS的区别
相同点:
都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。

不同点:
AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。

【十】 jq:

js => jq api 对应关系:

设置样式:
style --->css 

获取dom:
getEelementByX/ querySelect/All --->$('css选择器') 

创建dom:
var tag = $('<p>我是添加的结点</p>') ---> var tag = createEelement('p');tag.innerText = "我是添加的节点"

插入dom:
appendChild ---> append

类名赋值:
className ---> addClass('cur')
ex:$(this).addClass('cur').siblings().removeClass('cur');

dom内部内容:
innerHtml--->html()
innerText--->text()

表单元素的值:
value ---> val('')

请求:
 xhr对象 --->ajax({});


jq:1.9以下, IE所有版本都支撑,1.9以上 IE9+
jq插件:$.fn.extend, 插件挂在jq 对象的共享库上,任何jq的实例都可以调用到 $.extend 插件直接挂在jq 对象本身,也就是工具方法或是叫静态方法

image.png

其他

【一】看过的书:

. js高程:对原生js知识点解读的非常到位易懂。
. 网络层:图解HTTP(上野宣)
. js设计模式与开发实战:曾探-腾讯的 TODO(了解几种设计模式)
. nodejs:深入浅出nodeJs TODO(自己的一些小实践)

【二】网站:

. 掘金
. segmentFault
. 简书(主要自己会写点东西,有些写的认真,有些单纯自己记录下)
. 有空看看阮一峰的博客,讲的很细致系统。
. 谷歌的developers文档啥的



【三】浏览器调试工具

.


image.png
【四】js 扩充

.混入式继承,空对象通过遍历另外一个对象的属性赋值,拿过来进行继承。


[图片上传中...(image.png-9b7a9c-1561967598318-0)]

.


image.png

. instanceof
可以检测某个实例是不是某个对象的实例。--即可以检测数据类型是不是对象Object。

image.png

欢迎大家补充

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

推荐阅读更多精彩内容