- 
(一)面向对象
 面向对象是一种程序的设计思想,与之相对的编程思想叫面向过程
- 举个例子感受一下:比如我们想用代码描述一个这样的场景,有一只叫做XiaoA的猫,吃了一个苹果,又吃了一条鱼,然后有一只叫做xiaoB的猫,吃了一根香蕉
 
//面向过程编程function xiaoAEatApple(){}function xiaoAEatFish(){}function xiaoBEatBanana(){}xiaoAEatApple();xiaoAEatFish();xiaoBEatBanana();
//面向对象编程function Cat(name){this.name = name;}Cat.prototype.eat = function(somthing) {}var xiaoA = new Cat('xiaoA');var xiaoB = new Cat('xiaoB');xiaoA.eat('apple');xiaoA.eat('fish');xiaoB.eat('banana');
- 面向对象的特点
- 面向对象注重于抽象事物,而面向过程注重于叙述事物
 - JS通过函数和原型,模拟了传统面向对象编程中的类的概念,实现了面向对象的编程模式
 - 面向对象的编程思想,主要为了实现 3 件事:封装、继承、多态
 
 
封装
var catA = {name: 'xiaoA',eat: function(){console.log('xiaoA eat something');}}var catB = {name: 'xiaoB',eat: function(){console.log('xiaoB eat something');}}var catC = {name: 'xiaoC',eat: function(){console.log('xiaoC eat something');}}//封装//使用工厂模式进行封装function CreateCat(name){var obj = {};obj.name = name;obj.eat = function(){console.log(name + ' eat something');}return obj;}var xiaoA = CreateCat('xiaoA');var xiaoB = CreateCat('xiaoB');var xiaoC = CreateCat('xiaoC');//使用面向对象进行封装function CreateCat(name){this.name = name;this.eat = function(){console.log(this.name + 'eat something');}}var xiaoA = new CreatCat('xiaoA');var xiaoB = new CreatCat('xiaoB');var xiaoC = new CreatCat('xiaoC');/*new 做了啥1. 创建一个空对象2. 把构造函数的prototype赋值给新对象的__proto__3. 把构造函数的this,指向新对象4. 把构造函数的代码,执行一遍5. 把新对象返回*//*如 var xiaoA = new CreatCat('xiaoA') -->{__proto__: CreateCat.prototype,name: 'xiaoA',eat: function() {console.log(this.name + 'eat something')},}*/
继承
//继承/** new 做了哪些操作* 1.创建一个空对象* 2.将构造函数的prototype属性赋值给新对象的__proto__* 3.将构造函数的this指向新对象* 4.执行构造函数的代码* 5.将新对象返回*///在声明函数的时候,会自动创建一个prototype属性,我们管他叫函数原型对象,一般用来存放实例公用的方法function CreateCat(name){this.name = name;}CreateCat.prototype.eat = function(something){console.log(this.name + ' eat ' + something);}var catA = new CreateCat('xiaoA');// catA.eat('fish');console.log(catA);console.log(CreateCat.prototype);/*CreateCat.prototype = new Object() -> {__proto__: Object,constructor: CreateCat(){...},eat: function(something){...}}catA = {__proto__: CreateCat.prototype,name: 'xiaoA'}*/// 在js里规定,访问对象的属性和方法时,如果对象下没有这个属性或方法,则沿着他的__proto__一直往上找,直到尽头// 一、类式继承function A(name) {this.name = name;this.list = [1,2,3];}A.prototype.getName = function(){console.log(this.name);}function SubA(){this.subName = 'sub' + this.name;}//类式继承一波,注意这里莫得参数,导致undefinedSubA.prototype = new A();var one = new SubA('one');console.log(one);console.log(SubA.prototype);/*SubA.prototype = new A() -> {__proto__: A.prototype,name: undefined,list: [1,2,3]}new SubA('one') -> {__proto__: SubA.prototype,subName: 'subundefined'}//类式继承的问题//1.这种方法不支持父构造函数带参数//2.父构造函数中的属性和方法都变成共有属性*/// 二、构造函数继承function A(name) {this.name = name;this.list = [1,2,3];}A.prototype.getName = function(){console.log(this.name);}function SubA(name){//构造函数继承一波A.call(this, name);this.subName = 'sub' + this.name;}let s1 = new SubA('one');console.log(s1.name, s1.subName);console.log(s1);s1.getName(); //报错/*new SubA('one'): -> {__proto__: SubA.prototype,name: 'one',list:[1,2,3],subName: 'subone'}//构造函数的问题:不能继承父构造函数的原型方法*///三、组合式继承:类式继承+构造函数继承function A(name) {this.name = name;this.list = [1,2,3];}A.prototype.getName = function(){console.log(this.name);}function SubA(name){//关键一A.call(this, name);this.subName = 'sub' + this.name;}//关键二SubA.prototype = new A();let one = new SubA('xiaoA');console.log(one);one.getName();/*SubA.prototype = new A(): ->{name: undefined,list: [1,2,3],__proto__: {getName: fn}}new SubA("xiaoA"): -> {name: 'xiaoA',list: [1,2,3],subName: 'sub xiaoA',__proto__: {name: undefined,list: [1,2,3],__proto__: {getName: fn}}}//组合式继承的小问题//1. __proto__里面的属性没有用//2.执行了两次父构造函数*///四、寄生组合式继承function A(name) {this.name = name;this.list = [1,2,3];}A.prototype.getName = function(){console.log(this.name);}function SubA(name){//关键一A.call(this, name);this.subName = 'sub' + this.name;}//关键二:直接new太暴力了// SubA.prototype = new A();//换这个方式function inheritPrototype(subClass, superClass) {function F(){}F.prototype = superClass.prototype;subClass.prototype = new F();// subClass.prototype.constructor = subClass;}inheritPrototype(SubA, A);let one = new SubA('xiaoA');console.log(one);one.getName();/*new SubA('xiaoA') --> {__proto__: new F(),name: 'xiaoA',list: [1,2,3],subName: 'subXiaoA'}new F() --> {__proto__: superClass.prototype(A.prototype)}*/
多态
//多态: 表示不同对象调用相同方法。会产生不同的结果function Base(){}Base.prototype.initial = function(){this.init();}function SubA(){this.init = function(){console.log('SubA');}}function SubB(){this.init = function(){console.log('SubB');}}SubA.prototype = new Base();SubB.prototype = new Base();/*SubA.prototype = new Base() -->{__proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubA } },init: function(){ console.log('SubA')}}同理SubB.prototype = new Base() -->{__proto__: Base.prototype = { initial: function() { this.init(); // new的时候,this指向SubB } },init: function(){ console.log('SubB')}}所以SubA和SubB调用initial会有不同的结果*/var subA = new SubA();var subB = new SubB();subA.initial();subB.initial();
