Js中的对象、构造函数、原型、原型链及继承

一、对象数组

在传统的面向过程的程序设计中,会形成函数或变量的冗余。而JS中对象的目的是将全部的具备相同属性或行为的代码整合到一块儿,造成一个集合,这样就会方便咱们管理,例如:函数

var person1={
    name:"tan",
    age:26,
    showMessage:function(){
        alert("name:"+this.name);
    }
};
person.showMessage();//输出name:tanthis

以上的例子将name、age、showMessage放进person1这个对象中,方便了咱们的管理同时也减小了咱们的命名困难。.net

咱们下面的讲解会用到的基本知识点:prototype

1)、内存会对每个对象一个内存空间;设计

2)、函数也是一个对象。指针

每个对象都会占据必定的内存空间。对象

二、构造函数blog

以上能够看出对象的产生方便了咱们的代码管理,可是又产生了一个问题,若是我又定义了一个对象person2,以下:继承

var person1={

   name:"song",

    age:16,

    showMessage:function(){

       alert("name:"+this.name);

    }

};

这样就产生了代码的重复问题——person1与person2有一样的属性和行为,是否是能经过创造一个函数经过传参来改变对象的属性值,这样就引出了构造函数的概念。

function Person(name,age)={

    this.name=name;

    this.age=age;

      this.showMessage=function(){

       alert("name:"+this.name);

    };

}

var person1=new Person(tan,26);

var person2=new Person(song,16);

这样经过构造函数咱们就不用反复去从新定义属性和行为,咱们就创造了两个对象person1和person2。person1和person2也叫做构造函数Person的两个实例。

三、原型

看上去构造函数能够完美的解决咱们的代码管理和重复性的问题。可是,正如在1中提到的函数也是一个对象,也会有必定的内存空间,属性咱们能够容忍每个对象占据一个空间,但方法也就是行为,他对每个对象来讲动做是同样的,只是可能的参数不同。所以咱们要想一个方法来解决内存空间被过多的占用的问题。

拟解决方法1:函数的定义转移到构造函数外,例如:

function Person(name,age)={

    this.name=name;

    this.age=age;

      this.showMessage=showMessage;

}

function showMessage(){

        alert("name:"+name);

}

这时构造函数中this.showMessage会指向showMessage这个全局变量,先在构造函数的内部去找showMessage这个变量,而后去外部找(涉及到了做用域链的问题之后再说)。

这个解决方案看似很好,但一个对象如有多个方法时,代码的封装性没法体现,并且全局的函数只是为一个对象服务,则全局性体现的不明显。

拟解决方法2:原型

首先要知道,每个函数在建立的时候都会默认的分配一个prototype属性,构造函数也不例外。那么 prototype属性是什么?

prototype是一个指针,它指向一个对象。指针就像是我想到存一本书在一间房子里(这是一个行为),我要完成这个行为,我先要建房子而后把书放进房子里,我下次要存一本新书,那么我还要先建房子在放另外一本书,是否是听起来很麻烦,那么更好的解决方法呢?整个行为房子是一个肯定的动做,不须要每次都重建,我建一次把房子的地址记下来,之后我每一次有放书这个动做时只须要经过地址找到对应的房子就好了。如上面的例子showMessage就是建房子的动做,name是书,protoype属性是地址。构造函数就是每放一本书就要建一个房子,而原型就是经过地址去寻找房子。

//建房子

function Person(){

}

//房子里有什么并肯定了指针的指向

Person.prototype={

        name:"tan",

        age:"22",

        showMessage:function(){

               alert("name:"+this.name);

        }

};

var person1 = new Person();

person1这样就有了指针,就能访问指针指向的内存空间。
我想大家应该有如下的疑问:

1)对象person1是否能够有本身的属性?

能够有,并且对于person1和原型Person中都有的属性,先考虑的是person1中的属性。

2)是否能经过person1改变原型属性值:

对不起,不能够,实例person1只是获取了一个指向原型的指针,他并无改变原型的权利。但有一点要特别注意,对于包含引用类型的属性——列如数组。有一些操做是容许经过地址去访问内存的,列如push,这些操做就有可能改变原型属性,这个改变会形成灾难性的后果,由于全部引用这个原型的对象都会随之改变。
四、组合使用构造函数和原型来创造对象(自定义类型,也叫引用类型)

这是经常使用的自定义类型的建立方式,构造函数用来定义实例属性,而原型用于定义方法和共享属性。所以,每个实例都会有本身的一份实例属性的副本,但同时又共享着对方法的引用,最大限度的节约了内存。例如:

function Person(name,age){

        this.name=name;

        this.age=age;

}

//房子里有什么并肯定了指针的指向

Person.prototype={

        construction:Person,

        showMessage:function(){

               alert("name:"+this.name);

        }

};

var person1 = newPerson("tan",22);

prototype中的默认的construction属性,让原型指向构造函数,默认是Person。

五、原型链与继承

咱们以上说的都是同类型下的对象,person1和person2都是Person的实例。假如我有Person和Man两个引用类型,Person中的属性和方法是有Man须要的,我想偷懒直接从

Person中全部的属性和方法拿过来,这就是继承。那么我做为一个继承的引用类型我能得到谁的属性和方法,那么在这个问题上就会有原型链的概念。当对象尝试获某个属性时,该对象没有,会尝试从原型对象中去找,原型对象没有,在从原型对象的原型去找,最后到达Object.prototype。

 例如:

function Person(name,age){
this.pname=name;
this.page=age; 
}
Person.prototype={
showPMessage:function(){
alert("name:"+this.pname);
}
};
function Man(name,age){
        this.mname=name;
this.mage=age; 
}

//这一句话表示原型的指针指向了Person
Man.prototype = new Person("tan",22,"man");

//给原型添加方法必定要放在替换原型的语句以后
Man.prototype.test="wosi";
Man.prototype.showMMessage=function(){
alert("name:"+this.mname);
};

var song=new Man("song",1);
song.showMMessage();//显示song

song.showPMessage();//显示tan

出处:https://blog.csdn.net/tanzhengyu/article/details/50888657