首页 > 编程 > JavaScript > 正文

js继承的这6种方式!(上)

2019-11-19 11:43:49
字体:
来源:转载
供稿:网友

写在前面

继承的简介

继承”是JavaScript面向对象设计的重要一环,愿你认真读完本文,吃透继承的概念。

继承的核心

1. 继承方式一:原型链

1.1 介绍

原型链是实现继承最原始的模式,即通过prototype属性实现继承。

//父级-构造函数function Father() { this.fatherProp = true}//父级-原型属性Father.prototype.getFatherValue = function() { return this.fatherProp}//子级-构造函数function Son() { this.sonProp = false}//子级-原型属性:继承父级//即__proto__指向父级的prototype//若不理解请阅读《一张图彻底KO原型链(prototype,__proto__》Son.prototype = new Father()//子级-添加原型方法Son.prototype.getSonValue = function() { return this.sonProp}//创建子级的实例对象var son = new Son()console.log(son.getFatherValue()) //true

1.2 解析:son实例对象是如何找到getFatherValue()方法的呢?

  1. 首先在son对象自身中找。若对象自身没找到
  2. 然后在Son.prototype中找。若Son.prototype中没找到
  3. 继续往上一层,Son.prototype.__proto__(Fater.prototype)
  4. 依次类推,直到找到需要的属性或方法,或到达原型链顶端Object.prototype

如果到最后都没找到,会发生什么呢?

//一个不存在的方法console.log(son.getValue()) //ERROE:not a function

1.3 注意事项

重写父级原型链的方法或者添加父级原型链不存在的方法,必须在父级原型链代码之后。(这个很好理解,不放代码演示了)

通过原型链实现继承后,不能再使用字面量的方式创建原型对象,因为会覆盖原型链。

//子级-原型属性:继承父级Son.prototype = new Father()//不能像下面这样,这样会使得上面的代码无效//因为这相当于重新创建了一个原型对象Son.prototype = { getSonValue: function() {  return this.sonProp }}

1.4 原型链实现继承的弊端

世间万事万物都不可能十全而十美,原型链虽然强大,但也存在缺陷。

原型链中引用类型的属性会被所有实例共享的,即所有实例对象使用的是同一份数据,会相互影响。

 function Father() {  this.arr = [1,2,3] } function Son() { } Son.prototype = new Father() var son1 = new Son() console.log(son1.arr) //1,2,3 var son2 = new Son() son2.arr.push(4) console.log(son2.arr) //1,2,3,4 console.log(son1.arr) //1,2,3,4

无法向父级构造函数传参

2. 继承方式二:借用构造函数

2.1 介绍

方式一中引用类型带来的问题可借用构造函数的方式解决。其核心思想是:在子级构造函数中调用父级构造函数。

如何实现在一个构造函数中调用另一个函数?――call()和apply()

 function Father() {  this.arr = [1,2,3] } function Son() {  //call的第一个函数是this指向的对象,即构造函数的实例对象  Father.call(this)  /*上面代码等同于下面这段代码:  (function() {   this.arr = [1,2,3]  }).call(this)  */ } var son1 = new Son() console.log(son1.arr) //1,2,3 var son2 = new Son() son2.arr.push(4) console.log(son2.arr) //1,2,3,4 console.log(son1.arr) //1,2,3
//解决传参问题:function Father(name) { this.name = name}function Son(name) { Father.call(this, name)}var son1 = new Son("小名")console.log(son1.name)  //小名var son2 = new Son("一灯")console.log(son2.name)  //一灯

2.2 借用构造函数的缺陷

这种方式是通过构造函数实现的,当然也把构造函数自身的问题带过来了――破坏了复用性。因为每个实例都创建了一份副本。

3. 组合继承

3.1 介绍

组合继承 = 原型链 + 借用构造函数。取其长避其短:共享的用原型链,各自的借用构造函数

function Father(name) { this.name = name this.arr = [1,2,3]}Father.prototype.getName = function() { console.log(this.name)}function Son(name, age) { Father.call(this, name) this.age = age}Son.prototype = new Father()Son.prototype.constructor = SonSon.prototype.getAge = function() { console.log(this.age)}var son1 = new Son("小名", 23)son1.arr.push(4)console.log(son1.arr) //1,2,3,4son1.getName()    //小名son1.getAge()     //23var son2 = new Son("一灯", 24)console.log(son2.arr) //1,2,3son1.getName()    //一灯son1.getAge()     //24

3.2 解析

借用构造函数部分:

Father.call(this, name)――name来自Father
this.age = age; Son.prototype.constructor = Son――age来自Son

原型链部分:

Father.prototype.getName――getName方法来自Father.prototype
Son.prototype.getAge――getAge来自Son.prototype

后记

关于继承的后三种方式马上推出,期待你的点赞&关注!

以上所述是小编给大家介绍的js继承方式详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表