JS学习专辑(7)-"类"的创建和继承
其实在JS中是没有类这个概念的,它没有像Class那样的专门定义的类,但我们一般可以通过对对象创建的模拟把它模拟成类。
书上介绍了几种创建类的方式,在这里:
1.工厂方式:这个方式在函数内部定义对象,并定义各种属性,最后返回对象。一般如果用这个的话我们把属性方法定义在函数外面,这样就可以避免重复创建该方法。
function Student1(name,age){ var obj=new Object(); obj.name=name; obj.age=age; obj.f=f; return obj; } var f=function(){ return (this.name+" "+this.age); } var student1=Student1("jk","12"); console.log(student1.name+" "+student1.age+" "+student1.f()); //jk 12 jk 12 if(student1 instanceof Student1){console.log("Y")}else{console.log("N")} //N
只是上面这种方式无法进行对对象的类型的识别的,也就是说无法通过instanceof方法判断它属于那个类。
2.构造函数方式:这个方式使用构造函数创建对象,不用在函数内部创建,而使用this指代,不用return。同上一样,如果用这个就要把方法定义在外面。
function Student2(name,age){ this.name=name; this.age=age; this.f=f; } var f=function(){ return (this.name+" "+this.age); } var student2=new Student2("jk","12"); console.log(student2.name+" "+student2.age+" "+student2.f()); //jk 12 jk 12 if(student2 instanceof Student2){console.log("Y")}else{console.log("N")} //Y
3.原型方式:在函数中不对属性进行定义,然后利用prototype的属性进行属性定义。
function Student3(name,age){ } Student3.prototype={ name:null, age:null, f:function(){ return this.name+" "+this.age; } }; var student3=new Student3; student3.name="jk"; student3.age="12"; console.log(student3.name+" "+student3.age+" "+student3.f()); //jk 12 jk 12
只是单单用原型方式的话不是很好,因为当这个类有一个引用属性时,改变一个对象的这个属性也会改变其他对象得属性。比如一个Array再push进去东西的话,其他的对象属性也会更改。
4.混合的构造函数和原型模式(都推荐使用的是这个):将所有的不是方法的属性定义在函数中,将所有方法属性利用prototype定义在函数外面:
function Student4(name,age){ this.name=name; this.age=age; } Student4.prototype.f=function(){ return this.name+" "+this.age; } var student4=new Student4("jk",12); console.log(student4.name+" "+student4.age+" "+student4.f()); ////jk 12 jk 12
这个是使用率最高的一种方式,也没有上面那些缺点。
5.动态原型方式(这个也是常用的):这个和上面那个是差不多的,都是在不是方法的属性定义在函数中,所有方法利用prototype定义。唯一的区别是赋予对象方法的位置。
function Student5(name,age){ this.name=name; this.age=age; if(typeof Student5.f=="undefined"){ Student5.prototype.f=function(){ return this.name+" "+this.age; } Student5.f=true; } } var student5=new Student5("jk",12); console.log(student5.name+" "+student5.age+" "+student5.f()); //jk 12 jk 12
上面一些就是类的创建的方法,然后类的继承的话最简单的是通过利用共享prototype实现继承,先看下例子:
function Student6(name,age){ this.name=name; this.age=age; } Student6.prototype.f1=function(){ return this.name; } Student6.prototype.f2=function(){ return this.age; } function Candle(name,age,islight){ this.name=name; this.age=age; this.islight=islight; } Candle.prototype=Student6.prototype; //也可以这样Candle.prototype=new Student6(); Candle.prototype.f3=function(){ return this.islight; } var student6=new Student6("jk",12); console.log(student6.f1()+" "+student6.f2()); //jk 12 var candle=new Candle("jk",12,"no"); console.log(candle.f1()+" "+candle.f2()+" "+candle.f3()); //jk 12 no console.log(candle instanceof Student6); //true console.log(candle instanceof Candle); //true
上面的例子中第二个类继承了第一个类的f1和f2的方法,这是通过拷贝第一个类的prototype到第二个来实现的。然后用instanceof来判断了下对象是否是这两个类的实例是OK的。因为这个是用共享prototype的方法来实现定义的,是对同一个对象的引用,所以惟一的约束是不允许类成员的覆盖定义。
上面那种方法在不要求严格的情况下,这样的继承是比较简单方便的。但是毕竟如果成员的重新定义都会互相有影响,所以还有一种方法是通过反射机制和prototype实现继承,思路和上面那个差不多,但利用for(…in…)语句枚举出所有基类prototype的成员,并将其赋值给子类的prototype对象。下面是例子:
function Student7(name,age){ this.name=name; this.age=age; } Student7.prototype.f1=function(){ return this.name; } Student7.prototype.f2=function(){ return this.age; } function Candle(name,age,islight){ this.name=name; this.age=age; this.islight=islight; } //让Candle继承于Student7 for(var p in Student7){ Candle.prototype[p]=Student7.prototype[p]; } Candle.prototype.f1=function(){ //覆盖第一个类的f1方法 return this.age; } Candle.prototype.f2=function(){ //覆盖第一个类的f2方法 return this.name; } Candle.prototype.f3=function(){ return this.islight; } var student7=new Student7("jk",12); console.log(student7.f1()+" "+student7.f2()); //jk 12 var candle=new Candle("jk",12,"no"); console.log(candle.f1()+" "+candle.f2()+" "+candle.f3()); //12 jk no
OK,上面的那些就是关于js类的创建和继承,如有新东西可以继续补充~