原型对象及使用原型对象注意事项

  • 原型对象概念

  • 在构造函数创建出来的时候,系统会默认帮构造函数创建并关联的一个新对象
    自定义构造函数的原型对象默认是一个空对象。

  • 原型对象的作用

  • 构造函数中的原型对象中的属性和方法可以被使用该构造函数创建出来的对象使用。
    即以自定义构造函数方式创建出来的所有对象,自动拥有和共享该构造函数的原型对象中的所有属性和方法。

  • 如何访问构造函数的原型对象

  • ① 构造函数.protoType

  • ② 对象.proto(不推荐)

  • 设置原型对象的属性和方法

  • ① 利用对象的动态特性来为构造函数的原型对象添加属性和方法

  • ② 替换原型对象

  • 我们把"构造函数的原型对象"简化为"构造函数的原型"。

  • 代码示例:

<script>

    //01 提供构造函数
    function Student(number,name,age) {

        //02 设置对象的属性
        this.number = number;
        this.name = name;
        this.age = age;

        //03 设置对象的方法
        this.read = function () {
            console.log("阅读");
        }
    }

    //02 使用构造函数来创建对象
    var stu1 = new Student("20170201","严雯",18);
    var stu2 = new Student("20170202","严二雯",16);

    //03 设置构造函数的原型
    //001 为构造函数的原型对象添加属性
    Student.prototype.className = "神仙特技1班";

    //002 为构造函数的原型对象添加方法
    Student.prototype.description = function () {
        console.log("我的名字是" + this.name + "学号是" + this.number + "班级是" + this.className);
    };

    //04 尝试访问
    console.log(stu1.className);
    console.log(stu2.className);
    stu1.description();
    stu2.description();

    //05 原型属性和原型方法|实例属性和实例方法
    //在构造函数内部设置的属性 => 实例属性
    //在构造函数内部设置的方法 => 实例方法
    //在构造函数的原型对象上设置的属性 => 原型属性
    //在构造函数的原型对象上设置的方法 => 原型方法

    //06 思考:如果实例属性(方法)和原型属性(方法)存在同名,那么对象在使用属性(方法)的时候,访问的是
    //实例属性(方法)还是原型属性(方法)?
    //说明:使用构造函数创建的对象在访问属性或调用方法的时候:
    // ① 首先在内部查找有没有对应的实例属性(方法)
    // ② 如果有,那么就直接使用,如果没有找到,那么就继续去构造函数的原型中查找
    // ③ 原型对象中如果存在该属性或方法,那么就直接使用,如果不存在指定的属性则返回undefined,如果不存在指定的方法则报错

    //07 注意点
    //[01] 通常在创建对象之前设置构造函数的原型对象(提供共享的属性|方法)
    //[02] 访问原型对象的正确方法是 构造函数.protoType 而不是 对象.protoType

</script>

––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––

  • 原型对象的使用注意:

  • 实例和实例化

    • 实例化:通过构造函数创建具体对象的过程。

    • 实例:通过构造函数实例化出来的对象,我们称之为该构造函数的一个实例。

** 注意:在说实例的时候,一定要指定是某个具体构造函数的实例**

代码示例:

<script>

    //01 提供一个构造函数
    function Person() {

    }

    //02 根据该构造函数创建对象 == 使用Person构造函数实例化对象
    var p1 = new Person();

    //p1 是构造函数Person的一个实例

</script>
  • 原型的使用方法

    利用对象的动态特性给原型添加属性|方法

    • 如果要添加的方法过多,则有大量重复代码

    直接替换原型对象

    • 01 替换前后创建的对象所指向的原型对象不一致
    • 02 替换原型对象会切断和之前的原型对象之间的关系
  • 使用动态特性设置原型的属性和方法代码示例:

<script>

    //01 提供一个空的构造函数
    function Person() {
    }

    //02 设置原型对象的属性和方法
    Person.prototype.name = "臧飒";
    Person.prototype.age = 18;
    //.......
    Person.prototype.sayHello = function () {
        console.log("hello");
    }

    //如果要添加大量的属性和方法,则会出现很多重复的代码

</script>
  • 直接替换原型对象代码示例:

<script>
    //01 提供一个空的构造函数
    function Person() {
    }

    //在替换原型对象之前创建对象,其指向的原型对象为默认创建的空对象
    var p1 = new Person();

    //02 直接替换原型对象(以字面量的方式来创建原型对象)
    Person.prototype = {
        name:"默认的姓名",
        age:"默认的年龄",
        sayName:function () {
            console.log("我的名字是" + this.name);
        }
    };

    //在替换原型对象之后创建的对象,其指向的原型对象为替换过后的原型对象
    var p2 = new Person();

    //03 问题:替换原型对象前后所创建的对象,其指向的原型对象不是同一个

    //04 打印验证
    console.log(p1.name);   //undefined
    console.log(p2.name);   //默认的姓名

    //p1.sayName();           //调用的方法不存在
    p2.sayName();             //我的名字是默认的姓名
</script>

总结:

01 使用字面量的方式创建原型对象(替换原型对象)会切断构造函数和之前的原型对象之间的联系
① 当替换构造函数的原型对象的时候,已经使用构造函数创建出来的对象指向的原型对象不会发生改变
02 在替换原型对象之前创建的对象和替换之后创建的对象所指向的原型对象不同
② 如果是替换了构造函数的原型对象,那么构造函数的新的原型对象和旧的原型对象之间没有任何关系
  • 原型对象的使用注意:

 ① 访问属性:构造函数创建出来的对象在访问属性的时候,会先在实例内查找,如果没有找到则进一步到对应的原型对象中查找
    ② 设置属性:
       在使用点语法进行赋值的时候,无法操作到对应的原型对象
                      如果该属性在对象中已经存在,则修改该属性的值
                      如果该属性在对象中尚未存在,则新增该属性
    ③ 设置原型对象的属性:
        [01] 设置原型对象的属性,只能通过构造函数.Prototype的方式|替换原型对象的方式设置
        [02] 如果原型对象的属性是值类型,那么只能通过Person.prototype.属性的方式修改其值
             如果原型对象的属性是引用类型,那么可以通过对象名.引用对象.属性名的方式设置|修改
                (1) 使用构造函数创建出来的多个对象的原型对象中的该属性指向的是同一块数据
                (2) 某个对象对该原型对象属性进行了修改会影响到其他的对象
  • 01 属性的访问逻辑

<script>

    //01 提供一个简单的构造函数
    function Person() {
        this.name = "张三";
        this.age = 20
    }

    //02 设置构造函数的原型对象
    Person.prototype = {
        name:"原型对象中的属性-姓名",
        className:"原型对象中的属性-班级"
    }

//    Person.prototype.name = "李四";
//    Person.prototype.className = "班级";

    //03 使用构造函数创建对象
    var p1 = new Person();

    //04 访问属性
    console.log(p1.name);   //name属性在对象和对应的原型对象中均存在,则优先使用对象中的属性(就近原则)
    console.log(p1.className); //className属性在对象中没有,则使用对应的原型对象中的属性


</script>
  • 02 设置属性(值类型)

<script>

    //01 提供构造函数
    function Person() {
        this.name = "对象中的属性-姓名"
    }

    //02 设置原型对象
    Person.prototype.age = 20;

    //03 使用构造函数创建对象
    var p = new Person();

    //04 设置属性(值类型)
    p.age = 30;     //思考:它设置了谁的值?
    console.log(p.age);     //30

    //结论:在对对象的属性直接进行赋值操作的时候,无法操作到原型对象,只是对实例属性进行增加|修改
    p.filmay = ["哥哥","姐姐","爸爸","妈妈"];
    console.log(p.filmay);  //["哥哥", "姐姐", "爸爸", "妈妈"]

    //p.car.type = "汽车";  注意:不能这样进行赋值(报错)

    var p2 = new Person();
    console.log(p2.age);    //访问的是对象的原型属性(20)
    console.log(p2.filmay); //undefined
</script>
  • 03 设置原型对象的属性

<script>

    //01 提供一个空的构造函数
    function Person() {
    }

    //02 设置原型对象的属性(值类型)
    Person.prototype.className = "逍遥派01班";
    Person.prototype.car = {
        type:"汽车",
        number:"B 0888"
    };

    //03 创建对象
    var p1 = new Person();
    var p2 = new Person();

    //如果原型对象中的属性是值类型,那么只能通过Person.prototype.属性的方式修改其值
    //如果原型对象中的属性是引用类型,则情况不一样
    console.log(p1.car.type);   //汽车
    console.log(p2.car.type);   //汽车

    p1.car.type = "火车";
    console.log(p1.car.type);   //火车
    console.log(p2.car.type);   //火车

    //总结:如果原型对象中的某个属性为引用类型,则使用构造函数创建出来的多个对象的原型对象中的该属性指向的是同一块数据
    //    某个对象对该原型对象属性进行了修改会影响到其他的对象

    //补充说明
    p1.car = "测试汽车";
    console.log(p1.car);        //测试汽车
    console.log(p1.car.type);   //undefined
    //直接操作设置的是对象的实例属性,而非原型对象中的属性

    console.log(p2.car.type);   //火车


    //构造器属性
    console.log(Person.prototype.constructor);
    console.log(p1.constructor);

    console.log(Person.prototype.constructor == p1.constructor);
    console.log(Person.prototype.constructor == p1.__proto__.constructor);

</script>
  • proto属性说明:

    • proto是一个非标准属性
    • 即ECMAScript中并不包含该属性,这只是某些浏览器为了方便开发人员开发和调试而提供的一个属性,不具备通用性
    • 建议:在调试的时候可以使用该属性,但不能出现在正式的代码中

代码示例

<script>

    //01 提供一个空的构造函数
    function Person() {

    }

    //02 设置构造函数的原型对象的方法
    Person.prototype.sayHello = function () {
        console.log("hello");
    }

    //03 创建对象
    var p = new Person();

    //04 通过对象的__proto__设置原型对象
    p.__proto__.sayHi = function () {
        console.log("hi");
    }

    //05 尝试调用上面的方法
    p.sayHello();       //hello
    p.sayHi();          //hi

</script>
  • 使用原型对象解决构造函数方式创建对象的问题

代码示例:
<script>

    //01 提供构造函数
    function Student(number,name,age) {
        this.number = number;
        this.name = name;
        this.age = age;
    }

    //02 设置构造函数的原型方法
    Student.prototype.description = function () {
        console.log("我的名字是" + this.name + "学号是" + this.number + "年龄是" + this.age);
    };

    //03 使用构造函数来创建对象
    var stu1 = new Student("20170201","严雯",18);
    var stu2 = new Student("20170202","严二雯",16);

    //04 调用创建该对象的构造函数的原型对象中的方法(检查原型方法)
    stu1.description();
    stu2.description();

    //05 验证构造函数创建出来的多个对象共享原型对象的属性和方法
    console.log(stu1.description == stu2.description);

</script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容