面向对象编程主要涵盖:封装、继承、多态
1.封装
将属性和方法组合在一起形成一个类,通过new实例一个对象。这就是封装
先看一下js的一阶封装
?
<script>
var Cat = {
name : ‘‘,
color : ‘‘
};
var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
</script>
?上面cat1和cat2都是参考Cat的属性设置的,但是两者之间似乎没有任何关系。
再来看看二阶封装——构造函数
?
<script>
function Cat(name,color){
this.name = name;
this.color = color;
}
var cat1 = new Cat("小明","黑色");
var cat2 = new Cat("小红","红色");
alert("cat1.constructor == Cat如果返回true,表示cat1的构造函数时Cat,也表示Cat就是构造函数:"+cat1.constructor == Cat);
alert(cat2.constructor == cat1.constructor);
alert(cat2.constructor);
alert(cat1.constructor);
</script>
?上下文:this
this永远指向当前代码的上下文
?
?
<script>
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var than = this;
return function(){
return than.name;
};
}
};
alert(object.getNameFunc()());
</script>
?大家自己在火狐上面运行看看得到的结果。如果把上面的var than=this;去掉结果又是什么呢。好好体会this关键字。
?
Prototype形式的封装
我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是将该对象的实例共享所有属性和方法。那么,prototype就可以通过调用构造函数来创建那些对象实例的原型对象。
翻译白话:写一个对象函数,然后可以通过对象函数的prototype来定义其他的属性和方法,并且这个属性和方法都会被该对象的实例直接共享。
使用原型的好处是可以让对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中添加定义对象信息,而是可以直接将这些信息添加到原型中。使用构造函数的主要问题就是每个方法都要在每个实例中创建一遍。
直接使用构造函数来创建方法
?
<script>
function Cat(name,color){
this.name = name;
this.color = color;
this.eat = function(){
alert("吃鱼");
}
}
var cat1 = new Cat("小明","黑色");
var cat2 = new Cat("小红","红色");
cat1.eat();
alert(cat1.eat == cat2.eat)
</script>
?用prototype来添加方法
?
?
<script>
function Cat(name,color){
this.name = name;
this.color = color;
this.eat2 = function(){
alert(1);
}
//return this;
}
//我们在2.html中已经说过,Cat就是指构造函数。而js里面有个特殊的的对象prototype对象。每一个函数都有prototype属性,这个属性指向prototype对象
Cat.prototype.eat=function(){
alert(this.name+"吃鱼");
}
Cat.prototype.aa = "aa";
var cat1 = new Cat("小明","黑色");
var cat2 = new Cat("小明","黑色");
//alert(cat1);
alert(cat1.aa);
Cat.prototype.aa = "bb";
alert(cat1.aa);
alert(cat2.aa);
/**
var cat2 = new Cat("小红","红色");
//alert(Cat.eat()); //TypeError: Cat.eat is not a function
cat1.eat();
cat1.eat2();
alert(cat1.eat == cat2.eat);
alert(cat1.eat == cat2.eat);
*/
</script>
?
?好好体会一下上面的图。
?
①。因为所有函数都会有一个prototype属性,这个属性指向一个prototype对象(原型对象)。所以上面Cat对象的prototype属性指向原型对象。然后我们在原型对象上添加了一个eat方法。
②。所有通过Cat new出来的实体都会有一个匿名属性__proto__这个属性指向Cat指向的prototype对象。这个cat1和cat2就都具有eat方法。
③。原型对象具有一个constructor属性,这个属性指向自己的构造函数,那么上面的原型对象就会指向Cat方法
构造函数,实例,原型对象的区别
实例就是通过构造函数创建的。实例创造出来就具有constructor属性(指向构造函数)和__proto__属性(指向原型对象)。
构造函数中有一个prototype属性,这个属性是一个指针,指向它的原型对象。
原型对象内部也有一个指针(constructor属性)指向构造函数:Cat.prototype.constructor = Cat;
实例可以访问原型对象上定义的属性和方法。
继承
JavaScript实现继承的方式有很多,我们介绍几种简单并且使用的比较多的方式
继承是什么?
答:子类能够调用父类的方法和属性
上面的例子中,猫是动物。那么可以创建一个动物类。猫继承动物。前面描述了prototype的含义,那么是不是可以将猫的构造函数的prototype赋值为动物的对象。
继承方式一:
?
<script>
function Animal(typeName){
this.typeName = typeName;
}
Animal.prototype.eat = function(){
alert("吃");
};
function Cat(name,color){
this.name = name;
this.color = color;
/**
this.eat = function(){
alert("吃鱼");
}
*/
}
Cat.prototype.eat = function(){
alert("吃鱼");
}
Cat.prototype = new Animal("aa");
Cat.prototype.constructor = Cat;
var cat1 = new Cat("小明","黑色");
cat1.eat();
alert("Cat.prototype.constructor:"+Cat.prototype.constructor)
alert(cat1.typeName);
alert(cat1.name)
</script>

??
在上面可以看出一个问题,Cat.prototype.constructor指向的是Animal这就有点奇怪了,Cat明明是猫为什么会是动物呢,所以我们要重新将Cat的构造函数指向Cat。即:Cat.prototype.constructor=Cat
继承方式二:
?
?
<script>
function Animal(){
this.typeName = "动物";
}
Animal.prototype.eat = function(){
alert("吃");
};
Animal.prototype.attr = "属性"
function Cat(name,color){
this.name = name;
this.color = color;
this.eat = function(){
alert("吃鱼");
}
}
Cat.prototype = Animal.prototype;
var cat1 = new Cat("小明","黑色");
cat1.eat();
alert(cat1.typeName);
alert(cat1.attr);
var animal = new Animal();
alert("查看cat1的构造函数是谁(cat1.constructor):"+cat1.constructor);
alert("查看Cat的构造函数是谁(Cat.prototype.constructor):"+Cat.prototype.constructor);
alert("查看cat1的构造函数是谁(animal.constructor):"+animal.constructor);
alert("查看Cat的构造函数是谁(Animal.prototype.constructor):"+Animal.prototype.constructor);
Cat.prototype.constructor = Cat;
alert("查看cat1的构造函数是谁(cat1.constructor):"+cat1.constructor);
alert("查看Cat的构造函数是谁(Cat.prototype.constructor):"+Cat.prototype.constructor);
alert("查看cat1的构造函数是谁(animal.constructor):"+animal.constructor);
alert("查看Cat的构造函数是谁(Animal.prototype.constructor):"+Animal.prototype.constructor);
</script>
?查看例子:好处是可以不用创建Animal实例节约内存,坏处是Cat的原型对象和Animal的原型对象相同,对其中一个修改都会反映到另一个对象。而且Animal的构造函数不能有自己的属性和方法,不然Cat对象将继承不到这些属性
继承方式三:
?
<script>
function Animal(){
this.typeName = "动物";
}
Animal.prototype.eat = function(){
alert("吃");
};
Animal.prototype.attr = "属性"
function Cat(name,color){
this.name = name;
this.color = color;
this.eat = function(){
alert("吃鱼");
}
}
//Cat.prototype = Animal.prototype;
var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
var cat1 = new Cat("小明","黑色");
cat1.eat();
alert(cat1.typeName);
alert(cat1.attr);
var animal = new Animal();
alert("查看cat1的构造函数是谁(cat1.constructor):"+cat1.constructor);
alert("查看Cat的构造函数是谁(Cat.prototype.constructor):"+Cat.prototype.constructor);
alert("查看animal的构造函数是谁(animal.constructor):"+animal.constructor);
alert("查看Animal的构造函数是谁(Animal.prototype.constructor):"+Animal.prototype.constructor);
Cat.prototype.constructor = Cat;
alert("查看cat1的构造函数是谁(cat1.constructor):"+cat1.constructor);
alert("查看Cat的构造函数是谁(Cat.prototype.constructor):"+Cat.prototype.constructor);
alert("查看animal的构造函数是谁(animal.constructor):"+animal.constructor);
alert("查看Animal的构造函数是谁(Animal.prototype.constructor):"+Animal.prototype.constructor);
</script>
?
原文:http://zc985552943.iteye.com/blog/2258866