Javascript面向对象编程(一):封装

Javascript是一种基于对象的语言,可区别于真正的面向对象语言(我们俗称的OOP),原因就在于它的语法中,压根就没有我们所熟知的class的存在。

那么,我们如何才能做到类似于class这种效果呢?这里介绍两种方式:

一、 生成对象的原始模式:

如:

  var Person={

    name:'张三',

    sex:'男',

    age:26

  }

我们称上述为一个原型对象的规格,Person就类似于一个class,里面的name、sex、age就是我们所熟知的属性,我们在规格里面已经定义了初始化的数据。

如何根据规格生成实例呢?

首先定义一个空对象:

  var person_A={};

  person_A.name='二狗子';

  person_A.sex='男';

  person_A.age=27;

这就做到了一个最简单的封装,但很容易看出缺点:

1. 多个实例的时候,书写很麻烦;

2. 实例与原型之间,似乎压根就没有什么关系,看不出联系。

那么,我们就引导出如何对这种原始的模式进行改进呢?

二、 原始模式的改进模式:

为了解决代码重复问题,我们可以定义一个函数:

  function Person(name,sex,age){

    return {

      name:name,

      sex:sex,

      age:age

    }

  }

然后我们可以用次函数生成实例对象:

  var person_A=Person("二狗子","男",27);

这种改进方式,仅仅是避免了代码重复书写的问题,并未反映出它们是同一个对象的实例。

于是,我们引出第三种模式

三、 构造函数模式

Javascript提供了构造函数模式:其实就是普通函数,内部使用this变量,对构造函数使用new关键字,就能生成实例,并且this变量会绑定在实例对象上。

  function Person(name,sex,age){

    this.name=name;

    this.sex=sex;

    this.age=age;

  }

于是,我们就可以生成实例对象了:

  var person_A=new Person("二狗子","男",27);

调用的时候,直接用: person_A.name  / person_A.sex  / person_A.age即可;

此外,

1. 我们可以用实例的constructor属性,指向他们的构造函数:

  alert(person_A.constructor==Person);  //结果为true

2. Javascript提供了instanceof运算符,验证对象和实力对象的关系:

  alert(person_A instanceof Person);  //结果为true

是不是觉得这样就是完美了呢?非也~

构造函数的方法是很好用,但浪费内存的问题也很明显。

如:我们在Person对象新增一个不变的属性"type",在添加一个方法work(工作),如此一来:

  function Person(name,sex,age){

    this.name=name,

    this.sex=sex;

    this.age=age;

    this.type="灵长类动物";

    this.work=function(){

      alert("我是勤劳的小蜜蜂!");

    };

  }

创建实例:

  var person_A=new Person("二狗子","男",27);

  var person_B=new Person("三娃子","男",30);

  alert(person_A.type);  //灵长类动物

  person_A.work(); //我是勤劳的小蜜蜂!

看上去似乎没问题,但有一个很大的弊端。对于每一个不同的实例对象,type和work()方法都是一模一样的内容,每一次生成一个实例,就都是重复的内容,占用内存,效率低。

可以用下面方法检验相同的work()方法是不同的实例:  

alert(person_A.work==person_B.work);  //返回的结果是false

于是,我们引出最后的模式:

四、Prototype模式:

Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数实例继承。

  function Person(name,sex,age){

    this.name=name;

    this.sex=sex;

    this.age=age;

  }

  Person.prototype.type="灵长类动物";

  Person.prototype.work=function(){

    alert("我是勤劳的小蜜蜂!");

  }

然后,我们类似的去创建实例:

  var person_A=new Person("二狗子","男",27);

  var person_B=new Person("三娃子","男",30);

  alert(person_A.type);  //灵长类动物

  person_A.work(); //我是勤劳的小蜜蜂!

在这里验证:

  alert(person_A.work==person_B.work);  //返回的结果是true

由此,我们可知重复的部分其实都是同一个内存地址,指向prototype对象,这样就避免了多个不同的实例对象重复使用相同的属性值和函数,提高了运行效率。

使用Prototype方法,Javascript定义了一些辅助的方法,帮助我们使用:

1. isPrototypeOf()

判断prototype对象和某个实例之间的关系

  alert(Person.prototype.isPrototypeOf(person_A));  //true

  alert(Person.prototype.isPrototypeOf(person_B));  //true

2. hasOwnProperty()

每个实例对象都有一个hasOwnProperty方法,判断某一个属性到底属于本地属性,还是继承于prototype对象的属性。

  alert(person_A.hasOwnProperty("name"));  //true

  alert(person_A.hasOwnProperty("type")); //false

3. in运算符

(1). 判断某个实例是否含有某个属性(不管是本地属性还是继承于prototype属性)

  alert("name" in person_A); //true

  alert("type" in person_A); //true

(2). 遍历某个对象的所有属性

  for(var prop in person_A){

    alert("person_A["+prop+"]="+person_A[prop]);

  }

 

—本节结束—

posted @ 2015-12-14 12:38  我喂自己袋盐_1989  阅读(153)  评论(0)    收藏  举报