面向对象(ES5与ES6类的继承解析)

面向对象的语言都有一个类的概念,通过类可以创建多个具有相同方法和属性的对象,ES6之前并没有类的概念,在ES6中引入类class.

ES5 面向对象

创建对象(四种模式简介,此外还有动态原型模式、寄生构造函数模式、稳妥构造函数模式等)

一、工厂模式


function createPerson (Name,Age,Job) {

      var man= new Object();

      man.name= Name;

      man.age= Age;

      man.job= Job;

      man.sayName= function () {

              alert(this.name)

    }

  return  man;

}

var personOne=  createPerson ("Erric",26,"Engineer");

var personTwo=  createPerson ("Lori",26,"teacher");

优点:解决了多个相似对象的创建问题

缺点: ①  对象识别问题无法解决(即怎么知道一个对象的类型)

二、构造函数模式

function Person (Name,Age,Job) {

      this.name = Name;

      this.age = Age;

      this.job= Job;

      this.sayName= function () {

              alert(this.name)

      }

}

var personOne=  new Person("Erric",26,"Engineer");

var personTwo=  new Person("Lori",26,"teacher");

注一: 若不使用new操作符直接调用函数,那么其属性和方法都会被添加到window对象里面(因为在全局作用域调用一个方法时,this总是指向window对象)

如: Person("Erric",26,"Enginee")

        window.sayName()  //  弹出 "Erric"

          window.name            //  "Erric"

          window.age              //  26

注二: new 操作符实际上进行了以下操作

          ① 创建一个新的对象

          ② 将构造函数的作用域赋给新对象(this指向了这个新的对象)

          ③ 执行构造函数中的代码(为这个新对象添加属性)

          ④ 返回这个新的对象

优点:① 不用显式的创建对象

            ② 将属性和方法赋给了this对象

            ③ 没有return语句

缺点:①  每个方法都要在每个实例上重新创建一遍(personOne和personTwo中的sayName方法不是同一个方法,每个函数都是一个对象,故每  定义了一个函数就实例化了一个对象)。

            此问题也可以通过将方法单独抽出来解决(但是方法一多,都移到全局的话封装性就无从谈起),如下:

            function Person (Name,Age,Job) {

                    this.name = Name;

                      this.age = Age;

                      this.job= Job;

                      this.sayName= sayName

            }

            function sayName() {

                    alert(this.name)

              }

            var personOne=  new Person("Erric",26,"Engineer");

            var personTwo=  new Person("Lori",26,"teacher");

            ② 若是将公共的sayName方法移到全局,那么又没有封装性可言了。



三、原型模式

function Person () {

}

Person.prototype.name= "Erric"

Person.prototype.age= "28"

Person.prototype.job= "Job"

Person.prototype.sayName= function () {

        alert(this.sayName)

}

优点:①  解决了函数共用的问题,不用每个实例都创建一遍方法。

缺点:①  不能传参

            ② 如果实例中修改了原型中的属性(引用类型)或方法,那么这个属性或方法会被彻底的修改,而影响到其他实例。



四、构造函数+原型组合模式

function Person (Name,Age,Job) {

          this.name= Name

          this.age= Age

          this.job= Job

}

Person.prototype.sayName= function () {

          alert(this.name)

}

// 上面往原型上添加属性和方法的也可如下写,但是此时原型的constructor不指向Person构造函数,而是指向Object,因为Person.prototype就像一个新的对象实例,它的__proto__指向Object原型。

//  Person.prototype= {

          constructor: Person,            // 重新再实例中定义constructor的指向,覆盖Object原型中的constructor指向

          sayName: function () {

                  alert(this.name)

          }

}

var personOne=  new Person("Erric",26,"Engineer");

var personTwo=  new Person("Lori",26,"teacher");


原型对象的理解(重要)

1.首先得明白以下三点:

① 每个函数(含构造函数)都有一个prototype属性,指向Person原型

② 每个实例都有一个__proto__属性,也指向Person原型

③ 每个原型都有一个constructor属性,指向其对应的构造函数

构造函数、实例、原型三者关系如下图:

2.万物皆对象,说明原型链的最开始点都是Object,所以任何一个引用类型的 instanceof Object都会返回true。


类的继承(两种方式)

一、原型链继承

        对于什么是原型链?

        每个构造函数都有一个原型对象,原型对象的constructor指向这个构造函数本身,而实例的__proto__属性又指向原型对象。这个假设一个实例的__proto__内部指针指向其原型,而它的原型又是另一个类型的实例,那么它的原型又将指向另一个原型,另一个原型也包含一个指向它的构造函数的指针,假设另一个原型又是另一个类型的实例,这样层层递进,就构成了实例与原型的链条,这就是原型链的基本概念。

实现原型链的继承方式基本如下:

function Father () {

      this.appearance = "beautiful"

}

Father.prototype.sayHappy = function () {

        alert("快乐")

}

function Child () {

          this.name= "Jhon"

}

Child.prototype= new Father()        //  继承了父类的方法和属性

Child.prototype.addArr= [1,2,3,4,5]

var child= new Child()
child.sayHappy()          //  弹出“快乐”
child.appearance        //  "beautiful"

child.addArr                      //  [1,2,3,4,5]

原型链继承的缺点:①  不能传参  ② 若原型上的方法时引用类型的话,不小心被修改了的话会影响其他实例。


二、借助构造函数继承(利用calll和apply改变this指针)

基本思路:在子类型构造函数的内部调用超类型的构造函数。

function Father (Hobby){

      this.hobby= Hobby

}

Father.prototype.sayHappy = function () {

      alert("快乐")

}

function Child () {

      this.name= "Jhon"

      Father.call(this,"Play Games")          //  或者Father.apply(this,["Play Games"]),继承了Father的属性和方法

}

var child =  new Child()
child.sayHappy                // 没有反应,原型上的方法和属性不会继承
child.hobby                      //  "Play Games"

借助构造函数继承的缺点:①  方法都在构造函数中定义,函数的复用无从谈起    ②  超类中的方法对子类不可见。


三、组合继承(也叫经典继承,将原型链和借助构造函数继承相结合)

思路:1.原型链实现对原型属性和方法的继承;

            2.构造函数实现对实例属性的继承,且调用基类的构造函数;

function Father(Hobby) {

          this.hobby= Hobby;

          this.exGF = ['cuihua', 'erya']

}

Father.prototype.sayHappy = function () {

          alert("快乐")

}

function Child () {

          this.name= "Jhon"

          Father.call(this,"Play Games")          //  或者Father.apply(this,["Play Games"]),继承了Father的属性和方法

}

Child.prototype= new Father()

Child.prototype.sayName= function () {

          alert(this.name);

}

var liHua= new Child()

liHua.sayHappy()

liHua.sayName()


检测对象属性的两种方法:

object.hasOwnProperty(属性名),这个方法检测的是对象实例的属性(若是返回true),不能检测原型上的属性。

in操作符,检测对象所有的属性,包含原型和实例上的额,有的话就返回true.


判断一个原型是否在某个实例的原型链上:

Person.prototype.isPropotypeOf(personOne)    //  true

Object.prototype.isPropotypeOf(personOne)      //  true

判断一个构造函数是否在实例的原型链中出现过:

personOne instanceof Person                //  true

personOne instanceof Object                //  true


ES6 面向对象

ES6中引入了Class(类)这个概念,通过关键字class可以创建一个类。类的数据类型就是函数,类的所有方法都定义在prototype属性上。

class Person () {
        constructor (x,y) {
              this.name= x
              this.age= y
        }
        sayName () {
                alert("快乐")
        }
}
var liHua= new Person("张俊泽",26)

注: 可以理解为constuctor中的属性和方法为ES5中的构造函数部分,和constructor同级的是ES5中原型上的方法和属性。


ES6的继承通过extends关键字实现

class Father(){}
class Child extends Father {
        constructor(x,y,color){
                  super(x,y)
                  this.color= color
        }
        toString() {
                retunr "世界和平!"
        }
}

上面代码中,constructor方法和toString方法之中,都出现了super关键字,它在这里表示父类的构造函数,用来新建父类的this对象。

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。


类的prototype和__proto__属性

Class作为构造函数的语法唐,同时有prototype和__proto__属性,因此存在两条继承链:

①  子类的__proto__,表示构造函数的继承,总是指向父类

②  子类的prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class Father {

}

class Child extends Father{

          constructor () {

                  super()

          }

}

var childOne= new Child()

Child.__proto__ ==  Father        //  true

childOne.__proto__ ==  Child.prototype        //  true

Child.prototype.__proto__ ==  Fahter.prototype            //  true

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容