前端开发那些事程序员前端开发

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

2017-01-07  本文已影响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.总结

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

上一篇下一篇

猜你喜欢

热点阅读