Js中面向对象的三大特点:封装、继承、多态
前言:面向对象、对象、构造函数、原型对象、原型链
- 面向对象:程序中,都是先用对象结构,集中保存一个事物的属性和功能,然后再按需使用事物的属性和功能,这种编程思想就是面向对象。
- 对象:程序中,集中存储一个事物属性和功能的程序结构/存储空间。
- 构造函数:专门描述同一类型的所有对象的相同结构的函数。
- 原型对象:该类型下所有子对象集中保存共有成员方法或属性的一个父级对象。
- 原型链:由多级父对象逐级继承形成的链式结构。
一.封装(创建对象)
- 用{}创建一个对象:
var 对象名={
属性名1:属性值1,
属性名2:属性值2,
...:...,
方法名1:function(){
...this.属性名...
}
方法名2:function(){
...this.属性名...
}
}
适用于在创建对象时,已经知道对象的成员内容
- 用new Object() 创建
(1).先创建一个空对象:
var 对象名=new Object()
其中 new Object() 可以简写为{}
即:var 对象名={};
(2). 向空对象中强行添加新属性和方法
对象名.属性=值
对象名.方法名=function(){
...this.属性名...
}
适用于创建对象时暂时不知道对象中的成员,就可以先创建空对象,稍后得知对象的成员内容后,
再强行添加进对象中。
- 用构造函数反复创建多个相同结构的对象
以上两种方式,一次只能创建一个对象,如果反复创建多个相同结构的对象是,重复代码会极其多。
反复创建同一类型的相同结构的多个对象时,都要用构造函数
(1).定义构造函数
function 类型名(形参列表){
this.属性名=形参1;
this.属性名=形参2;
this.方法名=function(){
...this.属性名...
}
}
(2)使用new关键字调用构造函数创建对象
var 对象名=new 构造函数名(实参列表)
二.继承
继承:父对象的成员,子对象无需重复创建,就可直接使用。
构造函数虽然可以重用代码,但是却浪费了内存,定义在构造函数中的方法,每创建一个对象,都会执行一次function,都会创建该方法的一个完全相同的副本给每个新创建的对象。要实现多个子对象使用公共的方法,不要在构造函数中定义公共方法,而应该通过继承实现多个子对象使用公共的方法。
- Js中的继承都是通过继承原型对象实现的
- 原型对象无需自己创建,当定义构造函数时,就附赠了一个空的原型对象—构造函数.prototype。
- 当使用new调用构造函数创建子对象时,new的第2步设置了当前新创建的子对象继承构造函数的原型对象(Js中使用new关键字调用构造函数实例化对象时new的作用)
i. 每个对象上都有一个__proto__属性,用来标记当前对象的父对象是谁
ii. new的第二步将当前新对象的__proto__属性指向当前构造函数的原型对象
结果:父对象(构造函数的原型对象)中的成员无需重复创建,就可直接使用。 - 原型链保存着一个对象可用的所有属性和方法,控制着属性和方法的使用顺序:先使用自有属性和方法,自己没有才沿原型链向父级查找。
三.多态
多态:一个函数,不同情况下表现出不同的状态。
- 重写(override):在子对象中定义和父对象中同名的成员,结果:再使用这个成员时,总是优先使用子对象自己的同名属性,而永久屏蔽了父对象中的同名属性。当从父对象继承来的成员不好用时,都可在子对象内部定义同名的新成员,覆盖从父对象继承的同名成员。建议所有自定义类型和自定义对象中最好都要提供toString()来输出对象的内容,避免继承的toString()造成影响。
- 自定义继承:
(1). 如果子对象觉得现在的父对象不好,可以更换整个父对象
(2). 三种方法:
i. 只修改一个子对象的父对象:其实就是修改子对象的__proto__属性指向新的父对象即可。
子对象 .
__proto__=新父对象
问题:__proto__有的浏览器不让用
所以:Object.setPrototypeOf(子对象,新父对象)代替__proto__
ii. 更换该类型下所有子对象的父对象:其实就是更换构造函数的原型对象:构造函数.prototype=新原型对象
注意:应该在创建子对象之前更换,这样新创建的子对象才能自动继承新的原型对象,在创建子对象之后更换,虽然构造函数的原型对象发生改变,已经创建的子对象仍然继承旧的原型对象。