JavaScript面向对象编程

JavaScript面向对象编程

面向对象编程主要涵盖:封装、继承、多态

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>

 

  • 大小: 39.4 KB
  • 大小: 55 KB
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值