JavaScript语法基础

一、关于变量
(1) 什么是变量
变量 Variable ,描述了程序中临时存储数据的容器

image.png

(2) 变量的声明
原生JavaScript中,有两种方式可以创建变量:

  • 可以直接通过一个自定义名称创建一个变量;
  • 使用var关键字创建变量(推荐)
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 声明了一个变量【尽管可以使用,但是项目规范中严禁使用】
    // 如果没有变量的声明关键字,当js中出现大量代码时,我们无法定位这个变量什么位置被第一次声明
    // 缺点:降低了代码的可读性
    name = "大牧"

    // 声明了另一个变量【推荐的操作方式】
    var age = 18

    console.log("name:", name)
    console.log("age:" , age)
  </script>
</body>
</html>

备注:关于es6中声明变量的操作

ES6语法标准中,提供了letconst用来声明变量和常量,主要用于补充原生JavaScript中的var关键字功能,相当于对变量的声明语法,提供了更多的功能扩展

注意:关于ES6语法标准,关注我,后面会单独讲解!

(3) 命名规则
原生 JavaScript 作为一种编程语言,内部可以通过一些符号表示一些数据,。样的符号称为标识符.
标识符中包含了关键字、变量
标识符命名规则:描述数据的符号由字母、数字、下划线、 $ 符号组成,其中
数字不能开头

① 关键字
编程语言本身已经内置使用了很多的英文单词,这些内置的单词都称为关键字,如 var
可以参考一下都有哪些关键字,没有必要去记忆,使用的过程中可以根据程
序是否报错直接进行代码调整
下图中是一些常见关键字

image.png

② 变量
代码开发过程中,开发人员为了存储数据自定义的符号;注意不能使用关键字
变量的命名,遵循标识符的命名规则、不能使用关键字

var height = 175 // √
var shenGao = 180 // √
var w = 80 // √
var 1 = 80 // X
var this = 80 // X
var gender = '男' // √
var &gender = '女' // X ? √
var address = '河南省郑州市'   // √
var _addr = '河南省开封市' // √
var $addr = '河南省焦作市' // X ? √
var 2addr = '河南省濮阳市' // X
var %intro = '个人介绍' // X ? √
var intro% = '个人介绍' // X ? √
var intro_personal = '个人介绍' // √

(4)命名规范
大量的项目实践中,为了提高代码的阅读性/可读性,以及提高查看代码的效率;对变量名称的命名有一定的开发规范

  • 见名知意
  • 驼峰命名法:一个或者多个单词(拼音)组成,第一个单词(拼音)全部小写,后面每个单词(拼音)首字母大写
<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
  <script>
    // 这四个变量,分别表示了什么意思?
    var a = 12
    var b = 80
    var c = 180
    var d = 1

    // 这四个变量,分别表示了什么意思?
    var shenGao = 178
    var tiZhong = 80
    var xingBie = 1
    var nianLing = 16     // ninaLing(【小】驼峰命名法)   NianLing(大驼峰命名法 | 帕斯卡命名法)
    // 这四个变量,分别表示了什么意思?
    var height = 180
    var weight = 75
    var gender = 0
    var age = 20
    // 下面两个变量,那个变量语法更加人性化/更容易阅读
    var xian = "xxxx"
    var xiAn = "xxxxx"
    var xian = "xxxxx"
    var gerenjieshao = "........"
    var geRenJieShao = "xxxxxxxx"
    var personalIntroduce = "......"
    var personalintroduce = "xxxxxx"
  </script>
</body>
</html>

(5) 变量的赋值
变量作为一个存储数据的容器,需要添加数据之后才能正常访问,数据访问方式主要有:存储数据、查询数据、修改数据以及删除数据
变量中存储数据的方式就是变量的赋值操作,需要使用 赋值运算符:=

<script>
    // 1、赋值方式(默认)
    // 使用赋值语句,给单个变量中存储数据
    var version = "V1.0.0"
    console.log("version:", version)

    // 2、连续赋值
    // 项目开发中使用到多个变量,初始数据都是一致的
    // 1 1 2 3 5 8... 斐波那契数列
    // 基本赋值
    var n1 = 1
    var n2 = 1
    console.log("n1:", n1, ",n2:", n2)

    var n3 = n4 = 1
    console.log("n3: ", n3, ", n4:", n4)

    // 3、项目中某些场景下,多个变量初始数据不一致
    var name = '大牧', age = 20, gender = '男'
    console.log('name:', name, ", age:", age, ", gender:", gender)

    // 4、注意的问题:关于变量的交叉赋值
    // var name, age = '大牧', 28 
    // 期望  name="大牧" age=28; js语法中不支持

  </script>

(6) 变量的使用
项目中的数据操作,根据操作方式主要区分为两种

  • 数据的操作:数据作为一个独立的整体,可以执行存储、查询、修改、删除,简称增删改查
    • 增删改查:简称CRUD
    • C:Create 增加、R:Retrieve 查询、U:Update 修改、D:Delete 删除
  • 数据的运算:数据和数据之间,通过运算符执行运算,一般都是基础的加减乘除...
    变量的使用,区分增加、修改、查询和删除的操作
  • 增加:声明变量赋值的过程
  • 查询:通过变量名称,获取变量中数据的过程
  • 修改:给指定的变量重新赋值的过程
  • 删除:
    • 业务删除:项目开发中,约定变量中存储一个无效数据,表示该数据被删除;变量依然存在
    • 真实删除:项目代码中,使用delete关键字针对变量进行物理删除,很容易造成代码稳定性问题,语法上受到一定的限制,如不能直接删除var声明的变量
<script>
    // 声明变量
    // 声明变量的同时可以赋值;也可以声明变量以后再进行赋值
    var myName;   // 等价于:var myName = undefined(未定义)
    console.log("myName:", myName)

    // 赋值:增加数据
    myName = "damu"
    console.log("myName:", myName)

    // 修改数据:给变量中存储新的数据,覆盖旧的数据
    myName = "大牧"
    console.log("myName:", myName)

    // 删除数据:对于已经不再使用的变量,需要删除变量释放占用的系统资源
    // 业务中的删除,并不建议直接删除变量,而是给变量赋值一个(开发规范)约定的空值
    // 1- 约定空字符串,表示删除了数据
    // 2- 约定undefined,表示删除了数据
    myName = ""
    console.log("myName: ", myName)

    // 只有在特殊的情况下,才会真实删除变量
    // 直接删除变量的操作是一种敏感并且危险的操作: 变量一旦真实删除,代码中再次使用很容易出现问题
    // delete语句对于var声明的变量,目前语法上不支持删除DontDelete
    // delete myName
    // console.log("myName delete:", myName)
</script>

(7) 变量预解析

// 练习1
// 项目中我想使用班级的名称 
console.log("班级名称:", className)
// Uncaught Reference Error: className    is not defined
// 未捕获的  引用       错误:className变量  没有    定义
// 一旦程序报错,后面的代码不会执行(程序崩溃退出)


// 练习2
// 项目中变量的使用规则:先声明后使用
var className = "精品班"
console.log("班级名称:", className)


// 练习3
// 变量的预解析 
console.log("班级名称:", className) // undefined,没有报错?!
var className = "精品班"
console.log("班级名称:", className) // "精品班"


// 练习4
// 为什么没有报错?var关键字声明的变量,存在预解析功能
// 预解析:也称为变量提升,将变量的声明语句提升最前面,赋值还在原来的位置
// 上面的代码,等价于:
var className; // 变量预解析:提升了变量的声明,保障当前程序代码运行正确性(容错性)
console.log("班级名称:", className) // undefined,没有报错?!
className = "精品班"
console.log("班级名称:", className) // "精品班"

二、数据类型
(1) 认识数据类型
可以表示各种数据的类型的概念编程语言中,通过具体的代码,描述对应的数据类型!
(2) 基本数据类型(掌握)
原生JavaScript中提供了6种基本数据类型

  • 数值:Number
  • 字符串:String
  • 布尔:Boolean
  • 空值:Null
  • 未定义:Undefined
  • 对象(一切皆对象):Object
// String 字符串类型,可以使用双引号、单引号包含起来的一串字符
// 开发规范中:一般推荐或者要求使用单引号包含的语法
// 描述一个人的姓名
var name = "廉颇" // var name = '廉颇'
console.log('姓名:',name)

// Number 数值类型,包含整数和小数(浮点数)
// 描述一个人的身高
var height = 1.75
// 描述一个人的体重
var weight = 80
console.log('height身高:',height)
console.log('weight体重:',weight)

// Boolean 类型,布尔类型,只有两种取值:true / false
// 描述一个人是否存活|该用户账号是否可用
var status = true   // false
console.log('status可用:',status)

// undefined:表示无效数据,未定义数据
// 描述一个无效数据
var jobs;   // var jobs = undefined
console.log('jobs工作:',jobs)

// null:表示空值,表示一种没有任何数据的状态
// 描述一个空数据
var address = null
console.log('address地址:',address)

(3) 复杂数据类型(了解)
原生JavaScript中也提供了一些复杂数据类型,用于描述一些较为复杂的事物,如:常见的复杂类型

  • Array:数组
  • Function:函数
  • Object:对象
  • Math:处理数学运算的类型
  • Date:处理日期时间的类型
  • RegExp:处理正则表达式的类型
  • UUID:处理唯一数据的类型
// 复杂类型的基本使用
// 1、数组
var names = ["老王", "小李", "大黄", "小灰"]
console.log(names)

// 2、日期
var date = new Date()
console.log("今年是:", date.getFullYear(), ",月份:", date.getMonth() + 1)

// 3、随机数:得到一个验证码
var rcode = Math.random().toString(36).substr(2, 6)
console.log("随机验证码:", rcode)

(4) 查看类型

  • typeof(dat):简易的数据类型查看方式,适用于大部分场景
  • Object.prototype.toString.call(dat):数据类型原型查看方式
// 定义基本类型
var name = "耀"
console.log(name, typeof name)  // 耀 string

var hero = "娜可露露"
console.log(hero, typeof(hero)) // 娜可露露 string

var height = 20
console.log(height, typeof(height)) // 20 'number'

var pi = 3.1415
console.log(pi, typeof(pi))  // 3.1415 'number'

// status 单词,和前面用过的name一样,浏览器软件里面已经使用过这个变量
var sts = true
console.log(sts, typeof(sts)) // true  'boolean'

var address = undefined;
console.log(address, typeof(address))  // undefined 'undefined'

var intro = null
console.log(intro, typeof(intro)) // null 'object'
// 基本类型中存在Null类型,为什么这里打印object类型?有争议的类型
console.log(intro, Object.prototype.toString.call(intro)) // null '[object Null]'


// 复杂类型
var names = ["李信", "吕布"]
console.log(names, typeof(names)) // ['李信', '吕布'] 'object'
console.log(names, Object.prototype.toString.call(names)) // ['李信', '吕布'] '[object Array]'

var date = new Date()
console.log(date, typeof(date)) // 
console.log(date, Object.prototype.toString.call(date)) //

(5) 类型转换
项目中原生JavaScript数据的表示方式,同一个数据可能会以不同类型的形式表示出来;进行数据运算(加减乘除)的时候很容易出现错误运算结果;需要掌握类型的转换技术

  • 转换成字符串
    • 字符串拼接
    • String(dat)
    • dat.toString()
  • 转换成数值
    • Number(dat)
    • parseInt(dat)
    • parseFloat(dat)
  • 转换成布尔(字符串、数值、null/undefined
    • Boolean(dat)
// 同一个数据,可以是不同的类型
// var n1 = 3.14   // number
// var n2 = '3.14' // string

// var b1 = true     // boolean
// var b2 = 'false'  // string

// 需要进行类型转换(大部分类型转换都是基本类型的转换)
// 练习1、将其他类型转换成字符串类型
var x = 12
console.log(x, typeof(x))

var x1 = x + ''
console.log(x1, typeof(x1))
var x2 = String(x)
console.log(x2, typeof(x2))
var x3 = x.toString()
console.log(x3, typeof(x3))

var b = true
var b1 = String(b)
console.log(b1, typeof(b1))   // 'true'  string
var n = null
var n1 = String(null)
console.log(n1, typeof(n1))   // 'null'  string
var u = undefined
var u1 = String(u)
console.log(u1,  typeof(u1))  // 'undefined' string

// 练习2、转换成数值
var age = '20.01'
console.log(age, typeof(age))  // '20' string

// 转换成数值
var a1 = Number(age)
console.log(a1, typeof(a1))  // 20.01 number

// 转换成整数
var a2 = parseInt(age)
console.log(a2, typeof(a2))  //  20 number

// 转化成浮点数
var a3 = parseFloat(age)
console.log(a3, typeof(a3)) //  20.01 number

// 特殊转换
var money = "200元"
var m1 = parseInt(money)
console.log(m1, typeof(m1))  //  200 number

money = "¥200元"
m1 = parseInt(money)
// NaN(具体数据): not a number不是一个数值;属于数值类型
console.log(m1, typeof(m1))  //  NaN  number

// 其他类型
// 布尔类型,true -> 1;false -> 0
var b = true
var b1 = Number(b)
console.log(b1, typeof(b1))  //  1  number

// null 和 undefined
var n = null
var n1 = Number(n)
console.log(n1, typeof(n1), "Number") //  0 number
var n2 = parseInt(n)
console.log(n2, typeof(n2), "parseInt") // NaN number

var u = undefined
var u1 = Number(u)
console.log(u1, typeof(u1))  // NaN number
var u2 = parseInt(u)
console.log(u2, typeof(u2))  // NaN number

// 练习3、布尔类型
// 字符串转换布尔类型 
// 空字符串-> false,非空字符串->true
var s = ""    // 空字符串
var s2 = "  "  // 包含空白字符的字符串
var s3 = "helloworld" // 非空字符串

var s01 = Boolean(s)
console.log(s01, typeof(s01)) // false boolean

var s02 = Boolean(s2)
console.log(s02, typeof(s02)) // true boolean

var s03 = Boolean(s3)
console.log(s03, typeof(s03)) // true boolean

// 数值转换成布尔类型
// 0-> false, 非0-> true
var n1 = -10
var n2 = 0
var n3= 10

var n01 = Boolean(n1)
console.log(n01, typeof(n01)) // true, boolean

var n02 = Boolean(n2)
console.log(n02, typeof(n02)) // false booelean

var n03 = Boolean(n3)
console.log(n03, typeof(n03)) // true boolean

// null和undefined
var n = null
var n01 = Boolean(n)
console.log(n01, typeof(n01)) // false 'boolean'

var u = undefined
var u01 = Boolean(u)
console.log(u01, typeof(u01)) // false 'boolean'

(6) 显式/隐式转换

// 加法运算:参与运算的数据,无法执行隐式转换,所以得到错误结果
// 通过固定语法,将类型进行转换后完成数据运算:显示类型转换
// 1.
var price = '20'
var total = price + price
var totalx = parseInt(price) + pasreInt(price) // 显式转换
console.log('total:', total)  // total: 2020 期望以外的错误结果(代码没有报错)

// 数据的隐式类型转换:数据参与运算时,类型在运算过程中进行了自动匹配转换

// 2. 字符串和数值执行乘法运算时,出现了类型自动转换(字符串-> 数值-> 参与运算)
var price2 = '30'
var cnt = 2
var total2 = price2 * 2 // 字符串 乘以 数值
console.log('total2:', total2) // total2: 60

// 3. 字符串和字符串执行减法运算时,出现类型自动转换(字符串-> 数值-> 参与运算)
var pay = '180'
var money = '200'
var balance = money - pay  // 字符串 减法 字符串
console.log("找零:", balance) // 找零: 20


// 4. 数值执行保留小数位数操作时,出现类型自动转换(数值-> 字符串)
var pi = 3.1415926
var pi2 = pi.toFixed(2) // 保留两位小数位数
console.log(pi2, typeof(pi2)) // 3.14 string

三、运算符
(1) 关于数据的表示
编程语言中,一般处理数值数据,会有不同的进制表示方式:

  • 二进制(逢二进一):0, 1, 10, 11, 100, 101, 110, 111...
  • 八进制(逢八进一):0,1,2,3,4,5,6,7,10,11,12,13,14,15,16,17,20....
  • 十进制(逢十进一):0,1,2,3,4,5,6,7,8,9,10,11,12,...
  • 十六进制(逢十六进一):0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f,10,11,12,....
    (2) 赋值运算符
符号 描述
= 将等号右侧的数据,赋值给左侧的变量
// 赋值操作
var name = "damu"

(3) 算术运算符

符号 描述
+ 加法运算
- 减法运算
* 乘法运算
/ 除法运算
% 取余数运算
++ 自增运算
-- 自减运算

++在后,是先赋值后自增 j=i j=i+1; 变量赋予的是旧值,也就是1

++在前:先自增后赋值 i=1+i j=i 变量赋予的是新值 也就是2.

--同上。

// 2、算术运算符
var n1 = 12 
var n2 = 5

console.log(n1 + n2) //  17
console.log(n1 - n2) // 7
console.log(n1 * n2) // 60
console.log(n1 / n2) // 2.4
console.log(n1 % n2) // 2(整除的情况下得到的余数)

// 自增运算
n1++      // 独立出来的,++符号放在前面和后面没有区别
console.log('n1',n1)  // 13
++n1
console.log('n1',n1)  // 14

// 自增赋值
var x1 = n1++   // 先赋值,后加加
console.log(x1,',x1, ', n1, ",n1") // 14 ',x1, ' 15 ',n1'

var x2 = ++n1   // 先加加,后赋值
console.log(x2, ',x2, ', n1, ",n1") // 16 ',x2, ' 16 ',n1'

注意事项:算术运算符可以和赋值运算符进行混合使用

符号 描述
+= a += 1<br />等价于<br />
// 2.1、混合运算符
var num = 12
// num += 10
num = num + 10
console.log(num, ": num")

(4) 比较运算符
项目中经常做一些数据的比较操作,通过返回的数据(布尔类型的)体现比较的结果(true | false

符号 描述
> 大于
>= 大于等于
< 小于
<= 小于等于
== 等于
!= 不等于 !=
=== 全等于= = =
!== 不全等于!==
// 3、比较运算符
var age = 17      // 真实年龄
var verify = 20   // 限制年龄

console.log(age > verify)  // false:age不大于verify
console.log(age >= verify)  // false
console.log(age < verify)  // true:age数据小于verify数据
console.log(age <= verify) // true

age = 20
console.log(age == verify) // true 相等
console.log(age != verify) // false

age = '20'
console.log(age == verify) // true age中的数值和verify数值相等
console.log(age === verify) // false: age和verify,数据类型或者数值不相同
console.log(age !== verify) // true

// 字符串,通过ascii码(整数)表示
// 字符串进行比较运算时,自动通过ascii码进行判断
var c1 = "a"    // 字母a ascii: 97
var c2 = "b"    // 字母b ascii:98
console.log(c1 > c2) // false,"a"不大于"b"

// 字符串中包含多个字符时,逐位比较
var c3 = "ab"
var c4 = "abc"
console.log(c3 > c4) // false

(5) 逻辑运算符

符号 描述
&& 并且关系,多个条件同时为true返回true
! 取反

|| 或者关系,多个条件只要有一个为true返回true

// 4、逻辑运算符
// 账号+密码,同时正确,表示登录成功
var uname = "admin"
var upass = "123"

// 判断账号密码是否正确
console.log("admin" === uname && "1234" === upass) 
// true:账号密码正确
// false:提示账号或者密码有误

// 用户可以使用账号或者手机号码登录
var uname = "admin"
var uphone = "15899990000"
var upass = "123"
console.log(
  ('admin' === uname || '15899990000' === uphone)
  &&
  "123" === upass
) // true: 账号|手机号码 + 密码输入正确
// false:账号|手机号码  或者 密码有误


// 注册一个账号,判断账号是否合法
var account = "admin" // 模拟用户输入
console.log(Boolean(account)) // false,提示-注册账号不能为空
// true,用户输入了账号,可以继续注册
console.log(!Boolean(account)) // 和上一行代码的结果刚好相反,为了方便明天要学的合法性if判断

(6) 三元运算符

符号 描述
条件 ? 结果1 : 结果2 执行表达式中的?符号前面的条件运算<br />条件为true执行结果1中的代码<br />条件为false执行结果2中的代码
// 5、三元运算符
var uname = "admin"
var upass = "123"

var name = prompt("请输入账号:")
var pass = prompt("请输入密码:")

name === uname && pass === upass ? alert("用户登录成功"): alert("账号或者密码有误")

(7) 位运算符(了解)

符号 描述
& 与运算,1 - 1 -> 1、1 - 0 -> 0 、0 - 0 -> 0<br />eg: 1 & 2 => ?<br />eg: 01 & 10 => 00
^ 异或运算:1-1-> 0、0-0-> 0、1-0-> 1
>> 右移运算,100 -> >> -> 010<br /> 4 4>>1 2
<< 左移运算,010 -> << -> 100<br /> 2 -> 2<<1 -> 4

| | | 或运算:1 - 1 -> 1、1- 0-> 1、0 - 0 -> 0<br />eg: 1 | 2 => ?<br />eg: 01 | 10 => 11 |

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

推荐阅读更多精彩内容