JS面向对象三大特点封装、继承、多态
- 1.封装
- 2.继承
- 3.多态
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.多态
同一个方法,在不同情况下表现出不同状态
重写:可定义同名自有成员覆盖父对象中的 成员。