JavaScript之继承

继承是 OO 语言中的一个最为人津津乐道的概念。许多 OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。由于函数没有签名,在 ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的。

我们来看看JavaScript的继承。

1.原型链继承

function Person(name) {
      this.name = name || "人"
      this.sayHi = function () {
        console.log("我是" + this.name)
      }
    }
    function Teacher(name) {
      this.name = name
    }
    Teacher.prototype = new Person()
    var t1 = new Teacher("王老师")
    console.log(t1.sayHi()); //我是王老师
console.log(t1.name));  //王老师

 在这里我们可以看到,t1这个实例的原型继承了Person构造函数。

 所以,在实例t1的原型对象里,有一个name,sayHai的方法,当t1调用sayHai的方法的时候,默认会从本身自己的属性去找,若没有找到,会去原型对象上找。

 而访问name的时候,先从本身属性去找,所以会返回“王老师”,若想访问Person里的name则需要通过__proto__属性指向原型对象,再通过原型对象来访问

 如:ti.__proto__.name   //人

 但是,这样的话,通过Teacher构造函数创建出来的实例对象t1的constructor属性值就变成构造函数Person。

 这样就完成了我们的原型继承!但是要切记,原型链上的的属性值始终都是共享的。

2.借用构造函数

    function Person(name) {
      this.name = name || "人"
      this.sayHi = function () {
        console.log("我是" + this.name)
      }
    }
    Person.prototype.getName = function () {
      return this.name
    }
    function Teacher(name) {
      this.name = "1"
      Person.call(this,name)
    }
    var t1 = new Teacher("王老师")
    console.log(t1.sayHi()); //我是王老师
    console.log(t1.name);    //王老师

 

 通过使用 call()方法或 apply()方法,我们实际上是在(未来将要)新创建的Teacher实例的环境下调用了 Person构造函数。

 这样一来,就会在新 t1 对象上执行 Person()函数中定义的所有对象初始化代码。

   若觉得看不懂,可以通过百度搜索,bind(),call(),apply()的区别与使用,这里就不在一一细说。

 在这里t1实例又无法继承Person构造函数的原型里的方法。

3.组合继承

 组合继承(combination inheritance),有时候也叫做伪经典继承,指的是将原型链和借用构造函数的
    技术组合到一块,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方
    法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数
    复用,又能够保证每个实例都有它自己的属性。

 

    function Person(name) {
      this.name = name || "人"
      this.sayHi = function () {
        console.log("我是" + this.name)
      }
    }
    Person.prototype.getName = function () {
      return "我的名字叫" + this.name
    }
    function Teacher(name) {
      Person.call(this,name)
    }
    Teacher.prototype = new Person()
    Teacher.prototype.constructor = Teacher
    Teacher.prototype.alertName = function () {
      alert(this.name)
    }
    var t1 = new Teacher("王老师")
    var t2 = new Teacher("张老师")
    console.log(t1.sayHi()); //我是王老师
    console.log(t1.name);    //王老师
    console.log(t1.getName());  //我的名字叫王老师
    console.log(t1.alertName());  //王老师
    t1.getName = function () {
      return "别人叫我" + this.name
    }
    console.log(t2.getName());  //别人叫我张老师

 但是可以发现,实例 t1 如果重写了原型的属性或者方法,通过 Teacher构造函数创建的 t2实例对象,他的原型属性或方法也会跟着改变。

 

4.寄生式继承

  寄生式(parasitic)继承是与原型式继承紧密相关的一种思路,并且同样也是由克罗克福德推而广之的。
  寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该
  函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象。

 

    function createAnother(obj) {
      var clone = Object(obj)
      clone.sayHai = function () {
        alert(this.name)
      }
      return clone;
    }
    var person = {
      name: "张三",age: 19
    }
    var clonePerson = createAnother(person)
    clonePerson.sayHai()  //张三

 

5.寄生组合继承

  寄生组合式继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,
  我们所需要的无非就是超类型原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型。
 

 

    function inheritPrototype(Teacher,Person) {
      var prototype = Object(Person.prototype)
      prototype.constructor = Teacher
      Teacher.prototype = prototype
    }
    function Person(name) {
      this.name = name
      this.age = 18
    }
    Person.prototype.sayHai = function () {
      alert(this.name)
    }
    function Teacher(name) {
      Person.call(this.name)
      this.sex = "男"
    }
    inheritPrototype(Teacher,Person)
    Teacher.prototype.sayAge = function () {
      alert(this.age)
    }

  

  这个例子的高效率体现在它只调用了一次Person构造函数,并且因此避免了在 Teacher.prototype 上面创建不必要的、多余的属性。
  与此同时,原型链还能保持不变;因此,还能够正常使用instanceof 和 isPrototypeOf()。开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)