学习《JavaScript经典实例》之第1~3章

《JavaScript经典实例》各节中的完整代码解决了常见的编程问题,并且给出了在任何浏览器中构建Web应用程序的技术。只需要将这些代码示例复制并粘贴到你自己的项目中就行了,可以快速完成工作,并且在此过程中学习JavaScript的很多知识。

第1章 JavaScript不只是简单的构件块

1.1 JavaScript对象、基本类型和字面值之间的区别

  • 5种基本类型:字符串、数值、布尔值、null、undefined,有3个有对应的构造方法对象:string、Number、Boolean

  • 基本类型变量严格等于字面值,而对象实例则不会,因为基本类型是按值来比较的,而值是字面值

var num1 = 123;
var num2 = new Number(123);
console.log(typeof num1);  //number 
console.log(typeof num2);  //object

1.2 从字符串提取一个列表

  • 提取之前:This is a list of items: cherries, limes, oranges, apples.
  • 提取之后:['cherries','limes','oranges','apples']
  • indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
  • substring() 方法用于提取字符串中介于两个指定下标之间的字符。
  • split() 方法用于把一个字符串分割成字符串数组。
var sentence = 'This is one sentence. This is a sentence with a list of items: cherries, oranges, apples, bananas. That was the list of items.';
var start = sentence.indexOf(':');
var end = sentence.indexOf('.', start+1);
var listStr = sentence.substring(start+1, end);
var fruits = listStr.split(',');
console.log(fruits);  //[" cherries", " oranges", " apples", " bananas"]

//取出空格等
fruits.forEach(function(elmnt,indx,arry) {
    arry[indx] = elmnt.trim();
});
console.log(fruits);  //["cherries", "oranges", "apples", "bananas"]

1.3 检查一个存在的、非空的字符串

  • 想要验证一个变量已经定义了,是一个字符串,并且它不为空
if(typeof unknowVariable === 'string' && unknowVariable.length > 0) {...}

1.4 插入特殊字符

  • 想要向字符串中插入一个特殊字符,例如一个换行
  • 转义序列都以一个反斜杠 开始(\)

1.5 使用新字符串替换模式

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

正则表达式特殊字符

字符 匹配 例子
^ 匹配输入的开头 /^This/ 匹配This is...
$ 匹配输入的结束 /end$/ 匹配This is the end
* 匹配0次或多次 /se*/ 匹配s seeee或se
? 匹配0次或1次 /ap?/ 匹配apple and and
+ 匹配1次或多次 /ap+/ 匹配apple 但是不匹配and
{n} 严格匹配n次 /ap{2}/ 严格匹配apple 但是不匹配apie
{n,} 匹配n次或多次 /ap{2,}/ 匹配apple中的p,但是不匹配apie中的p
{n,m} 至少匹配n次,之多匹配m
除换行以外的任何字符
/ap{2,4}/ 匹配apppppple中的4个p
/a.e/ 匹配ape和axe
[...] 方括号中的任何字符 /a[px]e/ 匹配ape axe 但是不匹配apxe
[^...] 除了方括号以外的任何字符 /a[^px]/ 匹配ale 但是不匹配ape axe
\b 匹配单词边界 /\bno/ 匹配nono中的第一个no
\B 匹配非单词边界 /\Bno/ 匹配nono中的第二个no
\d 数字0到9 /\d{3}/ 匹配Now in 123 中的123
\D 匹配任何非数字字符 /\D{2,4}/ 匹配Now in 123 中的Now in
\w 匹配任何单词字符(字母、数组和下划线 /\w/ 匹配javaScript中的j
\W 匹配任何非单词字符(非字母、数组和下划线) /\W/ 匹配100%中的%
\n 匹配一个换行
\s 一个单个的空白字符
\S 一个单个的非空白字符
\t 一个制表符
(x) 捕获括号 记住匹配的字符
var searchString = "Now is the time, this is the tame";
var re = /t\w{2}e/g;
var replacement = searchString.replace(re, 'place');
console.log(replacement);  //Now is the place, this is the place

1.6 找到并突出显示一个模式的所有实例

  • RegExp exec() 方法用于检索字符串中的正则表达式的匹配
  • RegExpObject.exec(string)
  • 返回一个数组,其中存放匹配的结果。如果未找到匹配,则返回值为 null
var searchString2 = "Now is the time and this is the time and that is the time";
var parttern = /t\w*e/g;  //\w 匹配任何单词字符
var matchArray;

var str = "";

//用regexp exec检查模式,如果不为空,处理它
while((matchArray = parttern.exec(searchString2)) != null) {
    str += "at " + matchArray.index + " we found " + matchArray[0] + "\n";
}
console.log(str);
// at 7 we found the
// at 11 we found time
// at 28 we found the
// at 32 we found time
// at 49 we found the
// at 53 we found time
//实例1-1
document.getElementById("searchSubmit").onclick = function() {

    //获取模式
    var pattern = document.getElementById("pattern").value;
    var re = new RegExp(pattern, "g");
    //获取字符串
    var searchString = document.getElementById("inComing").value;
    
    var matchArray;
    var resultString = "<pre>";
    var first = 0;
    var last = 0;
    
    //找到每一个匹配
    while((matchArray = re.exec(searchString)) != null) {
        last = matchArray.index;
    
        //获取所有匹配的字符串,将其连接起来
        resultString += searchString.substring(first, last);
    
        //使用class,添加匹配的字符串
        resultString += '<span class="found">' + matchArray[0] + '</span>';
        first = re.lastIndex;
    }
    
    //完成字符串
    resultString += searchString.substring(first, searchString.length);
    resultString += "</pre>";
    
    //插入页面
    document.getElementById("searchResult").innerHTML = resultString;

}

1.7 使用捕获圆括号交换一个字符串中的单词

  • 交换名称,让姓氏先出现
  • 解决:使用捕获圆括号和一个正则表达式在字符串中找到并记住他们的名字,然后互换他们
  • replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
字符 替换文本
1、2、...、$99 与 regexp 中的第 1 到第 99 个子表达式相匹配的文本。
$& 与 regexp 相匹配的子串。
$` 位于匹配子串左侧的文本。
$' 位于匹配子串右侧的文本。
$$ 允许替换中有一个字面值美元符号($)
$n 插入使用RegExp的第n次捕获圆括号的值
var myName = "Tao Yang";
var nameRe = /^(\w+)\s(\w+)$/;
var myNewName = myName.replace(nameRe, "$2 $1");
console.log(myNewName);  //Yang Tao

1.8 使用命名实体来替代HTML标签

  • 使用正则表达式把尖括号(<>)转换为命名的实体:<和>
var pieceOfHtml = "<p>This is a <span>paragraph</span></p>";
pieceOfHtml = pieceOfHtml.replace(/</g, "&lt;");
pieceOfHtml = pieceOfHtml.replace(/>/g, "&gt;");
console.log(pieceOfHtml); //&lt;p&gt;This is a &lt;span&gt;paragraph&lt;/span&gt;&lt;/p&gt;

1.9 ISO 8610格式的日期转换为Date对象可接受的一种形式

var dtstr = "2014-3-04T19:35:32Z";
dtstr = dtstr.replace(/\D/g, " ");
console.log(dtstr);  //2014 3 04 19 35 32
var dtcomps = dtstr.split(" ");
//在基于1的ISO 8610月份和基于0的日期格式之间转换
dtcomps[1]--;

var convdt = new Date(Date.UTC.apply(null, dtcomps));
console.log(convdt.toString());  //Wed Mar 05 2014 03:35:32 GMT+0800 (中国标准时间)

1.10 使用带有定时器的函数闭包

  • 使用一个匿名函数作为setInterval()或setTimeout()方法调用的第一个参数
var intervalId = null;
document.getElementById("redbox").addEventListener('click', startBox, false);
function startBox() {
    if(intervalId == null) {
        var x = 100;
        intervalId = setInterval(function() {
            x += 5;
            var left = x + "px";
            document.getElementById("redbox").style.left = left;
        }, 500);
    } else {
        clearInterval(intervalId);
        intervalId = null;
    }
}

1.11 记录两个事件之间消耗的时间

  • 在第一个事件发生的时候,创建一个Date对象,当第二个时间发生的时候,创建一个新的Date对象,并且从第二个对象中减去第一个对象。两者之间的差以毫秒表示的,要转换为秒,就除以1000
  • 两个日期可以相减,但是相加就成了拼接字符串
var firstDate = new Date();
setTimeout(function() {
    doEvent(firstDate);
}, 25000);

function doEvent() {
    var secondDate = new Date();
    var diff = secondDate - firstDate;
    console.log(diff);   //25001
}

1.12 十进制数转化为十六进制值

var num = 255;
console.log(num.toString(16));  //ff

1.13 想要将表中一列的所有数字加和

  • 遍历表中包含了数字值的列,将其转换为数字,并加和
  • querySelector() 方法返回文档中匹配指定 CSS 选择器的一个元素
  • 如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代
  • 全局函数 parseInt()parseFloat() 都把字符串转化为数字
var sum = 0;
//使用querySelectorAll找到第二列的所有单元格
var cells = document.querySelectorAll("td:nth-of-type(2)");
for(var i=0, l=cells.length; i<l; i++) {
    sum += parseFloat(cells[i].firstChild.data);
}

1.14 在角度和弧度之间转换

  • 将角度转换为弧度
var radians = degrees * (Math.PI / 180);

  • 将弧度转化为角度
var degrees = radians * (180 / Math.PI);

1.15 找到页面元素可容纳的一个圆的半径和圆心

  • Math.min(x,y)方法可返回指定的数字中带有最低值的数字。
  • 求出宽度和高度中较小的一个,用其除以2得到半径
var circleRadius = Math.min(elemengWidth, elemengHeight) / 2;
  • 给指定页面元素的宽度、高度,通过将二者都除以2来找到其中心点
var x = elemengWidth / 2;
var y = elemengHeight / 2;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>将一个SVG圆放入到一个div元素中</title>
    <style type="text/css">
        #elem {
            width: 100%;
            height: 500px;
            border: 1px solid #ddd;
            background-color: #ddd;
        }
    </style>
</head>
<body>

    <div id="elem">
        <svg width="100%" height="100%">
            <circle id="circ" width="10" height="10" r="10" fill="#f90">
        </svg>
    </div>


    <script type="text/javascript">
    window.onload = window.onresize = function() {
        var box = document.getElementById("elem");
        var style = window.getComputedStyle(box, null);
        var width = parseInt(style.getPropertyValue("width"));
        var height = parseInt(style.getPropertyValue("height"));
        console.log('w', width, 'h', height);
        var x = width / 2;
        var y = height / 2;

        var circleRadius = Math.min(width, height) / 2;

        var circ = document.getElementById("circ");
        circ.setAttribute("r", circleRadius);
        circ.setAttribute("cx", x);
        circ.setAttribute("cy", y);
        console.log('r', circleRadius, ' cx', x, ' cy', y);
    }
    </script>
</body>
</html>

1.16 计算圆弧的长度

  • 给定了一个圆的半径及圆弧角的角度值,求该圆弧的长度
  • 使用Math.PI把角度转换为弧度,并在公式中使用该结果来求得圆弧的长度
var radians = degrees * (Math.PI / 180);
var arclength = radians * radians;

第2章 JavaScript数组

2.1 在数组中搜索

  • indexOf()、lastIndexOf()
var animals = new Array('dog', 'cat', 'seal', 'elephant', 'walrus', 'lion');
var index = animals.indexOf('cat');
var index2 = animals.lastIndexOf('lion');
console.log('i',index);  //1
console.log('i2',index2);  //5
  • findIndex() 方法返回传入一个测试条件(函数)符合条件的数组第一个元素位置。
var nums = [2, 4, 199, 80, 400, 30, 90];
var over = nums.findIndex(function(ele) {
    return (ele >= 100);
});
console.log('nums',nums[over]);  //199

2.2 用concat()和apply()将一个二维数组扁平化

  • concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
    • arrayObject.concat(arrayX,arrayX,......,arrayX)
var fruitarray = [];
fruitarray[0] = ['stranwberry', 'orange'];
fruitarray[1] = ['lime', 'peach', 'banana'];
fruitarray[2] = ['tangerine', 'apricot'];
console.log('array',fruitarray.concat());
var newArray = fruitarray.concat.apply([], fruitarray);
console.log(newArray);
function add(a, b) {
    console.log('add', this);
}
function sum(a, b) {
    console.log('sum', this);
}
add(1, 2);  //Window
sum(1, 2);  //Window

add.call(sum, 1, 2);  //sum(a, b)
sum.call(add, 1, 2);  //add(a ,b)
  • arguments装换为数组, 返回的是数组,但是arguments本身保持不变
var arg = [].slice.call(arguments);
// [].slice.call(document.getElementsByTagName('li'));
  • 借用别人的方法
var foo = {
    name: 'jack',
    showName: function() {
        console.log('this name:',this.name);
    }
}
var bar = {
    name: 'rose'
}
foo.showName();  //jack
foo.showName.call(bar);  //rose
  • 实现继承
var Student = function(name, age, high) {
    Person.call(this, name, age);
    this.high = high;
}
  • 封装对象保证this的指向
var _this = this;
_this.$box.on('mousedown', function()) {
    return _this.fndown.apply(_this);
}

2.3 删除或替换数组元素

  • splice() 方法与 slice() 方法的作用是不同的,splice() 方法会直接对数组进行修改。
var animals = new Array('dog', 'cat', 'rabbit', 'pig', 'apple');
// 从数组删除元素
animals.splice(animals.indexOf('apple'), 1);
console.log(animals);  // ["dog", "cat", "rabbit", "pig"]
// 替换
animals.splice(animals.indexOf('pig'), 1, 'monkey');
console.log(animals);  //["dog", "cat", "rabbit", "monkey"]

// 使用循环和分割来替换和删除元素
var charSets = ["ab", "bb", "cd", "ab", "cc", "ab", "dd", "ab"];
while(charSets.indexOf('ab') != -1) {
    charSets.splice(charSets.indexOf('ab'), 1, '**');
}
console.log(charSets);  //["**", "bb", "cd", "**", "cc", "**", "dd", "**"]
while(charSets.indexOf('**') != -1) {
    charSets.splice(charSets.indexOf('**'), 1);
}
console.log(charSets); //["bb", "cd", "cc", "dd"]

2.4 提取一个数组中的一部分

  • 不更改原数组,使用slice()
var animals = new Array('dog', 'cat', 'rabbit', 'pig', 'apple');
var newAnimals = animals.slice(1, 2);
console.log(animals);  //["dog", "cat", "rabbit", "pig", "apple"]
console.log(newAnimals);  //["cat"]

2.5 对每一个数组元素应用一个函数

var charSets = ["ab", "bb", "cd", "ab", "cc", "ab", "dd", "ab"];
charSets.forEach(function(element, index, array) {
    if(element == 'ab') array[index] = '**';
});
console.log(charSets);  //["**", "bb", "cd", "**", "cc", "**", "dd", "**"]

2.6 使用forEach()和call()遍历querySelectorAll()的结果

var cells = document.querySelectorAll('td + td');
[].forEach.call(cells, function(cell) {
    sum += parseFloat(cell.firstChild.data);
});

2.7 对数组中的每个元素执行一个函数并返回一个新数组

  • 将一个十进制的数组转化为新的等价的十六进制数组
  • map()方法创建一个新数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果。
  • 与forEach()不同,不会修改原数组,但是必须返回一个值
var decArray = [23, 3, 24, 45, 500, 9, 70];
var hexArray = decArray.map(function(ele) {
    return ele.toString(16);
});
console.log(decArray);  //[23, 3, 24, 45, 500, 9, 70]
console.log(hexArray);  //["17", "3", "18", "2d", "1f4", "9", "46"]

2.8 创建一个过滤后的数组

  • filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素。
var charSet = ['**', 'bb', 'cc', '**', 'cd'];
var newArray = charSet.filter(function(element, index, array) {
    return element != "**";
});
console.log(newArray);  //["bb", "cc", "cd"]

2.9 验证数组内容

  • 使用Array every()方法来检查每个元素是否符合给定的条件
  • some() 方法确保至少某些元素符合该条件
  • 区别:every()方法只要函数返回一个false值,处理就会结束,而some()方法会继续测试每个元素,直至返回true,此时,不再验证其他元素,即可返回ture
function testValue(element, index, array) {
    var testExp = /^[a-zA-Z]+$/;
    return testExp.test(element);
}
var elemSet = ['**', 123, 'adv', '-', 45, 'AAA'];
var result = elemSet.every(testValue);
var result2 = elemSet.some(testValue);
console.log(result);  //false
console.log(result2);  //true

var elemSet2 = ['aaa', 'animals', 'vvv'];
result = elemSet2.every(testValue);
result2 = elemSet2.some(testValue);
console.log(result);  //true
console.log(result2);  //true

2.10 使用一个关联数组来存储表单元素名和值

  • keys() 方法返回一个新的Array迭代器,它包含数组中每个索引的键。
var elemArray = {};
var elem = document.forms[0].elements[0];
elemArray[elem.id] = elem.value;
var elemArray = {name: 'yt', age:25};
Object.keys(elemArray).forEach(function(key) {
    var value = elemArray[key];
    console.log(value);
});

第3章 JavaScript的构建块

3种基本的创建函数方式:

  • 声明式函数
  • 匿名函数或函数构造函数
  • 函数字面值或函数表达式

3.1 放置函数并提升

  • 声明式函数,可以放置在代码中的任何位置;函数表达式,必须将其放置在使用函数的位置之前
// 在声明一个变量之前打印a
console.log('a', a);  //undefined
var a;
// 在声明一个变量并赋值
console.log('aa', aa);  //undefined
var aa = 1;

// 声明变量发生了提升,但是赋值并没有,赋值是在相应的位置发生的

// 声明式函数,在访问该函数之前,提升将确保把函数声明移动到当前作用域的顶部
console.log(mytest());  //success
function mytest() {
    return 'success';
}
// 使用函数表达式就会报错,变量可能声明了,但没有实例化,但是你的代码试图将这个变量当做一个函数对待
console.log(mytest2());  //TypeError: mytest2 is not a function
var mytest2 = function() {
    return 'success2';
}

3.2 把一个函数当做参数传递给另一个函数

function otherFunction(x, y, z) {
    x(y, z);
}
// 可以像传递一个命名的变量一样,将一个函数作为参数传递给另一个函数
var param = function func(a1, a2) { alert(a1 + " " + a2); };
otherFunction(param, "Hello", "World");
  • 函数式编程和JavaScript
    • 高阶函数: 一个函数接受另一个函数作为参数,或者返回一个函数,或者两者都具备
    • 函数式编程: 对应用程序复杂性进行抽象的一种方式,使用整齐、干净的函数调用替代了复杂的循环和条件语句(代码可读性高)
    • 比如:将数组中的所有数字相加
// for循环相加
var nums = [1, 34, 3, 15, 4, 18];
var sum = 0;
for(var i = 0; i < nums.length; i++) {
    sum += nums[i];
}
console.log('sum', sum);  //75

var nums2 = [1, 34, 3, 15, 4, 18];
var sum2 = nums2.reduce(function(n1, n2) {
    return n1 + n2;
});
console.log('sum2', sum2);  //75

<h4 id="3-3">3.3 实现递归算法</h4>

  • 想要实现一个函数,它递归地遍历一个数组并返回一个反向的数组字符串
  • 缺点:递归很消耗内存
// 阶乘
function factorial(n) {
    return n == 1 ? n : n * factorial(n - 1);
}
console.log('阶乘', factorial(4));  // 24

// 斐波那契
var fibonacci = function(n) {
    return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
}
console.log('斐波那契', fibonacci(10));  //55

// 使用一个递归函数字面值来反转数组元素,从最大长度开始,每次迭代都将这个值自减
// 当为 0 时,返回字符串
var reverseArrary = function(x, index, str) {
    return index == 0 ? str : reverseArrary(x, --index, (str += " " + x[index]));
}
var arr = ['apple', 'orange', 'peach', 'lime'];
var str = reverseArrary(arr, arr.length, "");
console.log('str', str);  //lime peach orange apple

// 如果要反过来,按照顺序把数组连接为一个字符串
var orderArray = function(x, i, str) {
    return i == x.length - 1 ? str : orderArray(x, ++i, (str += x[i] + " "));
}

var numArr = [1, 2, 3, 4];
var numStr = orderArray(numArr, -1, "");
console.log('numStr', numStr);  //1 2 3 4 

3.4 使用一个定时器和回调防止代码阻塞

  • 在程序的输出中,3个外围的 console.log() 立即被处理了
  • 队列中下一个事件是第一个 noBlock() 函数调用,其中又调用了 factorial() ,记录了其运行时候的活动,最后跟着回调函数的调用
  • 第二次同样地调用了 callBack()
  • 第三次调用 callBack() 的时候,回调函数中的调用针对第一次 callBack() ,并使用了第一次函数调用的最终结果:6
<script type="text/javascript">
function factorial(n) {
    console.log('n', n);
    return n == 1 ? 1 : n * factorial(n - 1);
}
function noBlock(n, callback) {
    setTimeout(function() {
        var val = factorial(n);
        if(callback && typeof callback == 'function') {
            callback(val);
        }
    }, 0);
}
console.log('Top of the morning to you');
noBlock(3, function(n) {
    console.log('first call ends width ' + n);
    noBlock(n, function(m) {
        console.log('final result is ' + m);
    });
});

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

推荐阅读更多精彩内容

  • 待繁花落尽又再次盛开 我亦不知流年何时再来 我在匆忙岁月中躲过红尘霭霭 掌心中的璎珞却已蒙上尘埃 子夜花开,散去寒...
    南有乔木怎思清商阅读 377评论 2 4
  • iOS 10拨打系统电话发现弹出框会延迟2s左右出现,很不爽,研究了一下,发现是openURL在http://bl...
    Joh蜗牛阅读 731评论 0 4
  • 对花如对人, 见花如见身。 生死边上事, 唯以生死了。 云冉冉,水灿灿, 明月芦草舟泛远。
    何俊荣阅读 566评论 0 0
  • 或许在我们心中,都对那些优秀的人心生向往。年少时怀着一份羞涩,不敢走近,远远的观望就已足够;慢慢长大后,各自一方,...
    心里有很多事阅读 355评论 0 0
  • 歌德曾说过,“在世界上发生的诸多灾难中,从未有过任何灾难像庞贝一样,它带给后人的是如此巨大的愉悦。” ...
    洪小兵阅读 941评论 0 2