返回顶部
首页 > 资讯 > 精选 >好程序员分享JavaScript六种继承方式详解
  • 344
分享到

好程序员分享JavaScript六种继承方式详解

2023-06-03 13:06:53 344人浏览 薄情痞子
摘要

好程序员分享javascript六种继承方式详解,继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的 原型链 首先得要明白什么是原型链,在一篇文章看懂

好程序员分享javascript六种继承方式详解,继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的

 

原型链

 

首先得要明白什么是原型链,在一篇文章看懂proto和prototype的关系及区别中讲得非常详细

 

原型链继承基本思想就是让一个原型对象指向另一个类型的实例

 

function SuperType() {

    this.property = true

}

 

SuperType.prototype.getSuperValue = function() {

    return this.property

}

 

function SubType() {

    this.subproperty = false

}

 

SubType.prototype = new SuperType()

 

SubType.prototype.getSubValue = function() {

    return this.subproperty

}

 

var instance = new SubType() console.log(instance.getSuperValue()) // true

代码定义了两个类型SuperType和SubType,每个类型分别有一个属性和一个方法,SubType继承了SuperType,而继承是通过创建SuperType的实例,并将该实例赋给SubType.prototype实现的

 

实现的本质是重写原型对象,代之以一个新类型的实例,那么存在SuperType的实例中的所有属性和方法,现在也存在于SubType.prototype中了

 

我们知道,在创建一个实例的时候,实例对象中会有一个内部指针指向创建它的原型,进行关联起来,在这里代码SubType.prototype = new SuperType(),也会在SubType.prototype创建一个内部指针,将SubType.prototype与SuperType关联起来

 

所以instance指向SubType的原型,SubType的原型又指向SuperType的原型,继而在instance在调用getSuperValue()方法的时候,会顺着这条链一直往上找

 

添加方法

 

在给SubType原型添加方法的时候,如果,父类上也有同样的名字,SubType将会覆盖这个方法,达到重新的目的。 但是这个方法依然存在于父类中

 

记住不能以字面量的形式添加,因为,上面说过通过实例继承本质上就是重写,再使用字面量形式,又是一次重写了,但这次重写没有跟父类有任何关联,所以就会导致原型链截断

 

function SuperType() {

    this.property = true

}

 

SuperType.prototype.getSuperValue = function() {

    return this.property

}

 

function SubType() {

    this.subproperty = false

}

 

SubType.prototype = new SuperType()

 

SubType.prototype = {

    getSubValue: function() {

        return this.subproperty

    }

}

 

var instance = new SubType() console.log(instance.getSuperValue()) // error

问题

 

单纯的使用原型链继承,主要问题来自包含引用类型值的原型。

 

function SuperType() {

    this.colors = ['red', 'blue', 'green']

}

 

function SubType() {}

 

SubType.prototype = new SuperType()

 

var instance1 = new SubType() var instance2 = new SubType()

 

instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"]

console.log(instance2.colors) // ["red", "blue", "green", "black"]

在SuperType构造函数定义了一个colors属性,当SubType通过原型链继承后,这个属性就会出现SubType.prototype中,就跟专门创建了SubType.prototype.colors一样,所以会导致SubType的所有实例都会共享这个属性,所以instance1修改colors这个引用类型值,也会反映到instance2中

 

借用构造函数

 

此方法为了解决原型中包含引用类型值所带来的问题

 

这种方法的思想就是在子类构造函数的内部调用父类构造函数,可以借助apply()和call()方法来改变对象的执行上下文

 

function SuperType() {

    this.colors = ['red', 'blue', 'green']

}

 

function SubType() {

    // 继承SuperType

    SuperType.call(this)

}

 

var instance1 = new SubType() var instance2 = new SubType()

 

instance1.colors.push('black') console.log(instance1.colors) // ["red", "blue", "green", "black"]

console.log(instance2.colors) // ["red", "blue", "green"]

在新建SubType实例是调用了SuperType构造函数,这样以来,就会在新SubType对象上执行SuperType函数中定义的所有对象初始化代码

 

结果,SubType的每个实例就会具有自己的colors属性的副本了

 

传递参数

 

借助构造函数还有一个优势就是可以传递参数

 

function SuperType(name) {

    this.name = name

}

 

function SubType() {

    // 继承SuperType

    SuperType.call(this, 'Jiang')

 

    this.job = 'student'

}

 

var instance = new SubType() console.log(instance.name) // Jiang

console.log(instance.job) // student

问题

 

如果仅仅借助构造函数,方法都在构造函数中定义,因此函数无法达到复用

 

组合继承(原型链+构造函数)

 

组合继承是将原型链继承和构造函数结合起来,从而发挥二者之长的一种模式

 

思路就是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承

 

这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性

 

function SuperType(name) {

    this.name = name this.colors = ['red', 'blue', 'green']

}

 

SuperType.prototype.sayName = function() {

    console.log(this.name)

}

 

function SubType(name, job) {

    // 继承属性

    SuperType.call(this, name)

 

    this.job = job

}

 

// 继承方法

SubType.prototype = new SuperType() SubType.prototype.constructor = SuperType SubType.prototype.sayJob = function() {

    console.log(this.job)

}

 

var instance1 = new SubType('Jiang', 'student') instance1.colors.push('black') console.log(instance1.colors) //["red", "blue", "green", "black"]

instance1.sayName() // 'Jiang'

instance1.sayJob() // 'student'

var instance2 = new SubType('J', 'doctor') console.log(instance2.colors) // //["red", "blue", "green"]

instance2.sayName() // 'J'

instance2.sayJob() // 'doctor'

这种模式避免了原型链和构造函数继承的缺陷,融合了他们的优点,是最常用的一种继承模式

 

原型式继承

 

借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型

 

function object(o) {

function F() {}

F.prototype = o

return new F()

}

在object函数内部,先创建一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例

 

本质上来说,object对传入其中的对象执行了一次浅复制

 

var person = {

    name: 'Jiang',

    friends: ['Shelby', 'Court']

}

 

var anotherPerson = object(person) console.log(anotherPerson.friends) // ['Shelby', 'Court']

这种模式要去你必须有一个对象作为另一个对象的基础

 

在这个例子中,person作为另一个对象的基础,把person传入object中,该函数就会返回一个新的对象

 

这个新对象将person作为原型,所以它的原型中就包含一个基本类型和一个引用类型

 

所以意味着如果还有另外一个对象关联了person,anotherPerson修改数组friends的时候,也会体现在这个对象中

 

Object.create()方法

 

ES5通过Object.create()方法规范了原型式继承,可以接受两个参数,一个是用作新对象原型的对象和一个可选的为新对象定义额外属性的对象,行为相同,基本用法和上面的object一样,除了object不能接受第二个参数以外

 

var person = {

    name: 'Jiang',

    friends: ['Shelby', 'Court']

}

var anotherPerson = Object.create(person) console.log(anotherPerson.friends)

寄生式继承

 

寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数

 

function createAnother(o) {

    var clone = Object.create(o) // 创建一个新对象

    clone.sayHi = function() { // 添加方法

        console.log('hi')

    }

    return clone // 返回这个对象

}

 

var person = {

    name: 'Jiang'

}

 

var anotherPeson = createAnother(person) anotherPeson.sayHi()

基于person返回了一个新对象anotherPeson,新对象不仅拥有了person的属性和方法,还有自己的sayHi方法

 

在主要考虑对象而不是自定义类型和构造函数的情况下,这是一个有用的模式

 

寄生组合式继承

 

在前面说的组合模式(原型链+构造函数)中,继承的时候需要调用两次父类构造函数

 

父类

 

function SuperType(name) {

this.name = name

this.colors = ['red', 'blue', 'green']

}

第一次在子类构造函数中

 

function SubType(name, job) {

// 继承属性

SuperType.call(this, name)

 

this.job = job

}

第二次将子类的原型指向父类的实例

 

// 继承方法

SubType.prototype = new SuperType()

当使用var instance = new SubType()的时候,会产生两组name和color属性,一组在SubType实例上,一组在SubType原型上,只不过实例上的屏蔽了原型上的

 

使用寄生式组合模式,可以规避这个问题

 

这种模式通过借用构造函数来继承属性,通过原型链的混成形式来继承方法

 

基本思路:不必为了指定子类型的原型而调用父类的构造函数,我们需要的无非就是父类原型的一个副本

 

本质上就是使用寄生式继承来继承父类的原型,在将结果指定给子类型的原型

 

function inheritPrototype(subType, superType) {

    var prototype = Object.create(superType.prototype);

    prototype.constructor = subType;

    subType.prototype = prototype;

}

该函数实现了寄生组合继承的最简单形式

 

这个函数接受两个参数,一个子类,一个父类

 

第一步创建父类原型的副本,第二步将创建的副本添加constructor属性,第三部将子类的原型指向这个副本

 

function SuperType(name) {

    this.name = name this.colors = ['red', 'blue', 'green']

}

 

SuperType.prototype.sayName = function() {

    console.log(this.name)

}

 

function SubType(name, job) {

    // 继承属性

    SuperType.call(this, name)

 

    this.job = job

}

 

// 继承

inheritPrototype(SubType, SuperType)

 

var instance = new SubType('Jiang', 'student') instance.sayName()

> 补充:直接使用Object.create来实现,其实就是将上面封装的函数拆开,这样演示可以更容易理解

 

function SuperType(name) {

    this.name = name this.colors = ['red', 'blue', 'green']

}

 

SuperType.prototype.sayName = function() {

    console.log(this.name)

}

 

function SubType(name, job) {

    // 继承属性

    SuperType.call(this, name)

 

    this.job = job

}

 

// 继承

SubType.prototype = Object.create(SuperType.prototype)

 

// 修复constructor

SubType.prototype.constructor = SubType

 

var instance = new SubType('Jiang', 'student') instance.sayName()

es6新增了一个方法,Object.setPrototypeOf,可以直接创建关联,而且不用手动添加constructor属性

--结束END--

本文标题: 好程序员分享JavaScript六种继承方式详解

本文链接: https://lsjlt.com/news/234370.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 好程序员分享JavaScript六种继承方式详解
    好程序员分享JavaScript六种继承方式详解,继承是面向对象编程中又一非常重要的概念,JavaScript支持实现继承,不支持接口继承,实现继承主要依靠原型链来实现的 原型链 首先得要明白什么是原型链,在一篇文章看懂...
    99+
    2023-06-03
  • 分享JavaScript 中的几种继承方式
    目录一、原型链1.1 原型链的问题二、盗用构造函数2.1 基本思想2.2 可向父类构造函数传参2.3 盗用构造函数的问题三、组合继承(伪经典继承)3.1 基本思想3.2 组合继承的问...
    99+
    2024-04-02
  • JavaScript中六种面试常考继承方式总结
    目录原型链继承盗用构造函数组合继承原型式继承寄生式继承寄生式组合继承js的几种继承方式在我们面试的时候经常会被问到,所以深入理解js几种继承方式以及它们的优缺点是非常有必要的。 原型...
    99+
    2023-02-13
    JavaScript继承方式 JavaScript继承
  • 好程序员web前端培训分享JavaScript学习笔记闭包与继承
      好程序员web前端培训分享JavaScript学习笔记闭包与继承,闭包:闭包是我们函数的一种高级使用方式,在聊闭包之前我们要先回顾一下 函数函数的两个阶段我们一直说函数有两个阶段定义阶段调用阶段开辟一个 存储空间把函...
    99+
    2023-06-03
  • 好程序员分享JavaScript命名空间模式实例详解
      好程序员分享JavaScript命名空间模式实例详解,本文实例讲述了JavaScript命名空间模式,具体如下:  命名空间可以被认为是唯一标识符下代码的逻辑分组。为什么会出现命名空间这一概念呢?因为可用的单词数太少,并且不同的人写的程...
    99+
    2023-06-03
  • C++三种继承方式及好处示例详解
    目录C++继承公有继承保护继承私有继承继承带来的好处总结C++继承 C++继承是面向对象编程中非常常见的一个概念,它提供了一种将一个类的特性引入另一个类的机制。在继承中,被继承的类...
    99+
    2023-05-16
    C++继承好处方式 C++继承方式
  • js继承的6种方式详解
    原型链继承 原型链继承是ECMAScript的主要继承方式。其基本思想就是通过原型继承多个引用类型的属性和方法。什么是原型链?每个构造函数都会有一个原型对象,调用构造函数创...
    99+
    2024-04-02
  • 好程序员分享java设计模式之享元模式
      好程序员分享java设计模式之享元模式,享元模式有点类似于单例模式,都是只生成一个对象被共享使用。享元模式主要目的就是让多个对象实现共享,减少不必要的内存消耗,将多对同一对象的访问集中起来,不必为每个访问者创建一个单独的对象,以此来降低...
    99+
    2023-06-02
  • 好程序员分享JavaScript事件委托代理和函数封装详解
    好程序员分享JavaScript事件委托代理和函数封装详解,JavaScript高级程序设计上讲:事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。下面我们一起看看事件代理相关介绍。 当用事件委托的时...
    99+
    2023-06-03
  • 好程序员技术分享html5和JavaScript的区别
    好程序员技术分享html5和JavaScript的区别,HTML5广义上讲是前端开发学科的代名词,包含HTML5、CSS3及JavaScript三个重要的部分,是运行在浏览器上应用的统称。如PC端网站、管理系统、手机网页应用(WebApps...
    99+
    2023-06-03
  • 好程序员web前端培训分享学习JavaScript
    好程序员web前端教程分享学习JavaScript,我试着总结自己学习JavaScript的方法 JavaScript给人那种感觉的原因多半是因为它如下的特点: 本身知识很抽象、晦涩难懂,如:闭包、内置对象、DOM。本身...
    99+
    2023-06-03
  • 好程序员技术分享浅谈JavaScript中的闭包
    好程序员技术分享浅谈JavaScript中的闭包,js闭包是指有权访问另一个函数作用域中的变量的函数,个人认为js闭包最大的用处就是防止对全局作用域的污染。 试想如果我们把一些仅仅只用到一两次的变量都声明在全局作用域中,最后肯定是容易出错且...
    99+
    2023-06-03
  • 好程序员web前端教程之详解JavaScript严格模式
      好程序员web前端教程之详解JavaScript严格模式,严格模式(Strict mode)是由ECMA-262规范定义的新兴JavaScript标准,发布于2009年12月第五版。旨在改善错误检查功能并且标识可能不会延续到未来Java...
    99+
    2023-06-03
  • 深入讲解JavaScript之继承的多种方式和优缺点
    目录1.原型链继承2.借用构造函数(经典继承)3.组合继承4.原型式继承5. 寄生式继承6. 寄生组合式继承1.原型链继承 function Parent () { th...
    99+
    2024-04-02
  • 好程序员web前端分享CSS3颜色值HSLA表示方式
    说明:本文档兼容性测试基础环境为:windows系统;IE6-IE10, Firefox6.0, Chrome13.0, Safari5.1, Opera11.51说明:HSLA(H,S,L,A)取值:H:Hue(色调)。0(或360)表示...
    99+
    2023-06-03
  • 好程序员分享如何看待CSS中BEM的命名方式?
      好程序员分享如何看待CSS中BEM的命名方式BEM的意识就是块(block)、元素(element)、修饰符(modifier),是由yandex团队提出的一种CSS Class命名方法。   任何一个东西的存在都有其存在的道...
    99+
    2023-06-03
  • 原生Javascript实现继承方式及其优缺点详解
    目录前言原型继承优点缺点 构造函数继承 优点 缺点 组合式继承 寄生式组合继承总结前言 最近在复习javascript的一些基础知识,为开启新的征程做准备。所以开始记录一些自己学习的...
    99+
    2024-04-02
  • 好程序员web前端教程分享js文件引用编码方式
    好程序员web前端教程分享js文件引用编码方式,js外部文件编码由这些因素决定:1.如果Apache有DefaultCharset,则js文件解析用服务器指定的编码;2.如果PHP header声明charset为编码utf-8,则文件编码...
    99+
    2023-06-03
  • 好程序员分享使用JavaScript正则表达式如何去掉双引号
      好程序员分享使用JavaScript正则表达式如何去掉双引号最近接了一个项目,项目需求需要用js正则表达式过滤掉页面文本域中值得双引号,其实解决办法很简单,下面把我写的代码分享给大家,有同样需求的朋友可以参考下。   具体的解...
    99+
    2023-06-03
  • 好程序员分享JavaScript学习笔记ES5中常见的数组方法
      好程序员分享JavaScript学习笔记ES5中常见的数组方法,ES5中常见的数组常用方法之前我们讲过的数组常用方法都是ES3的方法,今天来说一些ES5中的方法。indexOf· indexOf 用来找到数组中某一项的索引·&...
    99+
    2023-06-03
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作