JavaScript - 面向对象 - 继承


这一节,主要讲解面向对象的继承,回顾上一节讲解到判断对象原型和实例对象的两种方法.废话不多说,直接上代码 !

继承 ==> 重点

- 子对象-->父对象,Object是所有对象的父级
- 一种把其他对象的属性和方法变为己有的方式
- 通过继承可以提高代码的复用性和可维护性
- 举例 : 动物 -- 狗类 -- 金毛狗类

1.对于狗类来説:动物是它的父类型,而金毛狗类是它的子类型
2.对于金毛狗类来説.狗类是它的父类型,动物类是它的超类型.

继承的两种方式

  • 接口继承
  • 实现继承
  • js中的继承:
    javaScript中继承只支持实现继承,实现继承主要依赖原型链来完成

Js中继承的几种实现方式

混入式继承

  • ** 示例代码1 : **
    //1. 创建一个空的对象o
    var o = {};

    //2. 提供一个已经有的对象obj
    var obj = {
        name:"对象的属性",
        age:20,
        sayHello:function () {
            console.log("hello");
        }
    }

    //3. 混入式继承(把原有对象的所有属性和方法都拷贝给新的对象)
    for(var k in obj)
    {
        o[k] = obj[k];
    }

    //4. 打印查看o对象
    console.log(o);

    //5. 如果属性的值是引用类型的,那么子对象和父对象共享一块数据,修改了某个对象对另外一个对象有影响
    console.log(o.sayHello == obj.sayHello);    //true
  • **示例代码2 : **
<script>
    //参数:
    //第一个参数是目标对象
    //第二个,第三个参数是要拷贝属性的对象
    var o = {};
    var obj1 = {name:"name"};
    var obj2 = {age:20};
    var obj3 = {car:{type:"飞船"}};

    Object.assign(o,obj2,obj1,obj3);
    console.log(o);

    obj3.car.type = '汽车';
    console.log(o);
</script>

原型式继承

  • 原型对象中的成员(属性|方法)可以被使用该构造函数创建出来的所有对象共享
  • 利用上面的性质,可以实现原型式的继承
  • **示例代码1 : **
<script>
    //1. 提供一个构造函数
    function Person(name,age) {
        this.name = name;
        this.age = age;
    }

    //2. 设置原型对象的属性
    Person.prototype.className = "逍遥派1班";

    //3. 使用构造函数来创建原型对象
    var p1 = new Person("张三",10);
    var p2 = new Person("李四",20);

    //4. 打印p1和p2对象中的className属性
    console.log(p1.className);
    console.log(p2.className);

    //结论:对象p1和p2继承了构造函数原型对象中的属性className
    //但是这并不是严格意义上的继承
</script>
  • **示例代码2 : **
<script>
    //1. 提供一个构造函数
    function Person(name,age) {
        this.name = name;
        this.age = age;
    }

    //2. 设置原型对象的属性
    Person.prototype = {
        constructor:Person,
        className:"逍遥派1班"
    };

    //3. 使用构造函数来创建原型对象
    var p1 = new Person("张三",10);
    var p2 = new Person("李四",20);

    //4. 打印p1和p2对象中的className属性
    console.log(p1.className);
    console.log(p2.className);

    //结论:对象p1和p2继承了构造函数原型对象中的属性className
    //注意:使用原型替换的方式实现继承的时候,原有原型对象中的属性和方法会丢失
</script>

**示例代码3 : **

<script>
    //1. 提供超类型|父类型
    function SuperClass() {
        this.name = 'SuperClass的名称';
        this.showName = function () {
            console.log(this.name);
        }
    }

    //2. 设置父类型的原型属性和原型方法
    SuperClass.prototype.info = 'SuperClass的信息';
    SuperClass.prototype.showInfo = function () {
        console.log(this.info);
    };

    //3. 提供子类型
    function SubClass() {
    }

    //4. 设置继承(原型对象继承)
    SubClass.prototype = SuperClass.prototype;
    SubClass.prototype.constructor = SubClass;

    var sub = new SubClass();
    console.log(sub.name);          //undefined
    console.log(sub.info);          //SuperClass的信息
    sub.showInfo();                 //SuperClass的信息
    sub.showName();                 //sub.showName is not a function
</script>
  • 存在的问题 :

1.构造器属性指向(默认指向的是父构造函数)
2.无法获得实例属性和方法,只能继承(获得)父构造函数原型对象的属性和方法

  • **扩展内置对象 **
    要给数组扩展一个name的属性和一个sayHello方法
  • 示例代码 :
<script>
    //1. 创建数组对象
    var arr = [1,2,3];
    var arr2 = new Array(1,2,3);
    console.log(arr2);

    //2. 设置Array构造函数的原型对象
    Array.prototype.name = "默认的名称";
    Array.prototype.sayHello = function () {
        console.log("hello");
    };

    console.log(arr.name);  //默认的名称
    console.log(arr2.name); //默认的名称
    arr.sayHello();         //hello
    arr2.sayHello();        //hello


    //1.上面的方式可以达到扩展内置对象的效果,但不推荐这样去做
    //2.遇到那种大项目可能需要多人合作一起开发,而且项目中的代码数量可能非常庞大
    //3.如果大家都通过这种方式来扩展内置对象,那么日后必将难以管理,而且可能会出现方法被覆盖等安全问题
</script>
  • 安全的扩展内置对象

核心过程
1.提供一个构造函数(自定义)
2.设置构造函数的原型对象为内置构造函数创建出来的对象

  • 示例代码 :
    //Array
    function MyArray(){};
    //设置原型对象
    MyArray.prototype = new Array();
    MyArray.prototype.des = "描述信息";
    MyArray.prototype.logDes = function(){
        console.log(this.des);
    }

    //使用自己的构造函数来创建对象
    var myArr01 = new MyArray();
    var myArr02 = new MyArray();
    myArr01.push("123","abc");
    console.log(myArr01);
    console.log(myArr01.des);


    function OtherArray(){};
    OtherArray.prototype = new Array();
    OtherArray.prototype.des = "描述信息";
    OtherArray.prototype.logDes = function(){
        console.log("------------");
    }

    var otherArr01 = new OtherArray();
    var otherArr02 = new OtherArray();

    console.log(otherArr01.des);
    otherArr01.logDes();
  • 图解
**安全扩展内置对象**

原型链继承 ( 什么是原型链 ? )

  • 每个对象都是由构造函数创建出来的,因为每个对象都有构造函数

  • 每个构造函数都有一个与之对应的原型对象

  • 原型对象本身也是对象

  • 因此,原型对象也有自己的构造函数

  • 原型对象的构造函数也有自己的原型对象

  • 原型对象的构造函数的原型对象也是对象,所以它也有自己的构造函数

  • 原型对象的构造函数的原型对象的构造函数也有自己的原型对象。
    以上,形成一个链式的结构,就称为是原型链

  • 原型链的顶端是Object.prototype,Object.prototype本身也是一个对象,因此也有原型对象
    Object.prototype.__proto__ 是null

  • 原型链的搜索规则 :

是向上查找,如果有直接使用,如果没有,继续向上查找.直到找到原型链的顶端
原型链搜索的路径越长,查询属性所花费的时间就越多
原则:就近原型

**

  • 继承方法

1.提供一个父构造函数
2.提供子构造函数
3.设置子构造函数的原型对象为父构造函数的一个实例对象
4.在这个实例对象上面设置属性和方法

  • **示例代码 : **
<script>
    function A(){
        this.age = 55;
        this.showAge = function(){
            console.log(this.age);
        }
    };

    //设置A的属性和方法
    A.prototype.logDes = function(){
        console.log("des");
    }

    function B(){

    };
    //设置原型链继承
    B.prototype = new A();
    B.prototype.des = "des";
    B.prototype.show = function(){
        console.log("show");
    };

    var b1 = new B();
    console.log(b1.age);
    b1.showAge();
    b1.logDes();
    console.log(b1);
</script>
  • 复杂的原型链

1.提供构造函数(4)
2.设置属性和方法(建议:属性设置在实例上,方法设置在原型上)
3.设置继承
4.修正构造器属性

  • 示例代码 :
<script>
    Animal.prototype.run = function(){
        console.log("run");
    }
    function Animal(color){
        this.color = color
    }

    Person.prototype = new Animal();
    Person.prototype.eat = function(){
        console.log("chi");
    }
    Person.prototype.constructor = Person;

    function Person(){
        this.name = "默认的名称"
    }

    Student.prototype = new Person();
    Student.prototype.study = function(){
        console.log("good good study, day day up");
    }
    Student.prototype.constructor = Student;

    function Student(){
        this.id = "20160501"
    }

    Boy.prototype = new Student();
    Boy.prototype.lol = function(){
        console.log("LoL");
    }
    Boy.prototype.constructor = Boy;

    function Boy(){
        this.sex = "男"
    }

    //创建对象
    var boy = new Boy("红色");
    console.log(boy);
</script>
  • 原型链继承的注意点

1.注意必须要在设置子对象的原型属性和原型方法之前来实现继承
2.在子对象的原型对象中可以设置同名的属性或方法,覆盖父对象的原型对象中的属性和方法
3.原型链继承之后,使用字面量的方式来设置原型会导致之前的原型对象丢失

  • 示例代码1
<script>
    //注意点
    //如果代码段2==>代码段1 则运行正常,,如果代码段1==>代码段2,则报错'eat方法不存在'
     function Person() {};

     Person.prototype.run = function () {
        console.log('Person__run');
     };

     function Man() {};


     //代码段1
     Man.prototype.eat = function () {
        console.log('Man__eat');
     };

    //代码段2
    Man.prototype = new Person(); //设置原型链继承

     var m = new Man();
     m.run();                //Person__run
     m.eat();                //Man__eat

    //建议:在设置完原型链继承之后,再设置子对象原型对象上面的属性和方法,否则会丢失(之前的原型对象被切断)
</script>
  • 示例代码2 :
<script>
    // 注意点2 && 注意点3
    // 在子对象中(原型对象中)可以重写父对象中(原型对象中)的方法
    // 子对象在调用的时候原型对象中的方法会覆盖父对象原型对象中的
    // 方法,父类型的实例调用方法不受影响

     function Person() {};
     Person.prototype.run = function () {
        console.log('Person__run');
     };

     function Man() {};

     //代码段2
     Man.prototype = new Person(); //设置原型链继承
     Man.prototype.run = function () {
     console.log('Man__run');
     };

     var m = new Man();
     m.run();                //Man__run
     var p = new Person();
     p.run();                //Person__run

</script>

-示例代码3 :

<script>
    // 在重写原型对象实现继承之后,不能使用字面量的方式来设置原型对象,
    // 否则之前的原型继承关系会被切断
    function Person() {};
    Person.prototype.run = function () {
        console.log('Person__run');
    };

    function Man() {};

    //代码段2
    Man.prototype = new Person(); //设置原型链继承
    Man.prototype = {
        eat:function () {
            console.log('Man__eat');
        }
    }

    var m = new Man();
    m.eat();    //Man__eat
    m.run();    //调用的方法不存在
</script>
  • 原型链继承存在的问题

1.父类型实例属性会转换为子类型原型的原型属性,而如果父类型是实例属性是引用类型则会存在共享问题
2.在创建子类型的实例时,不能向父类型的构造函数中传递参数

  • ** 示例代码 : **
<script>
    //1. 提供父类型的构造函数
    function SuperType() {
        //2. 在构造函数中中设置实例属性,该属性为引用类型
        this.family = ['哥哥','姐姐','爸爸','妈妈'];
    };

    //3. 提供子类型的构造函数
    function SubType() {};

    //4. 设置原型继承
    SubType.prototype = new SuperType();

    //5. 创建父类型的实例对象,并对内部的实例化属性进行修改
    var subDemo1 = new SubType();
    var subDemo2 = new SubType();

    console.log(subDemo1);
    alert(subDemo1.family);    //哥哥,姐姐,爸爸,妈妈
    alert(subDemo2.family);      //哥哥,姐姐,爸爸,妈妈

    subDemo1.family.push('爷爷','奶奶');
    alert(subDemo1.family);    //哥哥,姐姐,爸爸,妈妈,爷爷,奶奶
    alert(subDemo2.family);    //哥哥,姐姐,爸爸,妈妈,爷爷,奶奶

    //6. 如果父类型的实例属性中有引用类型,那么在子类型创建的实例对象中存在共享问题
</script>
  • Object.Create
  • 作用:创建对象,并且设置该对象的原型对象
  • 兼容性问题:ES5
  • 基本用法
  • **示例代码1 : **
<script>
    //JavaScript语言精粹
    function create(o) {
        var F = function () {};
        F.prototype = o;
        return new F();
    }

    var obj1 = create({name:"默认的名字"});
    console.log(obj1);

    //把参数(对象)作为新对象的原型对象
    var obj = Object.create({name:"默认的名字"});
    console.log(obj);
    //需要考虑到浏览器兼容的问题
</script>
  • 实例代码2 : 若不兼容则动态添加create方法
<script>
    var tmp = {age:20};
    if (Object.create){
        //如果有值那么就直接调用
        var o = Object.create(tmp)
    }
    else{
        Object.create = function () {
            var F = function () {};
            F.prototype = tmp;
            var o = new F();
        }
    }
</script>
  • **示例代码3 : 使用函数来封装 **
<script>
    function create(o) {
        if (Object.create)
        {
            //如果有值那么就直接调用
            return Object.create(o)
        }else
        {
            var F = function () {};
            F.prototype = o;
            return F();
        }
    }
    var a = create({name:"默认的名字",age:20});
    console.log(a);
</script>
  • call && apply函数 ==> 重点

**1.这两个方法都是原型对象上面的方法 -- 借用其他对象的方法
2.call和apply两个函数的作用是一样的,都可以用来借用方法
参数:
第一个参数是调用该方法的对象(函数内部的this绑定的对象)
后面的参数:
call:参数列表
apply:数组
3.调用方法
对象1.方法.call(调用方法的真正的对象,参数1,参数2,参数3);

对象1.方法.apply(调用方法的真正的对象,[参数1,参数2,参数3..]);**

  • **示例代码 : **
<script>
    //console.log(Function.prototype);
    var demo01 = {
        name:"小偷",
        showName:function(param1,param2){
            console.log(this.name,param1,param2);
        }
    }
    var demo02 = {
        name:"我是老实人"
    }

    demo01.showName("小贼","毛贼");
    demo01.showName.call(demo02,"江洋大盗","采花大盗");
    demo01.showName.apply(demo02,["山贼","土匪"]);
</script>
  • 关于this

1.javaScript中的this总是指向一个对象。
2.调用方式 :
2.1作为对象的方法来调用 this--->当前的对象
2.2作为普通的函数调用 this--->window
2.3作为构造函数和new使用 this--->构造函数内部新创建的对象
2.4被call或者是apply调用(函数上下文调用) this--->第一个参数

  • ** 示例代码1 : 当函数作为对象的方法调用时,this指向该对象**
<script>
    var obj = {
        name:"张三",
        demoFunc:function () {
            console.log(this == obj);       //true
            console.log(this.name);         //张三
        }
    }
    obj.demoFunc();
</script>
  • 示例代码2 : 当函数作为普通函数调用是,this总是指向全局对象
<script>
    window.name = "window测试的name";
    var funcName = function () {
        console.log(this.name);     //window测试的name
    }
    funcName();
</script>
  • 示例代码3: 使用new 构造函数创建对象调用,this总是指向内部默认创建并返回的对象
<script>
    function Person() {
        this.name = "默认的姓名"
    }

    var p1 = new Person();
    console.log(p1.name);   //默认的姓名
</script>
  • ** 实例代码4: Function.prototype.call或Function.prototype.apply调用**
<script>
    var obj = {
        name:"张三",
        getName:function () {
            console.log(this.name);
        }
    }
    obj.getName();      //张三
    var obj2 = {name:"李四"};
    obj.getName.call(obj2); //打印李四
</script>

借用构造函数继承

  • 借用构造函数实现继承:可以获得父构造函数中的实例属性,解决了传参的问题
  • 示例代码 :
<script>
    function Person(name,age){
        this.name = name;
        this.age = age;
    };
    function Boy(bookName,name,age){
        this.bookName = bookName;
        //Person.call(this,"八戒",600);  //借用构造函数
        Person.call(this,name,age);
    }

    //创建对象
    var boy = new Boy("水煮三国","悟空",600);
    var boy02 = new Boy("大话西游","云风",40);
    console.log(boy);
    console.log(boy02);
</script>

组合(原型链 + 借用)继承

  • 借用构造函数实现继承:可以获得父构造函数中的实例属性
    Person.call(this,name,age)

  • 获得原型属性和方法 ( Boy.prototype = Person.prototype)

  • 组合继承:原型 + 借用构造函数

  • **示例代码 : **

<script>
    function Person(name,age){
        this.name = name;
        this.age = age;
    };
    Person.prototype.des = "描述信息";
    Person.prototype.logDes = function(){
        console.log(this.des);
    };

    function Boy(bookName,name,age){
        this.bookName = bookName;
        //Person.call(this,"八戒",600);  //借用构造函数
        Person.call(this,name,age);
    }

    //设置原型继承
    //Boy.prototype = new Person();
    Boy.prototype = Person.prototype;

    //创建对象
    var boy = new Boy("水煮三国","悟空",600);
    var boy02 = new Boy("大话西游","云风",40);
    console.log(boy);
    console.log(boy02);
    boy.logDes();

    var p1 = new Person();
    p1.logDes();

    Boy.prototype.des = "描述信息-bOY";
    boy.logDes();
    p1.logDes();
</script>

深拷贝和浅拷贝

  • **示例代码 : 浅拷贝 **
<script>
    var obj = {
        name:"小花脸",
        car:{
            type:"客车"
        }
    };
    var o = {};
    for (var k in obj)
    {
        o[k] = obj[k];
    }

    console.log(o);
    o.car.type = "银河战舰";
    console.log(obj);
</script>
  • 深拷贝

**1.提供一个函数,两个参数(原对象,要拷贝属性的对象)
2.在函数中先检查第一个参数是否有值,如果没有值那么就初始化一个空的对象
3.for..in循环来变量参数2,

3.1检查当前的属性值是什么类型
3.2如果是值类型,那么就直接拷贝赋值
3.3如果是引用类型,那么就再调用一次这个方法,去内部拷贝这个对象的所有属性**

  • 示例代码 : 深拷贝封装
<script  >
    var obj = {
        name:"小花脸",
        car:{
            type:"客车",
        },
        friends:["1","2","3"]
    };

    //兼容性处理
    if(typeof Array.isArray != "function") {
        Array.isArray = function(obj){
            return Object.prototype.toString.call(obj) == "[object Array]";
        }
    }

    var o = {};
    //deepCopy(o,obj);
    function deepCopy(obj1,obj2) {
        obj1 = obj1 || {};
        for (var i in obj2)
        {
            if (obj2.hasOwnProperty(i))
            {
                if( typeof obj2[i] == "object")
                {
                    //判断是数组还是对象
                    obj1[i] = Array.isArray(obj2[i])?[]:{};
                    //引用类型
                    deepCopy(obj1[i],obj2[i]);   //函数调用
                }else
                {
                    //值类型
                    obj1[i] = obj2[i];
                }
            }
        }
    }

    deepCopy(o,obj);
    console.log(o);

    //共享问题
    //o.car.type = "小货车";
    console.log(obj);
</script>

通过深拷贝实现继承

  • 完整的继承方案

1.拥有父构造函数的实例属性
2.拥有父构造函数的原型属性
3.是相互独立的,彼此不受影响

  • ** 示例代码 : **
<script>
    if(typeof Array.isArray != "function") {
        Array.isArray = function(obj){
            return Object.prototype.toString.call(obj) == "[object Array]";
        }
    }
    function deepCopy(obj1,obj2) {
        obj1 = obj1 || {};
        for (var i in obj2)
        {
            if (obj2.hasOwnProperty(i))
            {
                if( typeof obj2[i] == "object")
                {
                    //判断是数组还是对象
                    obj1[i] = Array.isArray(obj2[i])?[]:{};
                    //引用类型
                    deepCopy(obj1[i],obj2[i]);   //函数调用
                }else
                {
                    //值类型
                    obj1[i] = obj2[i];
                }
            }
        }
    }

    function Person(name,age){
        this.name = name;
        this.age = age;
    };
    Person.prototype.des = "描述信息";
    Person.prototype.car = {
        type:"汽车"
    }
    Person.prototype.logDes = function(){
        console.log(this.des);
    };

    function Boy(bookName,name,age){
        this.bookName = bookName;
        //Person.call(this,"悟空",600);  //借用构造函数
        Person.call(this,name,age);
    }

    //设置原型继承
    //Boy.prototype = Person.prototype;
    deepCopy(Boy.prototype,Person.prototype);  //把父构造函数原型对象上面的属性和方法全部拷贝一份给Boy

    //创建对象
    var boy01 = new Boy("水煮三国","悟空",600);
    var boy02 = new Boy("大话西游","云风",40);

    Boy.prototype.car.type = "火车";
    console.log(Boy.prototype);

    var p1 = new Person();
    console.log(p1.car.type);
</script>

基本包装类型

  • String Number Boolean
  • **示例代码 : **
<script>
    //1. 创建字符串对象
    var str1 = new String("demo01");  //object
    var str2 = "demo01";              //string
    var str3 = String("demo01");     //string(正确) | object

    console.log(typeof str1);
    console.log(typeof str2);
    console.log(typeof str3);

    //2. 创建数字对象
    var num1 = new Number(10);      //object
    var num2 = 10;                  //number
    var num3 = Number(20);          //number

    //3. 布尔类型的对象
    var bool01 = new Boolean(true); //object
    var bool02 = true;              //boolean
    var bool03 = Boolean(true);
    console.log(typeof bool01);

    //4. 特殊的创建方式
    var str4 = new Object("demo01");    //object | string
    var num4 = new Object(10);
    var bool04 = new Object(true);

    console.log(typeof str4);
</script>
  • 基本包装类型注意点:
<script>
    var str1 = "demo01";                      //string
    var str2 = new String("demo01");          //object
    var str3 = String("demo01");

    console.log(str1 == str2);  //true  转换
    console.log(str1 === str2); //false

    console.log(str1.length);   //6 获得字符串的长度
    //基本数据类型的值怎么能够访问属性呢?
    //属性和方法只有对象才有

    //为什么?
    //字符串、数值以及布尔值在访问属性或者调用方法的时候
    //1. 内部会隐式的创建一个对象,利用该对象来访问属性或者是调用方法
    //2. 得到结果之后,把结果赋值给基本数据类型的值
    //3. 销毁这个创建的对象

    str1.des = "描述信息";
    console.log(str1.des);            //undefined

    str2.des = "des";
    console.log(str2.des);           //des(正确的) | undefined
</script>
  • 总结

1.变量的方式调用成功
2.表达式的方式调用成功
3.数值的方式调用失败

  • **示例代码 : **
<script>
    Number.prototype.sum = function(param){
        return this + param;
    }

    var num1= new Number("10");
    var num2 = 30;

    console.log(num1.sum(2));
    console.log(num1.sum(33));
    console.log(num2.sum(44));  //可以调用吗? 74

    console.log((10).sum(11));      //可以调用吗?  ()表达式  21
    console.log(10.sum(22));        //不可以调用
</script>

附思维导图一张,希望能帮到各位 ! 如果图片不清晰的话 请下载到本地查看

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

推荐阅读更多精彩内容