前言:大家都知道,OOP有三大特性:封装,继承,多态。下面是自己对这三个特性的理解:

封装:把属性与方法整合到某种数据类型中。目的是让类的使用者按类的编写者的意愿去使用类。在封装过程中会一般会做两件事:

① 隐藏内部实现 ② 对外提供接口(访问权限控制)。

继承:共享父类的属性与方法

多态:不同对象执行相同的操作,可以产生不同的结果。关于多态要注意两点:

① 在子类以父类的形式存在时,不能使用子类的属性与方法
② 子类在工作时,采用自己的实现方式。

下面我们以java为例子看看OOP的三个特性。

/**
* 定义类:Animal
*/
public class Animal {
private String cate; public String getCate() {
return cate;
} public void setCate(String cate) {
this.cate = cate;
} public void shout() {
System.out.println("Animal shouted");
}
} /**
* 定义类:Dog,并让其从Animal继承
*/
class Dog extends Animal {
@Override
public void shout() {
System.out.println("dog shouted");
}
} /**
* 定义类:Collie,并让其从Dog类继承
*/
class Collie extends Dog {
@Override
public void shout() {
System.out.println("collie shouted");
} public void graze() {
System.out.println("collie graze");
}
}
 
//测试代码
public class OOPTest {
public static void main(String[] args) {
//封装
Animal animal = new Animal();
animal.shout();//Animal shouted //继承: Dog中并没有声明cate域,也没有对应的setter/getter
Dog dog = new Dog();
dog.setCate("dog");
System.out.println(dog.getCate());//dog //多态
Animal dog2 = new Collie();
dog2.shout();//collie shouted
//dog2.graze();error! 在子类以父类的形式存在时,不能使用子类的属性与方法
((Collie)dog2).graze();//进行向下转型后可以运行,打印出:collie graze
}
}

一: OOP在JS中的实现

但对于Js而言,目前还没有实现class关键字,也没有private,protected,public权限修辞符。但我们可以使用闭包来实现封装:

/**
* 定义Animal类型
* @returns {Animal}
* @constructor
*/
function Animal() {
var _cate; //防止直接调用Animal构造函数在window上新增属性
if(this instanceof Animal) {
this.setCate = cateSetter;
this.getCate = cateGetter;
this.shout = shout;
} else {
return new Animal;
} //使用函数名cateSetter方便理解
function cateSetter(cate) {
_cate = cate;
} function cateGetter() {
return _cate;
} function shout() {
console.log('Animal shouted');
} }
//使用:
var animal = new Animal();
animal.shout();//animal shouted
//直接不能访问到cate属性,只有通过对外提供的方法(setCate/getCate)去访问
animal.setCate('animal~~');
console.log(animal.getCate());//animal~~
 

JS中的继承是通过prototype来实现的,现在新增Dog类型,并从Animal继承:

/**
* 定义Dog类型,并让其从Animal继承
* @constructor
*/
function Dog() {}
Dog.prototype = new Animal();
//让instanceof运行符可以正常工作
Dog.prototype.constructor = Dog;
//测试:
var dog = new Dog();
//dog具有了方法shout, cate的getter/setter
dog.setCate('dog');
console.log(dog.getCate());//dog
dog.shout();//animal shouted
console.log(dog instanceof Dog);//true
console.log(dog instanceof Animal);//true

接着定义类型Collie,并实现多态:

/**
* 定义Collie类型,并让其从Dog继承
* @constructor
*/
function Collie(){}
//让Collie从Dog继承
Collie.prototype = new Dog;
Collie.prototype.constructor = Collie;
//为Collie新增graze方法
Collie.prototype.graze = function() {
console.log('collie graze');
}
//重写Collie的shout方法
Collie.prototype.shout = function() {
console.log('collie shouted');
}
//测试
var collie = new Collie();
collie.setCate('collie');
console.log(collie.getCate());//collie
console.log(collie instanceof Collie);//true
console.log(collie instanceof Dog);//true
console.log(collie instanceof Animal);//true
//多态:相同的方法,产生了不同的行为
collie.shout(); //collie shouted
 

完整的OOP实现代码:

/**
* 定义Animal类型
* @returns {Animal}
* @constructor
*/
function Animal() {
var _cate; //防止直接调用Animal构造函数
if(this instanceof Animal) {
this.setCate = cateSetter;
this.getCate = cateGetter;
this.shout = shout;
} else {
return new Animal;
} //使用函数名cateSetter方便理解
function cateSetter(cate) {
_cate = cate;
} function cateGetter() {
return _cate;
} function shout() {
console.log('animal shouted');
} } /**
* 定义Dog类型,并让其从Animal继承
* @constructor
*/
function Dog() {}
Dog.prototype = new Animal();
//让instanceof运行符可以正常工作
Dog.prototype.constructor = Dog; /**
* 定义Collie类型,并让其从Dog继承
* @constructor
*/
function Collie(){}
//让Collie从Dog继承
Collie.prototype = new Dog;
Collie.prototype.constructor = Collie;
//为Collie新增graze方法
Collie.prototype.graze = function() {
console.log('collie graze');
}
//重写Collie的shout方法
Collie.prototype.shout = function() {
console.log('collie shouted');
}

二: 缺点

这种构造函数(闭包)+prototype的实现的缺点:

1. 使用闭包模拟私有属性时,造成同一类型的多个实例共享一个相同闭包变量(Dog.prototype = new Animal() 只生成了一个闭包变量)

2. 每次实例化一个子对象时,都先要实例化一个父对象

3. 不能在子对象上调用父对象上的同名方法

4. 引用类型的共享Bug(在prototype上面的引用类型都会有这个问题,因为各个function的prototype是一个指针,实际的prototype对象在堆中只有一份内存分配)

5. 封装不优雅,很散乱

缺点1的测试代码:

var dog = new Dog();
var dog2 = new Dog();
//dog1,dog2共享闭包变量_cate,明显这不合适
dog.setCate('dog1');
console.log(dog.getCate());//dog1
dog2.setCate('dog2');
console.log('+++'+dog.getCate());//dog2
console.log('+++'+dog2.getCate());//dog2

小结JS中的OOP(上)的更多相关文章

  1. 小结JS中的OOP(下)

    关于JS中OOP的具体实现,许多大神级的JS专家都给出了自己的方案. 一:Douglas Crockford 1.1 Douglas Crockford实现的类继承 /** * 原文地址:http:/ ...

  2. 小结JS中的OOP(中)

    此篇文章主要是提炼<JavaScript高级程序设计>中第六章的一些内容. 一:JS中OOP相关的概念 开始之前先总结JS中OOP相关的一些概念: 构造函数:JS中的构造函数就是普通的函数 ...

  3. 不会JS中的OOP,你也太菜了吧!(第二篇)

    一.你必须知道的 1> 原型及原型链在继承中起到了关键的作用.所以你一定要理解他们.2> 不会JS中的OOP,你也太菜了吧!(第一篇) 二.继承的6种方法 1> 原型链继承 原型链继 ...

  4. JS中的继承(上)

    JS中的继承(上) 学过java或者c#之类语言的同学,应该会对js的继承感到很困惑--不要问我怎么知道的,js的继承主要是基于原型(prototype)的,对js的原型感兴趣的同学,可以了解一下我之 ...

  5. JS中在当前日期上追加一天或者获取上一个月和下一个月

    /** * 获取上一个月 * * @date 格式为yyyy-mm-dd的日期,如:2014-01-25 */ function getPreMonth(date) { var arr = date. ...

  6. 不会JS中的OOP,你也太菜了吧!(第一篇)

    一.你必须知道的 1) 字面量 2) 原型 3) 原型链 4) 构造函数 5) 稳妥对象(没有公共属性,而且其方法也不引用this的对象.稳妥对象适合用在安全的环境中和防止数据被其它程序改变的时候) ...

  7. 在js中如何得到上传文件的大小。

    <html>  <head>  <script language="javascript">    function getSize() {   ...

  8. JavaScript面向对象(一)——JS OOP基础与JS 中This指向详解

      前  言 JRedu 学过程序语言的都知道,我们的程序语言进化是从"面向机器".到"面向过程".再到"面向对象"一步步的发展而来.类似于 ...

  9. js中静态函数与变量

    一 私有变量和函数 js中没有概念上的私有,公有也没有静态和非静态相关概念,有的只能是通过作用于来模仿 函数的块级作用域使得函数内部成员可以不被外部所访问,比如我们使用块级作用于定义一个类 //定义一 ...

随机推荐

  1. maven也是apache下的项目

    maven也是apache下的项目,你看maven官网了,域名都在Apache下

  2. Zabbix简介(第一章第一节)

    Alexei Vladishev创建了Zabbix项目,当前处于活跃开发状态,Zabbix SIA提供支持. Zabbix是一个企业级的.开源的.分布式的监控套件 Zabbix可以监控网络和服务的监控 ...

  3. Java 包装类中的静态函数

    所有的核心类型转化 全是基于这个图的 是不是很简单 so easy~~~ 不过下面的这些函数也是很重要的哦~~~ 以后就可以随意发挥了 猜API吧!

  4. 关于JLINK固件丢失或升级固件后提示Clone的解决办法

    本人用的JLINK仿真器(某宝上买的),在使用新版KEIL时,提示要升级固件,升级后就出现JLINK is Clone的提示.在网上找了许多关于修复的资料,都觉得不是很好.经过本人反复试验,总算找到比 ...

  5. vmware通过vmnet8共享本地网络

    转载于:http://zhaolongchn.blog.163.com/blog/static/19065850420122595117886/ 1,首先将真实电脑的虚拟网卡VMnet8启用 2,然后 ...

  6. Struts2笔记——与ServletAPI解耦

    与ServletAPI解耦的访问方式 为了避免与 Servlet API 耦合在一起, 方便 Action 做单元测试, Struts2 对 HttpServletRequest, HttpSessi ...

  7. ntelliJ IDEA 14 注册码

    user or company nameo license key63625-MQ87K-3SRZ2-8MQYB-6NQZC-2Z8K6

  8. Clearing Floats清除浮动--clearfix的不同方法的使用概述

    清除浮动早已是一个前端开发人员必学的一课.毫无疑问,多年来,我们已经接触过多种清除浮动的方法,现在“clearfix methods”越来越被大家熟知.在深入剖析“clearfix”的多种用法之前,我 ...

  9. EXT实现表格斑马线

    Ext.grid.GridPanel 单双行颜色样式(斑马线)2014-04-03 11:25 1078人阅读 评论(0) 收藏 举报分类:ExtJs(36)Ext.grid.GridPanel st ...

  10. MyBatis学习总结_11_MyBatis动态Sql语句

    MyBatis中对数据库的操作,有时要带一些条件,因此动态SQL语句非常有必要,下面就主要来讲讲几个常用的动态SQL语句的语法 MyBatis中用于实现动态SQL的元素主要有: if choose(w ...