服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - js教程 - 聊一聊 JavaScript 中的 Super() 是什么?

聊一聊 JavaScript 中的 Super() 是什么?

2022-11-09 17:58新钛云服方章和 翻译 js教程

当你在js代码中看到有调用super()时,会不会好奇这个super()到底有什么作用?本文将假定您至少对构造函数以及子类和父类的概念有所了解。如果你不了解这些,则可能需要从Mozilla的Object-oriented JavaScript for beginners开始学习。

聊一聊 JavaScript 中的 Super() 是什么?

当你在js代码中看到有调用super()时,会不会好奇这个super()到底有什么作用?在子类中,您可以使用super()调用其父级的构造函数,并使用super.<方法名>来访问其父级的方法。

本文将假定您至少对构造函数以及子类和父类的概念有所了解。如果你不了解这些,则可能需要从Mozilla的Object-oriented JavaScript for beginners开始学习。

super并不是只javascript语言才有--许多其它编程语言,如java, python都有一个super()关键字来提供对父类的引用。与Java和Python不同,JavaScript并不是围绕类继承模型构建的。相反,它扩展了JavaScript的原型继承模型,以提供与类继承一致的行为。

让我们进一步了解它,并查看一些代码示例。

首先,这里引用的一段话Mozilla’s web docs for classes:

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript’s existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

一个简单的子类和父类的例子将有助于说明这句话的真正含义:

class Fish { constructor(habitat, length) { this.habitat = habitat this.length = length } renderProperties(element) { element.innerHTML = JSON.stringify(this)
}
} class Trout extends Fish { constructor(habitat, length, variety) { super(habitat, length) this.variety = variety } renderPropertiesWithSuper(element) { element.className="green" super.renderProperties(element);
}
} let grouper = new Fish("saltwater", "26in"); console.log(grouper); grouper.renderProperties(document.getElementById("grouper")); let rainbowTrout = new Trout("freshwater", "14in", "rainbow"); console.log(rainbowTrout); //invoke function from parent prototype rainbowTrout.renderProperties(document.getElementById("rainbowTrout")); //invoke function from child's prototype rainbowTrout.renderPropertiesWithSuper(document.getElementById("rainbowTroutParent"));

我的例子有两个类:Fish和 Trout。所有的鱼都有栖息地和长度的信息,所以这些属性属于鱼类。鳟鱼也有一个多样性的属性,所以它基于fish又扩展了属性variety。下面是鱼和鳟鱼的构造函数:

class fish { constructor(habitat, length) { this.habitat = habitat this.length = length }
} class trout extends fish { constructor(habitat, length, variety) { super(habitat, length) this.variety = variety }
}

鱼类的构造函数定义栖息地和长度,鳟鱼的构造函数定义了种类。我必须在鳟鱼的构造函数中调用super(),否则在尝试设置this.variety时会出现错误。那是因为在鳟鱼类的第一行中,我告诉JavaScript鳟鱼是使用extends关键字的“鱼”。

这意味着鳟鱼的上下文包括fish类中定义的属性和方法,以及鳟鱼为其自身定义的任何属性和方法。调用super()本质上使JavaScript知道鱼是什么,以便可以为鳟鱼创建this上下文,其中包括鱼中的所有内容以及我们将为鳟鱼定义的所有内容。fish类不需要super(),因为它的“父级”只是JavaScript对象。Fish已处于原型继承链的顶部,因此无需调用super()。

我在trout的构造函数中调用super(habitat, length),使这三个属性在这个上下文中立即可用。实际上还有另一种方法可以从trout的构造函数中得到相同的行为。我必须调用super()来避免引用错误,但我不必使用fish的构造函数所期望的参数正确调用它。

这是因为我不需要使用super()来给fish创建的字段赋值,我只需要确保这些字段存在于这个上下文上。这是JavaScript与真正的类继承模型(例如Java)之间的重要区别,根据我的实现方式,以下代码可能是非法的:

class trout extends fish { constructor(habitat, length, variety) { super() this.habitat = habitat this.length = length this.variety = variety }
}

这种替代的trout构造函数使您更难分辨哪些属性属于fish和哪些属性属于trout,但其结果与前面的示例相同。唯一的区别是,在此情况下,不带参数调用super()会在当前此this的上下文上创建属性habitat和length,而无需为其分配任何内容。

如果我在第三行之后调用console.log(this),它将显示{habitat:undefined,length:undefined}。第四行和第五行分配值。

我也可以在trout的构造函数之外使用super(),以引用父类上的方法。在这里,我定义了renderProperties方法,该方法会将类的所有属性显示在我传递给它的HTML元素中。

super()在这里很有用,因为我希望我的trout类实现一个类似的方法,该方法可以完成相同的工作,并且还要多做一些事情—它在更新HTML之前为该元素执定了一个类名。我可以通过在相关类函数内调用super.renderProperties()来重用fish类中的逻辑。

class fish { renderProperties(element) { element.innerHTML = JSON.stringify(this)
}
} class trout extends fish { renderPropertiesWithSuper(element) { element.className="green" super.renderProperties(element);
}
}

你在定义时方法命名很重要。我把我在trout类中的方法叫做renderPropertiesWithSuper(),因为我仍然希望可以选择调用trout.renderProperties(),因为它是在fish类上定义的。

如果我只是将函数命名为trout类中的renderProperties,那将是完全有效的;但是,我将不再能够从trout的实例中直接访问这两个函数--调用trout.renderProperties将调用定义在trout上的函数。

这不一定是一个有用的实现方式--可以说,像这样调用super的函数覆盖其父函数的名称是一个更好的模式--但它确实说明了JavaScript允许你的类是多么灵活。

其实也可以完全可以不使用前面代码示例中非常有用的super()或extends关键字来实现这个例子,只是不太方便。这就是Mozilla所说的 "语法糖 "的意思。事实上,如果我把我之前的代码插入像Babel这样的移植器中,以确保我的类能与旧版本的JavaScript一起工作,它将生成一些更接近下面的代码。

这里的代码大部分是一样的,但你会注意到,如果没有extends和super(),我必须将fish和trout定义为函数并直接访问它们的原型。我还必须在第15、16和17行对原型做一些额外的改动,并确保trout可以在其构造函数中传递正确的this上下文(混合继承)。

如果你有兴趣深入了解这里发生的事情,Eric Green有一篇优秀的帖子,里面有很多代码片段,介绍了如何使用和不使用ES2015构建类以及其继承的关系。

function Fish(habitat, length) { this.habitat = habitat; this.length = length;
} Fish.prototype.renderProperties = function(element) { element.innerHTML = JSON.stringify(this)
}; function Trout(habitat, length, variety) { this._super.call(this, habitat, length); this.variety = variety;
} Trout.prototype = Object.create(Fish.prototype); Trout.prototype.constructor = Trout; Trout.prototype._super = Fish; Trout.prototype.renderPropertiesWithSuper = function(element) { element.className="green"; this.renderProperties(element);
}; let grouper = new Fish("saltwater", "26in"); grouper.renderProperties(document.getElementById("grouper")); var rainbowTrout = new Trout("freshwater", "14in", "rainbow"); //invoke function from parent rainbowTrout.renderProperties(document.getElementById("rainbowTrout")); //invoke function from child rainbowTrout.renderPropertiesWithSuper(document.getElementById("rainbowTroutParent"));

JavaScript中的类是共享功能的强大方法。例如,React中的类组件依赖于它们。但是,如果您习惯使用另一种使用类继承模型的语言进行面向对象的编程,那么JavaScript的行为有时可能会令人惊讶。所以学习原型继承的基础知识可以帮助阐明如何使用JavaScript中的类。

原文地址:https://mp.weixin.qq.com/s/zPZcaQj77gMEHtA_DdUhwg

延伸 · 阅读

精彩推荐
  • js教程一文带你用80行代码实现简易 RxJS

    一文带你用80行代码实现简易 RxJS

    RxJS 是一个响应式的库,它接收从事件源发出的一个个事件,经过处理管道的层层处理之后,传入最终的接收者,这个处理管道是由操作符组成的,开发者...

    神光的编程秘籍6052022-02-28
  • js教程JavaScript 绘制饼图的示例

    JavaScript 绘制饼图的示例

    这篇文章主要介绍了JavaScript 绘制饼图的示例,帮助大家更好的利用JavaScript绘制图表,感兴趣的朋友可以了解下...

    MwqgKG11562022-01-21
  • js教程JavaScript实现鼠标拖拽调整div大小

    JavaScript实现鼠标拖拽调整div大小

    这篇文章主要为大家详细介绍了JavaScript实现鼠标拖拽调整div大小,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    BDawn9242022-02-12
  • js教程原生js实现自定义滚动条

    原生js实现自定义滚动条

    这篇文章主要为大家详细介绍了原生js实现自定义滚动条,可点击、拖动到达,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可...

    Xaivor4502022-01-05
  • js教程十个高级 TypeScript 开发技巧

    十个高级 TypeScript 开发技巧

    在使用了一段时间的 Typescript 之后,我深深地感受到了 Typescript 在大中型项目中的必要性。 可以提前避免很多编译期的bug,比如烦人的拼写问题。 并且越...

    web前端开发7832022-11-08
  • js教程javascript实现简单页面倒计时

    javascript实现简单页面倒计时

    这篇文章主要为大家详细介绍了javascript实现简单页面倒计时,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    潜力股wjk12032022-01-25
  • js教程微信小程序自定义tabbar组件

    微信小程序自定义tabbar组件

    这篇文章主要为大家详细介绍了微信小程序自定义tabbar组件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    赵思远kelsty5942022-02-16
  • js教程js删除指定位置超链接中含有百度与360的标题

    js删除指定位置超链接中含有百度与360的标题

    最近需要将最近更新的部分内容删除,只要标题中包括百度与360的都给删除了,主要用到了jquery的each,需要的朋友可以参考下...

    JS教程网3832021-12-27