What is super() in JavaScript?

2021-01-18 hahaCoder



小夥伴們大家好,今天我們來說一下ES6中的super關鍵字,這次我嘗試了一種新的寫文形式:中英文結合,在本文的前半部分,我會引用 Bailey Jone 的一篇關於super的文章,後半部分我會結合ES6的標準和實際的小demo對其做一個總結,請看文章。


source:https://css-tricks.com/what-is-super-in-javascript/

Author:Bailey Jone

Published:Nov 6, 2019



What’s happening when you see some JavaScript that calls super()?.In a child class, you use super() to call its parent’s constructor and super.<methodName> to access its parent’s methods. This article will assume at least a little familiarity with the concepts of constructors and child and parent classes. If that’s totally new, you may want to start with Mozilla’s article on Object-oriented JavaScript for beginners.Super isn’t unique to Javascript — many programming languages, including Java and Python, have a super() keyword that provides a reference to a parent class. JavaScript, unlike Java and Python, is not built around a class inheritance model. Instead, it extends JavaScript’s prototypal inheritance model to provide behavior that’s consistent with class inheritance.Let’s learn a bit more about it and look at some code samples.First off, here’s a quote from 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.


An example of a simple child and parent class will help illustrate what this quote really means:

 

<!--HTML代碼-->
<h4>grouper</h4>
<div id="grouper"></div>
<h4>rainbow trout</h4>
<div id="rainbowTrout"></div>
<div id="rainbowTroutParent"></div>


/*CSS樣式*/
.green {
color: green;
}


/*js代碼*/
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"));


My example has two classes: fish and trout. All fish have information for habitat and length, so those properties belong to the fish class. Trout also has a property for variety, so it extends fish to build on top of the other two properties. Here are the constructors for fish and trout:


/*js代碼*/
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
}
}


The fish class’s constructor defines habitat and length, and the trout’s constructor defines variety. I have to call super() in trout’s constructor, or I』ll get a reference error when I try to set this.variety. That’s because on line one of the trout class, I told JavaScript that trout is a child of fish using the extends keyword. That means trout’s this context includes the properties and methods defined in the fish class, plus whatever properties and methods trout defines for itself. Calling super() essentially lets JavaScript know what a fish is so that it can create a this context for trout that includes everything from fish, plus everything we’re about to define for trout. The fish class doesn’t need super() because its 「parent」 is just the JavaScript Object. Fish is already at the top of the prototypal inheritance chain, so calling super() is not necessary — fish’s this context only needs to include Object, which JavaScript already knows about.

 

The prototypal inheritance model for fish and trout and the properties available on the this context for each of them. Starting from the top, the prototypal inheritance chain here goes Object → fish → trout.


I called super(habitat, length) in trout’s constructor (referencing the fish class), making all three properties immediately available on the this context for trout. There’s actually another way to get the same behavior out of trout’s constructor. I must call super() to avoid a reference error, but I don’t have to call it 「correctly」 with parameters that fish’s constructor expects. That’s because I don’t have to use super() to assign values to the fields that fish creates — I just have to make sure that those fields exist on trout’s this context. This is an important difference between JavaScript and a true class inheritance model, like Java, where the following code could be illegal depending on how I implemented the fish class:
/*js代碼*/
class trout extends fish {
constructor(habitat, length, variety) {
super()
this.habitat = habitat
this.length = length
this.variety = variety
}
}

This alternate trout constructor makes it harder to tell which properties belong to fish and which belong to trout, but it gets the same result as the previous example. The only difference is that here, calling super() with no parameters creates the properties habitat and length on the current this context without assigning anything to them. If I called console.log(this) after line three, it would print {habitat: undefined, length: undefined}. Lines four and five assign values.I can also use super() outside of trout’s constructor in order to reference methods on the parent class. Here I』ve defined a renderProperties method that will display all the class’s properties into the HTML element I pass to it. super() is useful here because I want my trout class to implement a similar method that does the same thing plus a little more — it assigns a class name to the element before updating its HTML. I can reuse the logic from the fish class by calling super.renderProperties() inside the relevant class function.

 

/*js代碼*/
class fish {
renderProperties(element) {
element.innerHTML = JSON.stringify(this)
}
}

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


The name you choose is important. I』ve called my method in the trout class renderPropertiesWithSuper() because I still want to have the option of calling trout.renderProperties() as it’s defined on the fish class. If I』d just named the function in the trout class renderProperties, that would be perfectly valid; however, I』d no longer be able to access both functions directly from an instance of trout – calling trout.renderProperties would call the function defined on trout. This isn’t necessarily a useful implementation – it’s an arguably better pattern for a function that calls super like this to overwrite its parent function’s name – but it does illustrate how flexible JavaScript allows your classes to be.

It is completely possible to implement this example without the use of the super() or extends keywords that were so helpful in the previous code sample, it’s just much less convenient. That’s what Mozilla meant by 「syntactical sugar.」 In fact, if I plugged my previous code into a transpiler like Babel to make sure my classes worked with older versions of JavaScript, it would generate something closer to the following code. The code here is mostly the same, but you』ll notice that without extends and super(), I have to define fish and trout as functions and access their prototypes directly. I also have to do some extra wiring on lines 15, 16, and 17 to establish trout as a child of fish and to make sure trout can be passed the correct this context in its constructor. If you’re interested in a deep dive into what’s going on here, Eric Green has an excellent post with lots of code samples on how to build classes with and without ES2015.
/*js代碼-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"));```


Classes in JavaScript are a powerful way to share functionality. Class components in React, for example, rely on them. However, if you’re used to Object Oriented programming in another language that uses a class inheritance model, JavaScript’s behavior can occasionally be surprising. Learning the basics of prototypal inheritance can help clarify how to work with classes in JavaScript.

 


super 這個關鍵字既可以當作函數使用,也可以當作對象使用。在這兩種情況下,它的使用方法完全不同。


該情況下,super作為函數調用時代表父類的構造函數。在ES6標準之下,子類的構造函數必須執行一次super函數,請看演示代碼:


/*js代碼*/
class Family{
constructor(name,age) {
this.name = name;
this.age = age;
}
loveFamily(){
console.log(`我是父類中的方法:We are a big family,and her name is ${this.name},she has been ${this.age} years old,all our members love it deeply.`)
}
}

class Child extends Family{
constructor(name,age,mother) {
super(name,age);
this.mother = mother;
}
loveMom(){
console.log(`我是子類中的方法:My name is ${this.name},i am ${this.age} years old,and this is my mom,her name is ${this.mother}.`);
}
}

let family = new Family("hahaCoder",100)
family.loveFamily()
let child = new Child("shipudong",22,"Hui")
child.loveMom()


上述代碼中,我們定義了父類 Family ,子類 Child,並讓子類通過super關鍵字繼承了來自父類的兩個屬性:name和age,如果在子類中我們沒有調用父類的構造函數,即在子類中沒有使用super關鍵字,JS引擎就會報錯:



我們知道,super表示父類 Family 的構造函數,但是當在子類 Child 中使用的時候,其返回的是子類的實例,即其內部this指針指向的是子類Child,因此我們可以這樣理解:


super() === Family.prototype.constructor.call(this)


上述代碼太過冗餘了,我們不看它了,來寫一小段代碼,證實上述的這個結論:


/*js代碼*/
class A {
constructor() {
console.log(`親,當前正在執行的是${new.target.name}函數喲~`)
}
}
class B extends A{
constructor() {
super();
}
}
let a_exp = new A()
let b_exp = new B()


上述代碼中,new.target指向當前正在執行的函數。可以看到,在super()執行時,它指向的是子類B的構造函數,而不是父類A的構造函數,也就是說super()內部的this指向的是B,故上述結論得證。


最後,關於當super作為一個函數使用時的情況,我們在提醒最後一點:super()只能用在子類的構造函數中,用在其他地方會報錯,請看錯誤代碼:


/*js代碼*/
class A {}
class B extends A{
m(){
super();
}
}





該情況下,super作為對象時在普通方法中指向父類的原型對象;在靜態方法中指向父類。



/*js代碼*/
class SuperType {
constructor(name,age) {
this.name = name;
this.age = age;
}
sayHello(){
console.log(`Hello,this is ${this.name},he is ${this.age} years old,nice to meet you guys!`)
}
}

class SubType extends SuperType{
constructor() {
super();
super.sayHello();
console.log(super.name);
}
}

let sub = new SubType()


我們知道,在ES6中如果我們需要在類的原型對象上定義方法,可以直接在class中去寫,不用在像以前這樣:


/*js代碼*/
function Person(){}
Person.prototype.sayName = function(){
/*
邏輯功能
*/
}


因為在ES6標準中,方法是直接定義在原型對象上的,因此子類的實例對象可以藉助原型鏈訪問到子類的原型對象、父類的原型對象上的所有方法,但當我們想要訪問父類實例中的屬性時,卻不能訪問到,這是因為super指向父類的原型對象,定義在父類實例上的方法或屬性無法通過super來調用。上述代碼中通過super關鍵字調用父類的方法這一行代碼可以等價為如下代碼:


/*js代碼*/
class SubType extends SuperType{
constructor() {
super();
SuperType.prototype.sayHello(); // 本行代碼等價於super.sayHello();
}
}


如果我們必須要訪問父類實例上的屬性或方法,那我們就必須做如下定義:


/*js代碼*/
class A{}
A.prototype.x = 2;
class B extends A{
constructor(){
super();
console.log(super.x);
}
}


即把我們想要訪問到的屬性和方法,定義在父類的原型對象上。


在ES6標準下,規定:當通過super()調用父類的方法時,super會被綁定到子類的this,我們來看一段演示代碼:


/*js代碼*/
class SuperType {
constructor() {
this.x = 1;
}
}

class SubType extends SuperType{
constructor() {
super();
this.x = 2;
super.x = 3;
console.log(super.x); // undefined
console.log(this.x); // 3

}
}

let sub = new SubType()


上述代碼中,由於super會綁定子類的this,因此當通過super對某個屬性賦值,這時super就是this,賦值的屬性會變成子類實例的屬性,故當super.x被賦值為3時,等同於對this.x賦值為3,故當讀取this.x時候,其值為3,當讀取super.x時,由於其父類原型對象上並沒有關於x的任何定義,故其值為undefined。


我們最後再來說一下super在靜態方法中的情況:


首先,我們有必要來說一下class中的靜態方法:我們知道,類相當於實例的原型,所有類中定義的方法都會被實例繼承,如果在一個方法前加上static關鍵字,就表示該方法不會被實例繼承,而是直接通過類調用。


接下來, 我們看一段代碼:


/*js代碼*/
class SuperType {
static SuperMethod(info){
console.log(`我是父類中的靜態方法,我被定義在父類中:${info}`)
}
SuperMethod(info){
console.log(`我是父類中的普通方法,我被定義在父類的原型對象上:${info}`)
}
}

class SubType extends SuperType{
static SuperMethod(info){
super.SuperMethod(info)
}
SuperMethod(info){
super.SuperMethod(info)
}
}

SubType.SuperMethod("hello,靜態方法")
let sub = new SubType()
sub.SuperMethod("hello,普通方法")


上述代碼中,super在靜態方法中指向父類,在普通方法中執向父類的原型對象。


最後,在提醒各位小夥伴兩點:


/*js代碼*/
class A {}
class B extends A{
constructor() {
super();
console.log(super);
}
}


/*js代碼*/
let obj = {
sayName(){
console.log( `sayName:${super.toString()}`)
}
}
obj.sayName()





本文我們主要講解了super關鍵字的兩種應用場景,包括在函數中使用和在對象中使用,並嘗試了一種新的寫文方式:中英結合,小夥伴們理解了嗎?快去實現一下吧~


相關焦點

  • JavaScript在Avant瀏覽器中的妙用
    圖1 具體操作  1.顯示網頁中的所有圖片  javascript:Ai7Mg6P='';for%20(i7M1bQz=0;i7M1bQz<document.images.length  2.顯示網頁中除圖片的其他  javascript:for(jK6bvW=0;jK6bvW<document.images.length;jK6bvW++){void(document.images[jK6bvW].style.visibility='hidden')}  3.顯示網頁原始碼(對於加密過的可以直接顯示其加密前的原始碼)
  • 【學術報告】Super Dots for Super Resolution Imagingand Single...
    allow high-throughput bio-discoveries, data storage, single nanoparticle lasing and high-security-level anti-counterfeiting applications, setting records for the tracking of single-molecule transport, super-resolution
  • JavaScript:詳解Base64編碼和解碼
    我們經常使用的JavaScript語言,它內部就是採用UTF16編碼,並且它的存儲方式為大端序,來看一個例子:<script type="text/javascript">  console.group(
  • What will matter?人生的意義
    It will not matter what you owned or what you were owed.   Your grudges, resentments, frustrations, and jealousies will finally disappear.
  • Belli璧麗進駐綠地全球商品直銷中心G-super
    作為一個以高品質精選為口碑的優質平臺,G-super成功迎合了市場需求,它自上海起步,擁有全球五大洲採購基地,匯集了歐美、澳新、東南亞等全世界共計超過12000多種的優質進口商品,所有產品經過精挑細選,品類多樣且物美價廉。短短幾年,G-super便在成都、杭州、南京、蘇州等多個城市迅速擴展,規模躍居高超前三。
  • 天上智喜,少女時代,super junior,sunday婚禮總出動
    天上智喜,少女時代,super junior,sunday婚禮總出動天上智喜出身的Sunday公開了婚禮現場,Sunday於12日與模特出身的公司職員籤訂了百年佳約。少女時代和super junior的成員出席也是很多驚喜,帥哥美女齊聚一堂,Sunday的婚禮可以說是閃亮啦……匆匆一撇,已經到了說再見的時候,走之前別忘了給本小娛點個讚或者留個言,更更好加個關注,Kkk!轉載請告知,請著名!請尊重原創!
  • 首開「大潤發super」,大潤發為什麼要布局中型門店?
    在品類規劃上,不同於面積在500平米至1000平米的mini店主打一日三餐型消費,大潤發super以更大的面積可承載1.5萬支SKU,除了可以滿足顧客更加豐富的購買需求,在購物體驗上也是一個升級。比如在大潤發super首店內,部分商品陳列區增加了特色菜譜、單品小知識,幫助顧客了解商品;休閒食品區域排面設置了服務鈴,隨時可以呼叫工作人員;油鹽醬醋等生活調料必需品的排面上掛著放大鏡,方便老年顧客查看保質期;店門口還提供寵物寄存服務。除此之外,不少大潤發自有品牌的特色商品如「大潤發天天鮮牛奶」、「潤發工坊」的各類熟食出現在貨架上,並提供現場試吃服務。
  • 句式:What is that doing to……?
    When we ask "what does A do to B," we're asking "how does A affect B" or "in what ways does A affect B."在今天的對話中我們看到的「What is thatdoing to (那對......有什麼影響)」就是一個很好的例子。
  • 貓小樂:普通賀卡和super「特色賀卡」,我選擇普通賀卡!
    貓小樂:普通賀卡和super「特色賀卡」,我選擇普通賀卡!新年到了!一個聖誕老人在上面跑著喊道:新年到了!帽子還掉了!為什麼新年是聖誕老人在跑呢,應該是年獸加鞭炮好吧。崇洋媚外!在一間教室裡,一個身穿一件黃色長袖衛衣的人伸出左手拿食指指著天花板說道:新年到啦!
  • 專寵super會員就在雙十一獅晚晚會
    最嗨的雙十一晚會,黃牛都搶不到票蘇寧來幫你承包,只要你是super會員,頂流明星雲集的獅晚晚會門票,蘇寧免費送!  不肝不氪,只要你是super正式會員,從11月1日到11月4日,每天都能免費抽獅晚門票。每天三次!每天三次!每天三次!沒有套路,簡單粗暴點抽獎就好。
  • what翻譯成怎麼的句子
    what和how在什麼情況下表示怎麼what可能在中文裡翻譯成什麼. 但有時在英文裡會翻譯成怎麼.這和中文的思維有些不一樣.下面是what 作為怎麼的例句what表示怎麼的句型不多.具體例子翻譯如下.What to call you怎麼稱呼你What is climate like in your country.你國家的天氣怎麼樣?
  • what are you什麼的意思
    what are you的中文釋義為你是幹什麼的。例句:What are you doing with those matches? what are you 你是幹什麼的 例句: 1.What are you basing this theory on? 你這種理論的根據是什麼? 2."What are you getting at now?"
  • 中學生英語課外閱讀:What Will Matter?
    It will not matter what you owned or what you were owed.   Your grudges, resentments, frustrations, and jealousies will finally disappear.
  • Super PhotoCut Pro for Mac(摳圖工具)v2.8.2中文版
    此外,super photocut pro可以立即切出透明物體,如婚紗,面紗等,而不會損壞圖像質量!/mac/4151.html評論[p=40, null, left]super現在,您可以使用super photocut mac應用程式刪除圖片背景和戲劇性背景剪切圖像,以秒為單位,而不是幾分鐘到幾小時。與市場上的Mac圖像背景去除器不同,Super PhotoCut不需要任何Mac背景去除技能。您只需要用矩形標記對象以獲得所需的結果。適用於Mac的Super PhotoCut背景去除器會自動為您剪切物體。
  • Superdry昆明首店進駐南亞風情第壹城 大陸已有8家店
    superdry創建於2003年,是純英國製造品牌,由於加入日本街頭風格及日文,常常讓人誤以為是日本的牌。到目前為止,superdry已經在全球超過20個國家銷售,像貝克漢姆、裘德·洛、凱特·莫斯都會定期出現在superdry的發布會上(代言)。
  • 美文閱讀:何為重要What Will Matter?
    It will not matter what you owned or what you were owed. Your grudges, resentments, frustrations, and jealousies will finally disappear.
  • Thats What I Like歌詞中英文翻譯
    Thats What I Like歌詞翻譯  I got a condo in Manhattan  我在曼哈頓買了座公寓  Baby girl, what's hatnin'?>  And I'm gonna give it to you  你要的我也都會給你  Girl, you be shining so bright  黃金珠寶 在眼前閃耀不停  Strawberry champagne all night  還有冰鎮的草莓香檳  Lucky for you, that's what
  • What is wrong with our society today?
    Those who have gone through that, know what I am talking about.As I write this answer,a story of a girl is constantly flashing through my mind.
  • A Super Bowl Special
    Can you guess what Americans will be watching this weekend? Of course! It is Super Bowl Sunday. Christopher Cruise has more about the competing teams and the cities they represent.
  • 實用口語:問別人怎麼了 你只會what's up或者what's wrong?
    新東方網>英語>英語學習>口語>實用口語>正文實用口語:問別人怎麼了 你只會what's up或者what's wrong?