您的位置:首页 > Web前端 > JavaScript

js的两面-面向过程和面向对象

2017-03-21 18:56 190 查看
js是面向过程还是面向过程?一直以来,顶级大师各有各的说法,这里不敢妄加评论。
面向过程就是函数式编程,按照传统流程编写一个又一个的函数来解决需求的方式。
面向过程适合一个人的项目,如果是团队合作,别人想修改你的代码就不利于维护了。所以下面着重聊聊面向对象。
面向对象就是讲你的需求抽象成一个对象,然后针对这个对象分析其属性和方法。
面向对象的主要特点就是封装,继承,多态。
**一,封装**
封装就是把所需要的功能都放到一个对象里。例如
var News=function(id,product,group){
this.id=id;
this.product=product;
this.group=group;
}
也可以通过原型来添加属性和方法。如:
News.prototype.display=function(){
//显示新闻
}
这样我们将所需要的属性和方法都封装到我们抽象的News类里面,当使用功能和方法时,我们不能直接使用News这个类,需要使用new关键字来实例化
新的对象。例如:
var normal_news=new News(1024,"今日头条","北京事业组");
上面this添加的属性和方法是在当前对象上添加的,然而原型创建对象都有prototype,用于指向其继承的属性,方法。这样通过prototype继承的方法
并不是对象自身的,所以在使用这些方法时,需要通过prototype一级一级查找来得到。这样你会发现通过this定义的属性或者方法是该对象自身拥有的,
所以我们每次通过类创建一个新对象时,this指向的属性和方法都会得到相应的创建,而通过prototype继承的属性或者方法是每个对象通过prototype
访问到,所以我们每次通过类创建一个新对象时这些属性和方法不会再次创建。如图所示:




通过new关键字创建的对象实质是对新对象this的不断赋值,并将prototype指向类的prototype所指向的对象,而类的构造函数外面通过点语法定义的属性
方法是不会添加到新创建的对象上去的。因此要想在新创建的对象中使用display就得通过News类使用而不能通过this,如News.display,而类得原型
prototype上定义得属性在新对象里就可以直接使用,这是因为新对象的prototype和类的prototype指向的是同一个对象。

由于每次实例化对象的时候都需要用 new 关键字,所以js实例化有一种安全模式。如下
var News=function(id,product,group){
if(this.instanceof News){
this.id=id;
this.product=product;
this.group=group;
}else{
return new News(id,product,group);
}
}
这样就不用担心忘记使用new关键字的问题了。

二,继承
每个类都有三部分,第一部分是构造函数内的,这是供实例化对象复制用的,第二部分是构造函数外的,直接通过点语法添加的,这是供类使用的看,
实例化对象时访问不到的,第三部分是类的原型中的,实例化对象可以通过其原型链间接地访问到,也是为供所有实例所共用的。然而在继承中所涉
及的不仅仅是一个对象。
在JavaScript中没有继承这一现有的机制,那怎么实现呢!
2.1 子类的原型对象--类式继承
//类式继承
//声明父类
function SuperClass(){
this.superValue=true;
}
//为父类添加共有方法
SuperClass.prototype.getSuperValue=function(){
return this.superValue;
}
//声明子类
function SubClass(){
this.subValue=false;
}
//继承父类
SubClass.prototype=new SuperClass();
SubClass.prototype.getSubValue=function(){
return this.subValue;
};
继承很简单,就是声明两个类而已,不过类式继承需要将第一个类的实例赋值给第二个类的原型。
类的原型对象的作用就是为类的原型添加共有方法,但类不能直接访问这些属性和方法,必须通过原型prototype来访问。而我们实例化一个父类的时候,
新创建的对象复制了父类的构造函数内的属性与方法并且将原型__proto__指向了父类的原型对象,这样就拥有了父类的原型对象上的属性和方法,
并且这个新创建的对象可直接访问到父类原型对象上的属性和方法,如果我们将这个新创建的对象赋值给予类的原型,那么子类的原型就可以访问到父类
的原型属性和方法,新创建的对象不仅仅可以访问父类原型上的属性和方法,同样也可访问从父类构造函数中复制的属性和方法。你将这个对象赋值给予
类的原型,那么这个子类的原型同样可以访问父类原型上的属性和方法与从父类构造函数中复制的属性和方法。
2.2 创建即继承--构造函数继承
//构造函数式继承
//声明父类
function SuperClass(id){
//引用类型共有属性
this.books=['JavaScript','html','css'];
//值类型共有属性
this.id=id;
}
//父类声明原型方法
SuperClass.prototype.showBooks=function(){
console.log(this.books);
}
//声明子类
function SubClass(id){
//继承父类
SuperClass.call(this,id);
}
//创建第一个子类的实例
var instance1=new SubClass(10);
//创建第二个子类的实例
var instance2=new SubClass(11);

instance1.books.push("设计模式");
console.log(instance1.books); //['JavaScript','html','css',‘设计模式’]
console.log(instance1.id); //10
console.log(instance2.books);//['JavaScript','html','css']
console.log(instance2.id);//11
instance1.showBooks(); //TypeError

由于call这个方法可以更改函数的作用环境,因此在子类中,对superClass调用这个方法就是将子类中的变量在父类中执行一遍,由于父类中是给this
绑定属性的,因此子类自然也就继承了父类的共有属性。由于这种类型的继承没有涉及原型的prototype.所以父类的原型方法自然不会被子类继承,
而如果要想被子类继承就必须要放在构造函数中,这样创建出来的每个实例都会单独拥有一份而不能共用,这样就违背了代码复用的原则。为了综合这两
种模式的优点,就有了组合式继承。
2.3 将优点为我所用--组合式继承
//组合式继承
//声明父类
function SuperClass(name){
//值类型共有属性
this.name=name;
//引用类型共有属性
this.books=['html','css','javaScript'];
}
//父类原型共有方法
SuperClass.prototype.getName=function(){
console.log(this.name);
};
//声明子类
function SubClass(name,time){
console.log(this.name);
};
//声明子类
function SubClass(name,time){
//构造函数式继承父类name属性
SuperClass.call(this,name);
//子类中新增共有属性
this.time=time;
}
//类式继承 子类原型继承父类
SubClass.prototype=new SuperClass();
//子类原型方法
SubClass.prototype.getTime=function(){
console.log(this.time);
}

在子类构造函数中执行父类构造函数,在子类原型上实例化父类就是组合模式这样就融合了类式继承和构造函数继承的有点,并过滤掉其缺点。

三,多态
多态就是同一个方法多种调用方式。
//多态
function add(){
var arg=arguments,len=arg.length;
switch(len){
case 0:
return 10;
case 1:
return 10+arg[0];
case 2:
return arg[0]+arg[1];
}
}
对于多态就是根据传参不同做相应运算。将不同运算方法封装在类内,这样代码更容易懂。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: