面向过程、面向对象及面向对象编程
面向过程(Procedure Oriented
) :分析解决问题所需要的步骤,然后按照顺序一步一步调用不同的函数。例如:开(冰箱) -> (大象)装进冰箱 -> 关(冰箱)。
面向对象(Object Oriented,OO
) :面向对象有三大特点(封装:将功能封装程一个独立、继承:代码重用、减少编码,间接减少维护成本、多态:不同场合作出不同响应),把构成问题事物分解程各个对象,建立对象目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题问题的步骤中的行为。例如:冰箱.开门() -> 冰箱.装进(大象) -> 冰箱.关门()。
面向对象编程(Object Oriented Programming,OOP
) :是一种编程开发思想,它将真实世界各种复杂的关系,抽象成一个个对象,每个对象都是功能的中心,分工明确,可以接收信息,处理数据,发出信息等任务。因此,面向对象编程具有灵活性、代码可复用、高度模块化的特点。容易维护和开发。
注意:
(1)面向过程就是亲力亲为,事无巨细,面面俱到,步步紧跟,有条不紊。
(2)面向对象就是找一个对象,将执行者变成指挥者。
(3)面向对象不是面向过程的替代,而是面向过程的封装。
构造函数的属性
1 2 3 4 5 6 7 8 9 10 11 funcion A(name) { this .name = name; this .arr = [1 ]; this .say = function ( ) { console .log('hello' ) } } 注意:数组和方法都属于‘实例引用属性’,但是数组强调私有、不共享的。方法需要复用、共享。 注意:在构造函数中,一般很少有数组形式的引用属性,大部分情况都是:基本属性 + 方法。
一、类与实例化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 function Animal1 ( ) { this .name = 'name' this .run = functionn() { console .log("跑" ) } } class Animal2 { constructor () { this .name = 'name' } } var objo = Animal1(); var obj1 = new Animal1(); let obj2 = new Animal2();
二、类与继承
2.1 借助构造函数实现继承(构造函数继承)
原理:改变函数运行时的上下文,即this的指向
优点:实现了继承属性,可以传值
缺点:实现部分继承,父类的原型对象上的方法无法继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function Parent1 ( ) { this .name = 'Parent1' ; } Parent1.proptotype.say = function ( ) { console .log(this .name); } function Child1 ( ) { Parent1.call(this ) this .name = 'Parent1' ; this .type = 'Child1' ; } console .log(new Child1, new Child1().say())
2.2 借助原型链实现继承
原理:改变子类的prototype(即其实例的__proto__)属性指向其父类的实例
优点:实现了构造函数的继承,也继承了父类原型上的方法
缺点:原型链中的原型对象是共用的,子类实例的原型对象是同一个引用,当一个实例的属性改变时,其他实例也跟着改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function Parent2 ( ) { this .name = 'Parent2' ; this .arrs = [1 , 2 ]; } function Child2 ( ) { this .type = 'Child2' ; } Child2.prototype = new Parent2(); console .log(new Child2().__proto__);var a20 = new Child2();var a21 = new Child2();a21.arrs.push(3 ) console .log(a20.arrs, a21.arrs)
2.3 组合继承(构造函数+原型链)
原理:结合构造函数和原型链方法的优点,弥补了此两种方法的不足
优点:拥有两种方法的优点,弥补以上两个缺点
缺点:多次执行父类构造函数,浪费内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Parent3 ( ) { this .name = 'Parent3' ; this .arrs = [1 , 2 ]; } Parent1.proptotype.say = function ( ) { console .log(this .name); } function Child3 ( ) { Parent3.call(this ) this .type = 'Child3' ; } Child3.prototype = new Parent3(); var a30 = new Child3();var a31 = new Child3();p30.say(); a30.arrs.push(3 ) console .log(a30.arrs, a31.arrs)
2.4 组合继承优化1(构造函数+原型链)
原理:子类原型直接引用父类的原型
优点:不需要多次执行父类构造函数
缺点:不知道实例是由谁创造的(以上方法都存在)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Parent4 ( ) { this .name = 'Parent4' ; this .arrs = [1 , 2 ]; } function Child4 ( ) { Parent4.call(this ) this .type = 'Child4' ; } Child4.prototype = Parent4.prototype; var a40 = new Child4();var a41 = new Child4();a40.arrs.push(3 ) console .log(a40.arrs, a41.arrs) console .log(a40 instanceof Child4, a41 instanceof Parent4) console .log(a41.constructor)
2.5 组合继承优化2(寄生组合继承)
原理:利用Object.create()函数创建的对象,子类与父类的原型对象进行隔离,覆盖constructor
优点:不需要多次执行父类构造函数,且知道是由谁创造的实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Parent5 ( ) { this .name = 'Parent5' ; this .arrs = [1 , 2 ]; } function Child5 ( ) { Parent5.call(this ); this .type = 'Child5' ; } Child5.prototype = Object .create(Parent5.prototype) Child5.prototype.constructor = Child5; var a5 = new Child5();console .log(a5 instanceof Child5, a5 instanceof Parent5) console .log(a5.constructor)
2.6 ES6 Class extends
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class A { constructor () { this .color = '#FFF' ; this .arrs = [1 , 2 , 3 ] } say(word) { console .log(word); } } class B extends A { constructor () { super (); this .color = '#FF4' } } let a1 = new B(); let a2 = new B(); a1.arrs.push(9 ); a1.say('hello' ); console .log(a1.arrs, a2.arrs)
原理: 创建了父类A,然后B子类继承父类,两个类中都有一个constructor
构造方法,实质就是构造函数 A
和 B
。
在子类的构造方法中调用了 super
方法,它表示父类的构造函数,用来新建父类的this
对象。
注意:子类必须 constructor
方法中调用 super
方法,否则新建实例时会报错。
这是因为子类没有自己的 this
对象,而是继承父类的 this
对象,然后对其进行加工。
如果不调用 super
方法,子类就得不到 this
对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class A {}class B {}Object .setPrototypeOf = function (obj, proto ) { obj.__proto__ = proto; return obj; } Object .setPrototypeOf(B.prototype, A.prototype);Object .setPrototypeOf(B, A);