JS面向对象三大特点封装、继承、多态

20 阅读5分钟

@TOC

1.封装

定义:创建一个对象,集中存储一个事物的属性和功能。 为什么:便于维护。 何时:只要使用面向对象,都要先创建对象,再按调用对象的方法执行操作。 如何创建:3种

1.用对象直接量
var obj = { 
	属性名1:属性值1,
	属性名2:属性值2,
	方法名:function(){
		...this.属性名...
	}
}

对象自己的方法 ,访问自己的属性如果不加this,仅会在作用域中查找,不会在对象中查找。 要访问自己的属性:this.属性名 this.属性在当前对象和当前对象的原型链中查找

var obj = {
	name:"Monica",
	age:21,
	description:function(){
		console.log(`${this.name}今年${this.age}了`)
		//Monica今年21了
	}
};
2.用new
var obj = new Object();  //new 可省略   ()也可省略  但不能同时省略
//为对象添加属性
obj.属性名1 = 值1;
obj.属性名1 = 值2;
obj.方法名 = 函数
var obj = new Object();  //new 可省略   ()也可省略  但不能同时省略
//为对象添加属性
obj.name = "Monica";
obj.age = 21
obj.description=function(){
	console.log(`${this.name}今年${this.age}了`)
	//Monica今年21了
}
obj.sex     //访问不存在的属性  undefinded
obj.sex = "1" //强行给不存在的属性赋值   自动添加该属性到对象  不报错
obj.description()
for(var key in obj){
	key     //当前属性名
	obj[key]//当前属性值
}

JS中一切对象底层都是关联数组

obj["属性名"]=obj.属性名
//如果属性名是通过变量动态获得只能写obj[变量]  不加""	

问题:反复创建多个相同结构的对象时,会造成大量重复的代码。 解决:用构造函数反复创建多个相同结构的对象。

构造函数创建 定义:规定一类对象统一结构函数。 何时:反复创建多个相同结构的对象。 作用:描述统一的结构,将空对象构建成要求的结构。 如何:2种。 下面展示一些 内联代码片

1.定义构造函数
function 类型名(属性参数...){
	this.属性名=属性参数;
	this.方法名=function(){
		this.属性名
	}//JS种不建议将方法定义在构造函数中
	//将来对象中有几个属性就要定义几个this.属性,同时也要定义相同数量的属性形参
}
2.new调用构造函数
var obj = new 类型名(属性值...)
new //1.创建一个新的空对象
        //2.设置子对象的__proto__继承构造函数的prototype对象
        //3.调用构造函数,将构造函数中的this自动替换为当前新对象obj
        //4.返回新对象的地址保存到变量中
function obj1(name,age){
	this.name = name;
	this.age = age;
}
var obj2 = new obj1("Monica",21)
obj2.name //"Monica"
obj2.age  //21

优点:代码重用。 缺点:无法节约内存,放在构造函数中每new一次都会创建函数对象副本 解决:继承

2.继承

定义:父对象中的成员,子对象无需重复创建,就可直接使用。 何时:只要多个子对象拥有相同的属性值或方法值时,仅需要集中定义在父对象中一份,所有子对象公用即可。 为什么:代码重用,节约内存。 如何:JS中的继承都是继承原型对象。

原型对象 什么是:集中保存同一类型的所有子对象共有成员的父对象。 何时:只要多个子对象,拥有相同的成员时,都要将相同的成员集中保存在原型对象中一份即可。 如何:在定义构造函数同时,已经自动创建了该类型的原型对象。 构造函数.prototype指向原型对象。 原型对象.consructor指回构造函数。

继承方式6种 定义父类

function person(name,food){
	this.name=name;
	this.food=food;
	this.sleep=function(){
		console.log(`${this.name}睡着了`)
	}
}
person.prototype.eat=function(food){
	console.log(`${this.name}在吃${food}`)
}
1.原型链继承
function man(){
	
}
man.prototype=new person();
man.prototype.name="张三"
var men=new man()
console.log(men.name) //张三
men.eat("鸡蛋")//张三在吃鸡蛋
men.sleep()//张三睡着了
console.log(man instanceof person) //true
console.log(men instanceof man)    //true

特点:

1.实例是子类的实例,也是父类的实例 2.父类新增的方法,子类都可以访问。

缺点:

1.无法继承多个 2.创建子类实例时,无法向构造函数传参。

2.构造继承
function woman(name){
	person.call(this);
	this.name=name||"李四"
}
var women=new woman()
console.log(women.name) //李四
women.eat("鸡蛋")// not a function
women.sleep()//李四睡着了
console.log(women instanceof person) //false
console.log(women instanceof woman)    //true

特点: 1.创建子类实例时可以向父类传递参数。 2.可以实现多继承(call对个父类对象)。 缺点: 1.实例并不是父类的实例,只是子类的实例。 2.只能继承父类的属性和方法,不能继承原型的属性和方法。 3.无法实现复用,每个子类都有父类的副本。

3.实例继承
function children(name){
	var temp=new person()
	temp.name=name||"王五"
	return temp
}
var child=new children();
console.log(child.name) //王五
child.sleep()//王五睡着了

特点:不限制调用方式,new跟直接调用返回的结果一样。 缺点:是父类实例,非子类实例。不支持多继承。

4.拷贝继承
function Animal(){
	var temp=new person()
	for(let i in temp){
		Animal.prototype[i]=temp[i]
	}
	Animal.prototype.name=name||"兔子"
}
var animal=new Animal()
console.log(animal.name)  //兔子
animal.sleep()//兔子睡着了

特点:支持多继承 缺点:效率极低,占内存,无法继承for in 取不到的方法

5.组合继承
function man(name){
	person.call(this);
	this.name=name||"张三"
}
man.prototype=new person();
man.prototype.comstructor=man
var men=new man();//可传参数进去
console.log(man.name)//张三
men.sleep()//张三睡着了
men.eat("鸡蛋")

特点:可以继承实例属性和方法,也可以继承原型属性和方法 既是子类实例又是父类实例 函数可复用、可传参 缺点:调用了两次构造函数

6.寄生组合继承
function man(name){
	person.call(this);
	this.name=name||"张三"
}
(function(){
	var temp=function(){
		temp.prototype=person.prototype;
		man.prototype=new temp()
	}
})()
var men=new man()
console.log(men.name)//张三
men.sleep()//张三睡着了
men.eat("鸡蛋")//张三在吃鸡蛋

特点:没有缺点

3.多态

同一个方法,在不同情况下表现出不同状态 重写:可定义同名自有成员覆盖父对象中的 成员。