JavaScript难点——原型对象及其方法


0.前言

最近在网上学习原型这一块,看了很多博客,都不尽人意,因此笔者自己写一篇文章,尽量让大家明白这是怎么一回事。上一节我们只是了解一下js中的常用方法,同时也了解到prototype和constructor这两个属性,就是为了这一节做铺垫。

1.原型属性(prototype属性)

原型属性也叫prototype属性,每一个函数都有prototype属性,初始指向一个空对象(也叫原型对象)。我们可以给prototype进行修改,让它引用一个非空对象,只有在该函数是构造函数时才有实际意义。对于非构造函数,不会对函数的运行造成影响。当函数为构造函数时,我们可以通过原型属性修改原型对象,达到给用构造函数创建的对象增加属性和行为的功能。

2.利用原型添加方法与属性并修正constructor属性

首先定义一个构造函数

function Person(name, age){
            this.name = name;
            this.age  = age;
            this.say = function(){
                console.log("My name is " + this.name);
            };
        }
(1)利用原型添加方法和属性
Person.prototype.height = 175;
        Person.prototype.weight = 65;
        Person.prototype.run = function(){
            console.log("run");
        };
(2)用已存在的对象去给prototype赋值
Person.prototype = {
            height: 175,
            weight:65,
            run: function(){
                console.log("run");
            }
        };

定义上面两个方法时,我们发先一个问题,因为在上一节中我们了解到constructor是指向创建对象的构造函数,但是在这里由构造函数的prototype指向的原型对象变成了现有的对象,不是构造函数本省的原型对象,因此让它的constructor重新只回来,指向构造函数,这也是原型链的原理来张图片:

捕获.PNG

所以要添加如下的方法:

//解决:重新赋值成对应的构造函数
Person.prototype.constructor = Person;

var per = new Person("sunck", 18);
console.log(per.constructor);
console.log(Person.prototype.constructor);

结果:

捕获.PNG

实例化对象

var per1 = new Person("sunck", 18);
        console.log(per1.name);
        console.log(per1.age);
        per1.say();

        console.log(per1.height);
        console.log(per1.weight);
        per1.run();

结果:

捕获.PNG

发现实例化的对象可以访问原型对象中的属性和方法,可以发现原型对象可以为对象添加属性和方法。

3.使用原型的方法与属性

上一个方法主要讲了用原型设置属性和方法,既然能设置,那么肯定能访问,我们来看一下。
还是上面的代码:

//访问自身属性与方法
console.log(per.name);
console.log(per.age);
per.say();

结果:


捕获.PNG

当前对象访问原型对象中的属性(访问原型属性):
访问原型属性的方式与访问自身属性的方式是一样的。
对象访问属性的原理:当我们访问name属性时,首先在自身属性中查找,找到了立即返回当前属性的值。当我们访问height属性时,也会先在自身属性中查找,找不到的话去它的原型对象中查找,找到就返回数值。如果找不到还会去上一级原型对象中查找,最终找不到反返回undefined。

console.log(per.height);
        console.log(per.constructor.prototype.height);
        per.run();

结果:

捕获.PNG

我们来总结一下:
原型对象的精髓:实时性;在JS中,对象的传递都是引用传递,对于同一个构造函数创建的对象来说,仅仅是拥有一个原型对象的引用,不会拥有原型对象的副本。如:

Person.prototype.eat = function() {
    console.log("eat");
};
per.eat();

结果:

捕获.PNG

在上面的代码,你发现了什么?在构造函数中没有eat()这个函数,于是在原型对象上我们添加了一个eat()方法;per对象是在添加eat()方法之前就被创建了,但是它还是能访问后来创建的eat()函数,这就是原型对象的精髓——实时性

4.利用自身属性重写原型属性——hasOwnProperty()与isPrototypeOf()方法

这个知识点主要是介绍hasOwnProperty()与isPrototypeOf()这两个方法。可能上代码更能直观点:

var base = {
            height: 180,
            weight:70,
        };

        function Person(name, age){
            this.name = name;
            this.age  = age;
            this.height = 175;
            this.say = function(){
                console.log("My name is " + this.name);
            };
        }


        //
        Person.prototype = base;
        Person.prototype.constructor = Person;
        console.log(base.constructor);


        var per = new Person("sunck", 18);
        console.log(per.constructor);
        console.log(per.height);

在这扯个题外话:访问height属性,是自身属性还是原型属性呢?再上一个知识点说到,现在滋生属性上找,没有找到的话就到原型对象上找。所以这是——自身属性
结果:

捕获.PNG

看见 console.log(per.height);打印出来的是自身属性。
hasOwnProperty():判断属性是否是自身属性;自身属性返回true,原型属性返回false

console.log(per.hasOwnProperty("weight"));

结果:

捕获.PNG

删除与原型属性同名的height属性,那么原型属性暴露出来

delete per.height;
console.log(per.height);

isPrototypeOf():判断一个对象是否是另一个对象的原型对象

console.log(base.isPrototypeOf(per));
        console.log(new Array(5).isPrototypeOf(per));

结果:

5.for-in枚举属性(propertyIsEnumerable()方法)

var base = {
            height: 180,
            weight:70,
        };
        function Person(name, age){
            this.name = name;
            this.age  = age;
            this.say = function(){
                console.log("My name is " + this.name);
            };
        }
        Person.prototype = base;
        // Person.prototype.constructor = Person;



        var per = new Person();

        for(var i in per){
            console.log(i);
        }

结果:


捕获.PNG

总结一下:
1.不是所有的属性都能遍历出来,比方说数组中的length和constructor。自身属性与原型属性(原型链上的属性)都可以遍历。
2.內建属性,对象自身自带的属性。內建属性大多数都是不可以枚举的。
3.propertyIsEnumerable判断属性是不是可枚举的,原型属性都会返回false。

console.log(per.propertyIsEnumerable("name"));
console.log(per.propertyIsEnumerable("height"));
console.log(per.propertyIsEnumerable("constructor"));
console.log(new Array(5).propertyIsEnumerable("length"));

结果:


捕获.PNG

6.总结

   这一节的原型对象我自认为说的还算通畅吧,如果又不懂得地方欢迎来信哦!!!

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

推荐阅读更多精彩内容