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]);
}
—本节结束—
浙公网安备 33010602011771号