js OOP编程

今天来总结下关于JavaScript的面向对象编程!

<h1>一、封装</h1>
<h2>/*1. 生成对象的原始模式*/</h2>var Cat = {
	name:'',
	color:''
}

//根据这个原型对象的规格,生成2个实例对象。

var cat1 = {};
cat1.name = "大毛";
cat1.color = "黄色";

var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";

//缺点:1.代码冗余 2.实例之间看不出联系,它们属于object


<h2>/*2. 原始模式改进(工厂模式)*/</h2>function Cat(name,color){
	return {
		name:name,
		color:color
	}
}

//使用:
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");

//缺点:1.实例之间看不出联系,它们属于object


<h2>/*3. 构造函数模式*/</h2>function Cat(name,color){
	this.name = name;
	this.color = color;
}

//使用:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");

//这时,cat1和cat2会自动包含一个constructor属性,指向它们的构造函数

alert(cat1.constructor == Cat);//true
alert(cat2.constructor == Cat);//true

alert(cat1 instanceof Cat);//true
alert(cat2 instanceof Cat);//true

//缺点:浪费内存


<h2>/*4. 构造函数模式的问题和Prototype模式*/</h2>
function Cat(name,color){
	this.name = name;
	this.color = color;
	this.type = "猫科动物";
	this.eat = function(){
		alert("吃老鼠");
	}
}

//使用:
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");

//实际上这样做是十分浪费内存的,因为type属性和eat方法是所有Cat类都应该有的,
//没有必要每次实例化的时候都为这两个属性分配空间。
//从这里可以看出为它们另外分配了空间:
alert(cat1.type == cat2.type);//false
alert(cat1.eat == cat2.eat);//false


//下面用prototype模式可以解决这个问题
//javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。
//这个对象的所有属性和方法,都会被构造函数的实例继承。

//这样,我们就可以将那此不变的属性和方法,直接定义在prototype对象中。
function Cat(name,color){
	this.name = name;
	this.color = color;
}

Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){
	alert("吃老鼠");
}

//prototype对象是一个类所有实例公用的,可以以此来验证:
alert(cat1.type == cat2.type);//true
alert(cat1.eat == cat2.eat);//true
//指向同一空间


<h2>/*5. prototype模式的验证方法*/</h2>
<h3>1).isPrototypeOf()</h3>//用来判断,某个prototype对象和某个实例之间的关系。
alert(Cat.prototype.isPrototypeOf(cat1));//true
alert(Cat.prototype.isPrototypeOf(cat2));//true

<h3>2).hasOwnProperty()</h3>//用来判断,一个属性是不是本地属性
alert(cat1.hasOwnProperty("name"));//true
alert(cat1.hasOwnProperty("type"));//false
//type属性是继承自prototype对象的属性,不是本地属性,所以为false

<h3>3).in运算符</h3>//用来判断,某个实例是否含有某个属性,不管是不是本地属性。
alert("name" in cat1);//true
alert("type" in cat1);//true

//in运算符还可以用来,遍历某个对象的所有属性。
for(var prop in cat1){
	alert(cat1[prop]);
}



<h1>二、继承</h1>
<h2>/*1.“构造函数”继承*/</h2>
function Animal(){
	this.species = '动物';
}

function Cat(name,color){
	this.name = name;
	this.color = color;
}

//问题:怎样才能让“猫”继承“动物”呢?

<h3>/*1). 构造函数绑定*/</h3>function Cat(name,color){
	Animal.apply(this,arguments);//实际上是调用了父类的构造函数
	this.name = name;
	this.color = color;
}

<h3>/*2). prototype模式*/</h3>Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;

<h3>/*3). 直接继承prototype*/</h3>//这种方法是对第二种方法的改进,由于Animal对象中,
//不变的属性都可以直接写入Animal.prototype,所以我们也可以让Cat()跳过Animal(),
//直接继承Animal.prototype

//改写Animal对象:
function Animal(){}
Animal.prototype.species = '动物';

//开始继承:
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;

//与前一种方法相比,这样做的优点是效率高(不用建立Animal实例),比较节省内存
//缺点:Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对
//Cat.prototype的修改,都会反映到Animal.prototype中,这并不是我们想要的


<h3>/*4). 利用空对象作为中介*/</h3>//正因为存在上述的缺点,所以才有了第四种继承方式,利用一个空对象作为中介实现继承。
var F = function(){}
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;

//F是空对象,所以几乎不占用内存。

//为了使用的方便,将其封装一下:
function extend(Child, Parent) {
	var F = function(){};
	F.prototype = Parent.prototype;
	Child.prototype = new F();
	Child.prototype.constructor = Child;
	Child.uber = Parent.prototype;//主要是用来做扩展的
}


<h3>/*5). 拷贝继承*/</h3>//对于父类,还是将它所有不变的属性放到它的prototype对象中。
function Animal(){}
Animal.prototype.species = '动物';

function extend2(Child, Parent){
	var p = Parent.prototype;
	var c = Child.prototype;
	for(var i in p){
		 c[i] = p[i];
	}
	c.uber = p;<span style="font-family: Arial, Helvetica, sans-serif;">//  用于功能扩展</span>
}


<h2>/*2.“非构造函数”继承*/</h2>
var Chinese = {
	nation:'中国'
};

var Doctor = {
	career:'医生'
}

//怎样让“医生”去继承“中国人”,从而得到一个中国医生对象?
//注:这里的两个对象都是普通对象,而不是构造函数,无法使用构造函数方法实现继承。


<h3>/*1). object()方法*/</h3>function object(o){
	function F() {}
	F.prototype = o;
	return new F();
}


<h3>/*2). 浅拷贝方法*/</h3>function extendCopy(p){
	var c = {};
	for(var i in p){
		c[i] = p[i];
	}
	c.uber = p;// 用于功能扩展
	return c;
}


<h3>/*3). 深拷贝方法*/</h3>function deepCopy(p,c){
	var c = c||{};
	for(var i in p){
		if(typeof p[i] === 'object'){
			c[i] = (p[i].constructor === Array) ? [] : {};
				deepCopy(p[i],c[i]);
			} else {
				c[i] = p[i];
			}
		}
	}
	return c;
}



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。