面向对象

1、面向对象(OOP | OO)

  • 对象:黑盒子{ Math(abs random ceil floor)、Date、Object(对象,没有功能,是所有js对象的父级)}
    盖楼房:调用具有某些功能的人来实现某些功能。
    对象是一个整体,对外提供一些功能和属性。使用对象时只关注对象的提供的功能,不关注对象的内部实现。
  • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态性的特性,可 以设计出低耦合的系统,使系统 更加灵活、更加易于维护
  • 缺点:性能比面向过程低

2、面向过程

  • 过程:过程就是面向函数式编程(function)。
  • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源; 比如单片机、嵌入式开发、 Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
  • 缺点:没有面向对象易维护、易复用、易扩展

3、面向对象的特点:(封装,继承,抽象(多态))

  • 抽象:就是建模,抓住核心问题。
  • 封装:
    • 使用者:不必考虑内部实现,只考虑内部提供的功能。
    • 创建者:考虑好对外提供的功能,实现内部的代码。
  • 继承:
    • 从已有的对象上继承出新的对象,新对象具有了老对象的一些功能和特性。
    • 多重继承:
      沙发 汽车(带轮子的沙发)
      盒子 汽车(集装箱货车)
    • 多态:龙生九子
    • 属性的继承使用 call(this)
      eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
function A(){ //构造函数
    this.name='lisisi';
    this.age = 18;
}
A.prototype.sss = 'sss';
A.prototype.func = function(){
    console.log(this.name);
}
A.prototype.func1 = function(){
    console.log(this.age);
}
function B(){
    A.call(this);  //修改A的this,相当于A里面的属性是给B添加的。
}
// B.prototype = A.prototype;  //引用类型
for(let m in A.prototype){
    B.prototype[m] = A.prototype[m];
}
let a = new A();
let b = new B();
// B.prototype=A.prototype;
console.log(B.prototype);
console.log(A.prototype);
B.prototype.func1 = function(){
    console.log(1);
}
b.func1(); //1
a.func1(); //18
</script>
</body>
</html>

4、对象的组成

  • 属性:属于对象的变量
  • 方法:属于对象的函数
    eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
//工厂方法创建对象
function MakeStu(name,weight){  //构造函数 参数就是原料
    //加工
    var obj = new Object();
    //属性
    obj.name = name;
    obj.weight = weight;
    //方法
    obj.getName = function(){
        console.log('我的名字叫:'+this.name);
    }
    obj.getWeight = function(){
        console.log('我的体重是:'+this.weight);
    }
    //出厂
    return obj;
}
var obj1 = MakeStu('limao','100kg');
obj1.getName();
obj1.getWeight();
var obj2 = MakeStu('lihaoshung','90kg');
obj2.getName();
obj2.getWeight();
</script>
</body>
</html>

5、this 函数的调用者就是this(每一个函数都具有自己的调用对象)

  • 事件:触发事件的对象
div.onclick = function(){
    alert(this);
};

6、new : 一个函数( 创建对象实例)。

  • new的深入操作:
    • 创建一个空对象,作为将要返回的对象实例。
    • 将这个空对象的原型,指向构造函数的prototype属性。
    • 将这个空对象赋值给函数内部的this关键字。
    • 开始执行构造函数内部的代码。
    • 将对象实例返回。
      eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
    function show(){
        //this=new Object();
        alert(this);
        //return this;
    }
    show(); //window
    new show(); //object
</script>
</body>
</html>
  • 防止漏掉new造成错误:
    • 在构造函数内部使用严格模式。
    • 使用instanceof在内部判断。判断是否为当前对象的实例。
    • 使用new.target 在内部判断,new.target指向自己的构造函数。
      eg:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    //严格模式
    function A(name){
        'use strict';
        this.name = name;
    }
    let a = new A('ahuang');
    console.log(a.name); //ahuang


    //递归
    function B(name){
        //this 指向新创建的实例
        if (!(this instanceof B) ) {
            return new B(name);
        }
        this.name = name;
    }
    let b1 = new B('zhangsan');
    console.log(b1.name); //zhangsan
    let b2 = B('lisi');
    console.log(b2.name); //lisi


    function C(name){
        if (!(new.target == C)) {
            throw new Error('这个对象必须使用new来创建对象');
        }
        this.name = name;
    }
    let c1 = new C('ergouzi'); //ergouzi
    console.log(c1.name);
    let c2 = C('wangwu'); //这个对象必须使用new来创建对象
</script>
</html>

7、构造函数里面的return语句:

  • 任何一个函数都可以使用new。返回值都是一个对象。如果这个函数是一个构造函数的话,返回的是这个函数的实例。如果函数是一个普通函数,那么返回的是一个空的对象。
  • 如果return的是普通数据类型。那么相当于没写。
  • 如果返回的是this,那么返回的与本身返回的是一样的。
  • 如果构造函数中具有return语句,并且return返回的是一个对象,那么构造函数产生的对象就是返回的这个对象。而不是构造函数的本身实例。
    eg:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    // 简单数据类型
    function A(name){
        this.name = name;
        return 123;
    }
    let a = new A('12');
    console.log(a); //12


    //返回this
    function B(name){
        this.name = name;
        return this;
    }
    let b = new B('34');
    console.log(b); //34


    //返回其他对象
    function C(name){
        this.name = name;
        return {
            "a": a
        };
    }
    let c = new C('56');
    console.log(c); //"a":a
</script>
</html>

8、Object对象,是所有JS对象的基础。Object 的原型指向null。一切对象的基础是null,null也叫空。

eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
    console.log(Object.prototype.__proto__); //null
</script>
</body>
</html>

9、Object.create()有的时候我们拿不到对象的构造函数。可以根据这个对象的某一个实例去创建一个对象。

eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    function A(name){
        this.name = name;
    }
    let a = new A('lisi');
    let b = Object.create(a);
    console.log(b); //zhangsan
    b.name = 'zhangsan';
    console.log(a.name) //lisi
</script>
</html>

10、对于对象来说,每一个属性都有四个描述。

  • value 值
  • enumerable 枚举、遍历(for in)
  • configurable 修改
  • writable 删除
    后面三个默认值都是true
    eg:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    let obj1 = new Object();
    obj1.p1 = 'zhangsan';
    obj1.p2 = 18;
    let obj2 = Object.create(obj1,{
        p1:{
            value: 'zhangsan', //值
            enumerable: false, //遍历 有问题
            configurable: true, //修改值
            writable: true //删除属性
        },
        p2:{
            value: 18,
            enumerable: false,
            configurable: true,
            writable: true
        }
    });
    for(let i in obj2){
        console.log(i,obj2[i]);
    }
    obj1.p1 = 'lisi';
    console.log(obj1.p1); //lisi
    delete obj1.p2;
    console.log(obj1.p2); //undefined
</script>
</html>

enumerable:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    let obj = {
        a: 'a',
        b: 'b',
        c: 'c',
    };
    for(let i in obj){
        console.log(i,obj[i]); //aa bb cc
    }

    console.log('-------------');
    Object.defineProperty(obj,'c',{
        value: 1,
        enumerable: false, //遍历
    })
    for(let i in obj){
        console.log(i,obj[i]); //aa bb
    }
</script>
</html>

11、JavaScript的面向对象是基于constructor(构造函数)与prototype(原型链)的。

  • 构造函数:constructor

    • 构造函数就是一个函数。和普通函数有一些区别。
    • 函数的内部使用this的关键字。
    • 首字母是大写的。
    • 使用的时候要用new操作符创建实例对象。
  • 原型(prototype):一个函数可以看成一个类,原型是所有类都有的一个属性,原型的作用就是给这个类的每一个对象都添加一个统一的方法。(统一的给多个对象添加属性或者方法

    • 产生原理:
      • JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法,可以定义在构造函数内部。
      • 通过构造函数为实例对象定义属性,虽然很方便,但是有一个缺点。同一个构造函数的多个实例之间,无法共享属性,从而造成对系统资源的浪费。
      • JavaScript 继承机制的设计思想就是,原型对象的所有属性和方法,都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象就能共享,不仅节省了内存,还体现了实例对象之间的联系。
      • JavaScript 规定,每个函数都有一个prototype属性,指向一个对象。这个对象就是函数的原型。
    • 类: 模板(人类)在JS中一般称为对象
    • 对象:创建出来的具体的实例(张三)在JS中一般称为对象实例
      eg1:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    let arr1 = new Array(1,2,3,4,5,6);
    let arr2 =new Array(7,8,9);
    //原型 给每个对象添加相同的属性
    Array.prototype.sum = function(){
        let sum = 0;
        for (var i = 0; i < this.length; i++) {
            sum += this[i];
        }
        return sum;
    };
    console.log(arr1.sum()); //21
    console.log(arr2.sum()); //24
</script>
</html>

eg2:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
function MakeStu(name,weight){
    // var this = new Object();
    //属性
    this.name = name;
    this.weight = weight;
    //return this;
}
//方法
MakeStu.prototype.getName = function(){
    console.log('我的名字叫:'+this.name);
}
MakeStu.prototype.getWeight = function(){
    console.log('我的体重是:'+this.weight);
}
var obj1 = new MakeStu('limao','100kg');
obj1.getName();
obj1.getWeight();
var obj2 =new  MakeStu('lihaoshung','90kg');
obj2.getName();
obj2.getWeight();
</script>
</body>
</html>
  • 原型也是一个对象(原型对象),里面是所有加在对象原型上的方法以及属性。
    eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
    Object.prototype.name = function(){
        console.log('a');
    };
    let obj = new Object(); //a
    let obj2 = new Object(); //a
    obj.name();
    obj2.name();
    //给对象再次添加相同的属性,旧的属性会被新的属性覆盖
    obj2.name = function(){
        console.log('b')
    };
    obj.name(); //a
    obj2.name(); //b
</script>
</body>
</html>
  • 原型链:JavaScript 规定,所有对象都有自己的原型对象(prototype)。一方面,任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”(prototype chain):对象到原型,再到原型的原型……如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。也就是说,所有对象都继承了Object.prototype的属性。这就是所有对象都有valueOf和toString方法的原因,因为这是从Object.prototype继承的。那么,Object.prototype对象有没有它的原型呢?回答是Object.prototype的原型是null。null没有任何属性和方法,也没有自己的原型。因此,原型链的尽头就是null。
    (构造函数创建实例对象,构造函数具有原型,实例对象也具有原型。实例对象的原型指向构造函数的原型。)
    图解

    image.png

    • constructor:构造器。默认指向prototype对象所在的构造函数。
    • proto:每一个实例对象都具有的私有属性。指向自己的原型。
      eg:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    function A(){
        this.a = '1';
    }
    let b = new A();
    console.log(b.__proto__); //object
    console.log(A);
</script>
</html>

12、 getPrototypeOf 获取obj对象实例的原型

格式:Object.getPrototypeOf(obj)
eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    function A(name){
        this.name = name;
    }
    let a = new A('lisi');
    console.log(Object.getPrototypeOf(a)); //object 获取实例对象的原型
    console.log(a.__proto__); //object

    Object.getPrototypeOf({}) === Object.prototype; //true
    // {}:new Object与Object的原型一致   构造函数的原型与对象的原型一致
    Object.getPrototypeOf(Object.prototype) === null;
    // Object对象的原型的原型指向null,null是原型链的顶点
/*
let o = new Object();
o.__proto__
Object.peototype
Object.peototype.peototype
null
*/

    function f(){}
    Object.getPrototypeOf(f) === Function.prototype; //true
    // 构造函数的原型与内置对象Function的原型一致   f === new Function()
</script>
</html>

13、isPrototypeOf 判断该对象是否为参数对象的原型

格式:Object.prototype.isPrototypeOf()
eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    let a = new Array();
    console.log(Array.prototype.isPrototypeOf(a)); //true Array.prototype === a.__proto__
</script>
</html>

14、设置一个对象的prototype对象,返回参数对象本身

eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    let a = new Array();
    console.log(Object.getPrototypeOf(a)); //Array
    Object.setPrototypeOf(a,Number.prototype);
    console.log(Object.getPrototypeOf(a)); //Number
</script>
</html>

15、getOwnPropertyNames 成员是参数对象本身的所有属性的键名,不包含继承的属性键名。hasOwnProperty 用于判断某个属性定义在对象自身,还是定义在原型链上。

格式:
Object.getOwnPropertyNames()
Object.prototype.hasOwnProperty()
eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    function A(name){
        this.name = name;
        function say(){
            console.log('s');
        }
    }
    A.prototype.m = function(){
        console.log('m');
    };
    function B(){
        A.call(this);
        this.age = 18;
        this.sex = 'man';
    }
    for(let i in A.prototype){
        B.prototype[i] = A.prototype[i];
    }
    let b = new B();
    b.m(); //m b继承a的属性
    // b.name();   is not a function b本身的属性
    //console.log(Object.getOwnPropertyNames(b)); name say age sex
    console.log(B.prototype.hasOwnProperty('name')); //false
</script>
</html>

16、私有属性

eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    function A(name){
        let b = name;
        this.getName = function(){
            console.log(b); //私有属性
        };
    }
    let a = new A('lili');
    // console(a.name) is not a function
    a.getName();
</script>
</html>

17、命名空间

eg:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>
<body>

</body>
<script>
    //大型项目组 防止污染
    var Li = {
        this.F = function(){

        }
        this.S = function(){

        }
    }
    Li.F();
</script>
</html>

18、json:(字符串)数据传输格式

json 对象:json字符串解析出来的对象,或者就是个对象。但是这个对象有限制。键必须是双引号包起来。值必须是简单类型或者数组。
eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
//json 创建对象的格式
let json = {
    "name":"zhangsan",
    "age":19,
    "getName": function(){
        console.log(this.name);
    }
};
//单体对象(适用于只有一个对象的场景)
//对象转化为字符串
console.log(JSON.stringify(json));
</script>
</body>
</html>

19、闭包:

函数的作用域是定义的地方,而不是函数调用的地方。
eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
function t(){
    var a = 10;
  //往外寻找变量,若在函数内部找不到,就去外部寻找(最外层是window),若外部没有找到会产生not defined
    return function(){
        console.log(++a);
    }
}
var a = 1000;
var tmp = t();
tmp(); //11
/*
function t(){
    var a = 10;
    //return = function(){
        console.log(++a);
    }; ;
}
var a = 1000;
var tmp = function(){
        console.log(++a);
    };
tmp(); //1001
*/
</script>
</body>
</html>

20、js的数据类型分为简单类型与复杂类型(引用类型)

  • 这两种数据类型保存数据的形式是不同的。
  • 简单类型:
    数字
    字符串
    布尔值
    undefined
    null
  • 引用类型:
    数组
    对象
  • 图解:


    image.png

eg:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
    let arr = [1,2,3];
    let arr1 = arr;
    arr1.push(8);
    console.log(arr); //1,2,3,8
    console.log(arr1); //1,2,3,8
</script>
</body>
</html>

21、instanceof 判断某一个实例对象是否是某一个对象的实例。

  • 格式:obj instanceof Object
  • 任何实例都是Object的实例
    eg:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
//数组的实例
let a = new Array();
console.log(a instanceof Number); //false
function Say(name){
    this.name = name;
}
let s = new Say();
console.log(s instanceof Say); //true
</script>
</body>
</html>

22、案例

  • 选项卡
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
    <style>
        button{
            width: 80px;
            height: 40px;
            margin: 50px;
        }
        div div{
            width: 200px;
            height: 200px;
            border: 1px solid #ccc;
            display: none;
        }
        .active{
            background-color: yellow;
        }
    </style>
</head>
<body>
    <div id="tab">
        <button class="active">vf</button>
        <button>vdf</button>
        <button>vdsv</button>
        <div style="display: block;">ddfa</div>
        <div>fvd</div>
        <div>fva</div>
    </div>
</body>
<script>
    function Tab(id){
        //this = new Tab('tab');
        // _this = this;
        let obj = this;//保存现场的this   this进入一个新的函数会改变,把this赋值给一个不会改变的量
        //属性 初始化
        this.con = document.getElementById('tab');
        this.btn = this.con.getElementsByTagName('button');
        this.div = this.con.getElementsByTagName('div');
        for (var i = 0; i < this.btn.length; i++) {
            this.btn[i].index = i;
            this.btn[i].onclick = function(){
                //事件内部this发生变化,this变成按钮 this = this.btn[i]
                obj.fclick(this);
            };
        }
    }
    //方法
    //原型:同时给多个对象添加属性
    Tab.prototype.fclick = function(btn){
        //this 函数的调用者 Tab
        for (var j = 0; j < this.btn.length; j++) {
            this.btn[j].className = '';
            this.div[j].style.display = 'none';
        }
        //用到按钮的this btn = this = this.btn[i]
        btn.className = 'active';
        this.div[btn.index].style.display = 'block';
    };
    new Tab('tab');
    // new Tab('abc'); 若使用_this = this(全局变量),再次构造函数会造成函数覆盖,可在构造函数中var/let 变量 = this解决该问题
</script>
</html>
  • 数组赋值
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
<script>
    let a = [1,2,3];
    let b = [];
    for(var j in a){
        b.push(j);
    }
    console.log(a); //123
    console.log(b); //123
    b.push(8);
    console.log(a); //123
    console.log(b); //1238
    let arr = [1,2,3];
    let arr1 = [...arr];
    arr1.push(8);
    console.log(arr); //123
    console.log(arr1); //1238
</script>
</body>
</html>
  • 有范围的拖拽封装
function Drag(id){
    this.d = document.getElementById(id);
    //初始化
    this.x = 0;
    this.y = 0;
    let obj = this;
    this.d.onmousedown= function(ev){
        var ev = ev || event;
        obj.mousedown(ev)
    };
}
Drag.prototype.mousedown = function(ev){
    //计算鼠标相对div的距离
    this.x = ev.clientX - this.d.offsetLeft ;
    this.y = ev.clientY - this.d.offsetTop;
    let obj = this;
    document.onmousemove = function(ev){
        var ev = ev || event;
        obj.mousemove(ev)
    }
    document.onmouseup = this.mouseup;
}
Drag.prototype.mousemove = function(ev){
    this.d.style.left = ev.clientX - this.x + 'px';
    this.d.style.top = ev.clientY - this.y+'px';
};
Drag.prototype.mouseup = function(){
    document.onmousemove = null;
    document.onmouseup = null;
}
  • 有范围的拖拽
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        div{
            width:200px;
            height:200px;
            background: red;
            position: absolute;
        }
    </style>
</head>
<body>
    <div id="move"></div>
</body>
<script src="Drag.js"></script>
<script>
function LimitDrag(id){
    Drag.call(this,id); //this LimitDrag()
}
for(let a in Drag.prototype){
    //[a]:键名(mousedown mousemove mouseup)
    LimitDrag.prototype[a] = Drag.prototype[a];
}
//重写
LimitDrag.prototype.mousemove = function(ev){
    //计算div相对浏览器可视窗口的距离
    let l = ev.clientX - this.x;
    let t = ev.clientY - this.y;
    //判断拖拽边界
    if(l<0){
        l=0
    }else if(l>window.innerWidth - this.d.offsetWidth){
        l = window.innerWidth - this.d.offsetWidth;
    }
    if(t<0){
        t=0
    }else if(t>window.innerHeight-this.d.offsetHeight){
        t =window.innerHeight-this.d.offsetHeight;
    }
    this.d.style.left = l + 'px';
    this.d.style.top = t+'px';
};
new LimitDrag('move');
</script>
</html>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容