美文网首页前端开发那些事程序员前端开发
JavaScript难点——原型对象及其方法

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

作者: 紫荆峰 | 来源:发表于2017-01-07 10:30 被阅读0次

    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.总结

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

    相关文章

      网友评论

        本文标题:JavaScript难点——原型对象及其方法

        本文链接:https://www.haomeiwen.com/subject/nsyxbttx.html