Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537
于class類這個概念,我相信學過編程的人應該對他見多不怪了,因為在其他的編程語言中很早就實現(xiàn)了,而JavaScript語言并沒有實現(xiàn),一直以來,開發(fā)人員都是使用function和原型prototype來模擬類class實現(xiàn)面向?qū)ο蟮木幊?
接下來的學習,前端君默認大家都了解傳統(tǒng)的模擬類的寫法,如果你已經(jīng)忘記了,ES6系列的第九節(jié)有介紹JavaScript的面向?qū)ο螅c擊可以查看。
現(xiàn)在,ES6給我們帶來了好消息,它給JavaScript帶來了類class的概念。但實際上,JavaScript的類class本質(zhì)上也是基于原型prototype的實現(xiàn)方式做了進一步的封裝,讓我們使用起來更簡單明了。也就是說它實際上也是函數(shù)function和原型prototype實現(xiàn)。
那么,我們就使用ES6封裝后的類class來實現(xiàn)我們想要的效果,我們來學學它的基本用法。
聲明一個類的寫法:
//定義一個叫Animal的類
class Animal {
//構造函數(shù)constructor
constructor(color){
this.color = color;
}
}
代碼很簡短,我們通過關鍵字class來聲明一個名字叫Animal的類,可以看到類里面(花括號 {}里面)有一個叫constructor方法,它就是構造方法,構造方法里面的this,指向的是該類實例化后的對象,這就是實現(xiàn)了一個類的聲明。
其中,構造方法constructor是一個類必須要有的方法,默認返回實例對象;創(chuàng)建類的實例對象的時候,會調(diào)用此方法來初始化實例對象。如果你沒有編寫constructor方法,執(zhí)行的時候也會被加上一個默認的空的constructor方法。
了解了類的聲明和constructor構造函數(shù)的特點,我們下面來了解如何給類添加屬性和方法。
class Animal {
//構造方法
constructor(name){
//屬性name
this.name = name;
}
//自定義方法getName
getName(){
return this.name;
}
}
我們把類名后面的括號{ }里面的內(nèi)容稱之為類體,我們會在類體內(nèi)來編寫類的屬性和方法。上面的案例中,類體內(nèi)有2個方法:constructor( )、getName()。
其中constructor方法是構造方法,在實例化一個類的時候被調(diào)用。constructor方法是必須的,也是唯一的,一個類體不能含有多個constructor構造方法。我們可以在方法里面自定義一些對象的屬性,比如案例中的name屬性。
此外,我們還自定義了一個getName( )方法,它屬于類的實例方法,實例化后對象可以調(diào)用此方法。
掌握了類的屬性和方法的寫法,接下來,我們學習如何創(chuàng)建對象和使用對象的實例方法:
class Animal {
//構造方法
constructor(name){
//屬性name
this.name = name;
}
//自定義方法getName
getName(){
return 'This is a'+this.name;
}
}
//創(chuàng)建一個Animal實例對象dog
let dog = new Animal('dog');
dog.name; //結果:dog
dog.getName(); //結果:This is a dog
還是同一個類Animal,我們通過new來創(chuàng)建了實例對象dog,構造方法會把傳進去的參數(shù)“dog”通過this.name賦值給對象的name屬性,所以dog的name屬性為“dog”,對象dog還可以調(diào)用自己的實例方法getName( ),結果返回:“This is a dog”。
實例對象的創(chuàng)建有幾個要注意的事項:
上面講到的自定義方法是實例方法,也就是實例化后的對象才可以調(diào)用的方法,比如上述案例的getName( )方法。除了實例方法以外,我們還可以定義一種直接使用類名即可訪問的方法,我們稱之為“靜態(tài)方法”。
我們一起來看看如何實現(xiàn)靜態(tài)方法的定義:
class Animal {
//構造方法
constructor(name){
//屬性name
this.name = name;
}
//自定義一個靜態(tài)方法
static friends(a1,a2){
return `${a1.name} and ${a2.name} are friends`;
}
}
//創(chuàng)建2個實例
let dog = new Animal('dog');
let cat = new Animal('cat');
//調(diào)用靜態(tài)方法friends
Animal.friends(dog,cat);
//結果:dog and cat are friends
靜態(tài)方法和實例方法不同的是:靜態(tài)方法的定義需要使用static關鍵字來標識,而實例方法不需要;此外,靜態(tài)方法通過類名來的調(diào)用,而實例方法通過實例對象來調(diào)用。
上述案例的friends( )方法中,我們用到了字符串模板的知識,是ES6給String字符串帶來的新特性,第六節(jié)有講解,點擊可以查看。
說到類class,就不得不說類的繼承,ES6使用extends關鍵字來實現(xiàn)子類繼承父類,我們來演示一下:
//父類Animal
class Animal {//...}
//子類Dog
class Dog extends Animal {
//構造方法
constructor(name,color){
super(name);
this.color = color;
}
}
上面的案例中,我們定義兩個類,Animal類作為父類,Dog類作為子類,然后通過關鍵字extends來實現(xiàn)繼承,此外,我們還注意到一個關鍵字super,它相當于是父類中的this。
我們可以用super來引用父類,訪問父類的方法,我們來演示一下:
//父類Animal
class Animal {
//構造方法
constructor(name){
//屬性name
this.name = name;
}
//父類的自定義方法
say(){
return `This is a animal`;
}
}
//子類Dog
class Dog extends Animal {
//構造方法
constructor(name,color){
super(name);
this.color = color;
}
//子類的實例方法
getAttritube(){
return `${super.say()},
name:${this.name},
color:${this.color}`;
}
}
//創(chuàng)建Dog的實例對象
let d = new Dog("dog","black");
//調(diào)用子類的Dog的實例方法
d.getAttritube();
//結果:This is a animal,
name:dog,
color:black
在父類中,我們定義了say方法,想要在子類中調(diào)用父類的say方法的話,我們使用super.say( )即可實現(xiàn)。
使用super有幾個要注意的事項:
以上就是關于類繼承的介紹,重點在于關鍵字extends和super,尤其是super的理解和使用,大家需要理解透徹。
如果是完全沒有接觸過類class和面向?qū)ο蟮某鯇W者,看這一節(jié)也許不能完全理解透徹,你可以先翻看第九節(jié)的JavaScript面向?qū)ο蟮慕榻B。
總結:ES6給JavaScript帶來了類class的概念和實現(xiàn),實際上是對傳統(tǒng)實現(xiàn)方式的一種包裝,通過關鍵字class來定義類,通過extends來實現(xiàn)繼承,子類的super是父類的引用,在繼承中起著十分重要的作用。
上一篇:教你如何使用ES6的Promise對象
CMAScript 6 提供了更接近傳統(tǒng)語言的寫法,新引入的class關鍵字具有正式定義類的能力。類(class)是ECMAScript中新的基礎性語法糖結構,雖然ECMAScript 6類表面上看起來可以支持正式的面向?qū)ο缶幊蹋珜嶋H上它背后使用的仍然是原型和構造函數(shù)的概念,讓對象原型的寫法更加清晰、更像面向?qū)ο缶幊痰恼Z法。
定義類也有兩種主要方式:類聲明和類表達式。這兩種方式都使用class關鍵字加大括號:
kotlin
復制代碼
// 類聲明 class Person {} // 類表達式 const TestPerson = class {}
注意:函數(shù)聲明和類聲明之間的一個重要區(qū)別在于,函數(shù)聲明會提升,類聲明不會。需要先聲明類,然后再訪問它,否則就會出現(xiàn)ReferenceError,如:
arduino
復制代碼
const test = new Person(); // ReferenceError: Person is not defined class Person {}
另一個跟函數(shù)聲明不同的地方是,函數(shù)受函數(shù)作用域限制,而類受塊作用域限制:
javascript
復制代碼
{ function FunctionDeclaration () {} class ClassDeclaration {} // 使用var 聲明 var VarClass = class {} // 使用let/const 聲明 let LetClass = class {} } console.log(FunctionDeclaration) // FunctionDeclaration () {} console.log(ClassDeclaration) // ReferenceError: ClassDeclaration is not defined console.log(VarClass) // class {} console.log(LetClass) // ReferenceError: letClass is not defined
class 類完全可以看成構造函數(shù)的另一種寫法,這種寫法可以讓對象的原型屬性和函數(shù)更加清晰。
javascript
復制代碼
class Person {} console.log(typeof Person) // function console.log(Person === Person.prototype.constructor) // true
上面代碼表明,類的數(shù)據(jù)類型就是函數(shù),類本身就指向構造函數(shù)。
constructor 方法是一個特殊的方法,這種方法用于創(chuàng)建和初始化一個由class創(chuàng)建的對象。通過 new 關鍵字生成對象實例時,自動會調(diào)用該方法。一個類只能擁有一個名為constructor構造函數(shù),不能出現(xiàn)多個,如果定義了多個constructor構造函數(shù),則將拋出 一個SyntaxError錯誤。如果沒有定義constructor構造函數(shù),class 會默認添加一個空的constructor構造函數(shù)。
kotlin
復制代碼
class Person {} // 等于 class Person { constructor () {} }
使用new操作符實例化Person的操作等于使用new調(diào)用其構造函數(shù)。唯一可感知的不同之處就是,JavaScript解釋器知道使用new和類意味著應該使用constructor函數(shù)進行實例化。
類必須使用new調(diào)用,否則會報錯。這是它跟普通構造函數(shù)的一個主要區(qū)別,后者不用new也可以執(zhí)行。
scss
復制代碼
class Person {} Person() // TypeError: Class constructor Test1 cannot be invoked without 'new'
使用new調(diào)用類的構造函數(shù)會執(zhí)行如下操作。
一起來看看下面例子:
javascript
復制代碼
class Person {} class Test1 { constructor () { console.log('Test1 初始化') } } class Test2 { constructor () { this.test = '通過初始化構造函數(shù)設置值' } } // 構造函數(shù)返回指定對象 const dataObj = { n: '自定義實例對象' } class Test3 { constructor () { this.test = '通過初始化構造函數(shù)設置值' return dataObj } } const a = new Person(); const b = new Test1(); // Test1 初始化 const c = new Test2(); console.log(c.test) // 通過初始化構造函數(shù)設置值 const d = new Test3(); d instanceof Test3; // false console.log(d) // { n: '自定義實例對象' }
類實例化時傳入的參數(shù)會用作構造函數(shù)的參數(shù)。如果不需要參數(shù),則類名后面的括號也是可選的:
javascript
復制代碼
class Person { constructor (...args) { console.log(args.length) } } class Test1 { constructor (test) { console.log(arguments.length) this.test = test || '默認值' } } // 不傳值 可以省略() const a = new Person // 0 const b = new Person('1', '2') // 2 const c = new Test1() // 0 console.log(c.test) // 默認值 const d = new Test1('傳入值') // 1 console.log(d.test) // 傳入值 const d = new Test1('1', '2', '3') // 3 console.log(d.test) // 1
與立即調(diào)用函數(shù)表達式相似,類也可以立即實例化:
arduino
復制代碼
const a = new class Person { constructor (text) { this.text = text console.log(text) } }('立即實例化類'); // 立即實例化類 console.log(a); // Person
類的語法可以非常方便地定義應該存在于實例上的成員、應該存在于原型上的成員,以及應該存在于類本身的成員。
實例的屬性除非顯式定義在其本身(即定義在this對象上),否則都是定義在原型上。
每個實例都對應一個唯一的成員對象,這意味著所有成員都不會在原型上共享:
javascript
復制代碼
class Person { constructor (x, y) { this.text = new Number(1); this.x = x this.y = y this.getText = () => {console.log(this.text)} } toString () { console.log(`${this.x}, ${this.y}`) } } const test1 = new Person('x', 'y'), test2 = new Person('x2', 'y2'); console.log(test1.getText()) // Number {1} console.log(test2.getText()) // Number {1} console.log(test1.x, test1.y) // x y console.log(test2.x, test2.y) // x2 y2 // console.log(test1.text === test2.text) // false // console.log(test1.getText === test2.getText) // false test1.text = '測試' console.log(test1.getText()) // 測試 console.log(test2.getText()) // Number {1} test1.toString() // x, y test2.toString() // x2, y2 test1.hasOwnProperty('x'); // true test1.hasOwnProperty('y'); // true test1.hasOwnProperty('getText'); // true test1.hasOwnProperty('toString'); // false test1.__proto__.hasOwnProperty('toString'); // true // 類的實例共享同一個原型對象 console.log(test1.__proto__ === test2.__proto__) // true // 也可以使用ES6提供的 Object.getPrototypeOf 來獲取prototype const test1Prototype = Object.getPrototypeOf(test1) test1Prototype.myName = '共享字段' // test2 中也是能獲取到 console.log(test2.myName) // 共享字段
x、y、text和getText都是實例對象test1自身的屬性,所以hasOwnProperty()方法返回true,而toString()是原型對象的屬性(因為定義在Person類),所以hasOwnProperty()方法返回false,這些都與 ES5 的行為保持一致。
類的所有實例共享同一個原型對象。這也意味著,可以通過實例的__proto__屬性或Object.getPrototypeOf方法獲取原型為“類”添加方法,這將會出現(xiàn)共享情況,必須相當謹慎,不推薦使用,因為這會改變“類”的原始定義,影響到所有實例。
類方法等同于對象屬性,因此可以使用字符串、符號或計算的值作為鍵:
scss
復制代碼
const symbolKey = Symbol('test') class Person { stringKey () { console.log('stringKey') } [symbolKey] () { console.log('symbolKey') } ['calculation' + '1'] () { console.log('calculation') } } const a = new Person(); a.stringKey() // stringKey a[symbolKey]() // symbolKey a.calculation1() // calculation
在 class 內(nèi)部可以使用 get 與 set 關鍵字,對某個屬性設置存值函數(shù)和取值函數(shù),攔截該屬性的存取行為。
kotlin
復制代碼
class Person { constructor (test) { this.test = test || '默認值' } get prop () { return this.test } set prop (value) { console.log(`setter prop value: ${value}`) this.test = value } } const p = new Person('1') p.prop // 1 p.prop = '2' // setter prop value: 2 p.prop // 2
set函數(shù)和get函數(shù)是設置在屬性的 Descriptor 對象上的,可以通過 Object.getOwnPrototyDescriptor 來獲取指定屬性的指定描述對象。
javascript
復制代碼
const descriptor = Object.getOwnPropertyDescriptor(Person.prototype, 'prop') 'get' in descriptor // true 'set' in descriptor // true
如果某個方法之前加上星號(*),就表示該方法是一個 Generator 函數(shù):
scss
復制代碼
class Person { constructor(...args) { this.args = args; } * generatorFun () { for (let arg of this.args) { yield arg; } } } const a = new Person(1,2,3,4); const generatorNext = a.generatorFun().next generatorNext() // {value: 1, done: false} generatorNext() // {value: 2, done: false} generatorNext() // {value: 3, done: false} generatorNext() // {value: 4, done: false} generatorNext() // {value: undefined, done: true}
類的方法內(nèi)部如果含有this,它默認指向類的實例。但是某些情況是指向當前執(zhí)行環(huán)境;
arduino
復制代碼
class Person { constructor () { this.text = '1' } getText () { console.log(this.text) } } const a = new Person() a.getText() // 1 const {getText} = a // this 指向為undefined class 默認嚴格模式 getText() // TypeError: Cannot read properties of undefined (reading 'text')
上面找不到 this 問題,this會指向該方法運行時所在的環(huán)境,因為 class 內(nèi)部是嚴格模式,所以 this 實際指向的是undefined。有兩個方法解決當前問題:
第一、構造方法中綁定this:
kotlin
復制代碼
class Person { constructor() { this.text = '1' this.getText = this.getText.bind(this) } getText () { console.log(this.text) } }
第二、使用箭頭函數(shù):
javascript
復制代碼
class Person { constructor() { this.text = '1' } getText = () => { console.log(this.text) } }
箭頭函數(shù)內(nèi)部的 this總是指向定義時所在的對象。
第三、使用proxy 在獲取方法的時候自動綁定this:
kotlin
復制代碼
function classProxy (target) { const map = new Map() // 讀取攔截配置, 只需要配置 get const hanlder = { get(target, key) { const val = Reflect.get(target, key) // 要獲取的是函數(shù)執(zhí)行, 如果不是函數(shù)就直接返回 val if (typeof val !== 'function') return val if (!map.has(val)) { // 使用 bind改變運行函數(shù)的 this為攔截的實例對象 map.set(val, val.bind(target)) } return map.get(val) } } const proxy = new Proxy(target, hanlder) return proxy } class Person { constructor (text) { this.text = text } getText () { console.log(this.text) return this.text } } const person = classProxy(new Person('test')) const { getText } = person getText() // test
靜態(tài)方法、靜態(tài)屬性及靜態(tài)代碼塊(proposal-class-static-block)都是使用 static關鍵字定義的屬性、方法或塊只能 class 自己用,不能通過實例繼承。
靜態(tài)方法中的this 指向的是 當前類,而不是指向?qū)嵗龑ο蟆lo態(tài)屬性是當前類自身的屬性。
javascript
復制代碼
class Person { static staticProp = 'Person靜態(tài)屬性' constructor () { // 通過 類名 獲取 console.log(`output: ${Person.staticProp}`) // 也可以通過 構造函數(shù)的屬性 this.constructor.staticFun1() } static staticFun1 () { this.staticFun2() console.log(`output: 靜態(tài)方法staticFun1,獲取Person靜態(tài)屬性 ==> ${Person.staticProp}`) } static staticFun2 () { console.log(`output: 靜態(tài)方法staticFun2,獲取靜態(tài)屬性 ==> ${this.staticProp}`) } } Person.staticProp // 靜態(tài)屬性 Person.staticFun1() // output: 靜態(tài)方法staticFun2,獲取靜態(tài)屬性 Person靜態(tài)屬性 // output: 靜態(tài)方法staticFun1,獲取Person靜態(tài)屬性 ==> Person靜態(tài)屬性 const a = new Person() // output: Person靜態(tài)屬性 a.staticProp // undefined a.staticFun1 // undefined a.staticFun2 // undefined // 通過其原型構造函數(shù)還是能獲取到 這些靜態(tài)屬性及方法 不推薦使用 // a.__proto__.constructor.staticProp // a.__proto__.constructor.staticFun1()
是在 Class 內(nèi)創(chuàng)建了一個塊狀作用域,這個作用域內(nèi)擁有訪問 Class 內(nèi)部私有變量的特權,在這個代碼塊內(nèi)部,可以通過 this 訪問 Class 所有成員變量,包括 # 私有變量,且這個塊狀作用域僅在引擎調(diào)用時初始化執(zhí)行一次 ,決解以前初始化靜態(tài)類屬性需要設置一個靜態(tài)變量初始化邏輯。
注意: static 變量或代碼塊都按順序執(zhí)行,父類優(yōu)先執(zhí)行,一個類中允許多個靜態(tài)代碼塊存在。
kotlin
復制代碼
class Person { static staticProp = '靜態(tài)屬性' static staticPropArr = [] static staticPropObj = {} static getStatic (name) { console.log(`獲取:${name}`, name && this[name]) return name && this[name] } static resetData (name, data) { name && (this[name] = data) console.log(`重置:${name}`, name && this[name]) } static { console.log('靜態(tài)代碼塊執(zhí)行'); this.getStatic('staticProp'); this.getStatic('staticPropArr'); this.getStatic('staticPropObj'); this.resetData('staticProp', '重置靜態(tài)屬性'); this.resetData('staticPropArr', ['重置靜態(tài)數(shù)組']); this.resetData('staticPropObj', { text: '重置靜態(tài)對象' }); this.staticPropObj.staticBlock1 = '代碼塊中直接設置' console.log(this.staticPropObj) } } /** * 靜態(tài)代碼塊執(zhí)行 獲取:staticProp 靜態(tài)屬性 獲取:staticPropArr [] 獲取:staticPropObj {} 重置:staticProp 重置靜態(tài)屬性 重置:staticPropArr ['重置靜態(tài)數(shù)組'] 重置:staticPropObj {text: '重置靜態(tài)對象'} {text: '重置靜態(tài)對象', staticBlock1: '代碼塊中直接設置'} */
上面代碼中可以看出,static 關鍵字后面不跟變量,而是直接跟一個代碼塊,就是 class static block 語法的特征,在這個代碼塊內(nèi)部,可以通過 this 訪問 Class 所有成員變量,包括 # 私有變量。
在這里提前使用一下私有變量,理論上 class 私有變量外部是訪問不了的,但是有了靜態(tài)代碼塊( *class-static-block *)之后,我們可以將私有屬性暴露給外部變量:
javascript
復制代碼
let privateValue export class Person { #value constructor(x) { this.#value = x } static { privateValue = (obj) => obj.#x; } } export function getPrivateValue (obj) { return privateValue(obj) } // 在另一個文件中 import { Person, getPrivateValue } from 'xxx' const a = new Person('私有變量') getPrivateValue(a) // 私有變量
其實class-static-block本質(zhì)上并沒有增加新功能,我們完全可以用普通靜態(tài)變量代替,只是寫起來很不自然,所以這個特性可以理解為對缺陷的補充,或者是語法完善,個人認為現(xiàn)在越來越像java。
私有屬性和私有方法,是只能在類的內(nèi)部訪問的方法和屬性,外部不能訪問,不可以直接通過 Class 實例來引用,其定義方式只需要在方法或?qū)傩郧懊嫣砑?。
私有屬性:
arduino
復制代碼
class Person { #privateVar1; #privateVar2 = '默認值'; constructor (text) { this.#privateVar1 = text || '--' console.log(this.#privateVar1) } getPrivateData1 (key) { // 這里是獲取不了的 console.log('傳入key來獲取私有變量:', this[key]) console.log('獲取私有變量', this.#privateVar2, this.#privateVar1) } static staticGetPrivateData (person, key) { console.log('靜態(tài)方法獲取私有變量:', person.#privateVar2, person.#privateVar1) // 下面是獲取不到 console.log('靜態(tài)方法傳入key來獲取私有變量:', person[key]) } } const a = new Person() // 不傳 默認 -- // output: -- a.getPrivateData1('#privateVar1') // output: 傳入key來獲取私有變量:undefined // output: 獲取私有變量: 默認值 -- // 使用靜態(tài)方法 Person.staticGetPrivateData(a, '#privateVar1') // output: 靜態(tài)方法獲取私有變量: 默認值 -- // output: 靜態(tài)方法傳入key來獲取私有變量:undefined
從上面代碼中我們可以看到,私有變量是只能內(nèi)部讀取或?qū)懭耄荒芡ㄟ^動態(tài)key讀取(外部調(diào)用就會報錯)
注意:在class 中 公共屬性 test 與 #test 是兩個完全不同的值;
私有方法:
arduino
復制代碼
class Person { #private; constructor () { this.#private = '私有變量' this.#methods() // 調(diào)用私有方法 } #methods () { console.log('私有方法#methods:', this.#private) } static #staticMethods (person) { if (person) { console.log('靜態(tài)私有方法#staticMethods person獲取值', person.#private) person.#methods() } } init1 () { this.#methods() console.log('使用this') Person.#staticMethods(this) } init2 (person) { if (person) { console.log('使用傳入實例') Person.#staticMethods(person) } } } const a = new Person() // output: 私有方法#methods: 私有變量 // a.#methods() SyntaxError // a['#methods']() TypeError: a.#methods is not a function a.init1() // output: 私有方法#methods: 私有變量 // output: 使用this // output: 靜態(tài)私有方法#staticMethods person獲取值 私有變量 // output: 私有方法#methods: 私有變量 a.init2(a) // output: 使用傳入實例 // output: 靜態(tài)私有方法#staticMethods person獲取值 私有變量 // output: 私有方法#methods: 私有變量
從上面代碼中我們可以看到,私有方法只能內(nèi)部調(diào)用,在外部調(diào)用就會報錯。
使用 extends 關鍵字,讓子類繼承父類的屬性和方法。
javascript
復制代碼
class Person { num = 1 text = 'person' getNum = () => console.log(this.num, this) addNum () { console.log(++this.num, this) } } // 繼承 class Child extends Person { constructor () { super() this.getText() } getText = () => console.log(this.text, this) } const a = new Child() // output: person Child {} console.log(a instanceof Child) // output: true console.log(a instanceof Person) // output: true a.getText() // output: person Child {} a.getNum() // output: 1 Child {} a.addNum() // output: 2 Child {} a.getNum() // output: 2 Child {} a.text // person a.num // 2
從上面代碼中,我們可以看出Child 類 繼承了 Person 的屬性及方法,在Child 中也是可以調(diào)用Person的方法及屬性,注意 this 的值會反映調(diào)用相應方法的實例或者類。子類中(Child)如果設置了 constructor 方法 就必須調(diào)用 super() ,否則就會出現(xiàn)新建實例時報錯,如果沒有 constructor 構造函數(shù),在實例化繼承類時會調(diào)用 super() ,而且會傳入所有傳給繼承類的參數(shù)(后面會詳細講解)。
arduino
復制代碼
class Person { static staticText = 'staticText'; #private = 'private' static staticMethods1 (person) { console.log('staticMethods1', this) person.#privateMethods() } #privateMethods () { console.log('#privateMethods', this) } } // 使用表達式格式 也是可以使用 extends 繼承 const Child = class extends Person { methods () { console.log('methods', Child.staticText) } } const a = new Child() a.methods() // output: methods staticText Child.staticMethods1(a) // output: staticMethods1 class Child {} // output: #privateMethods Child {} Person.staticMethods1(a) // output: staticMethods1 class Person {} // output: #privateMethods Child {}
使用表達式格式 也是可以使用 extends 繼承,類 的靜態(tài)方法與屬性是可以繼承的,其私有屬性及方法是不能繼承的,可以從繼承的共有方法與靜態(tài)方法 中獲取其私有屬性或調(diào)用其私有方法。
super 關鍵字可以作函數(shù)使用,也可以作對象使用,但是其只能在繼承類中使用,且只能在繼承類的constructor 構造函數(shù)、實例方法和靜態(tài)方法中使用。作為函數(shù)時是在 繼承類的constructor 構造函數(shù)中使用,根據(jù)要求如果繼承類中定義了constructor構造函數(shù)就必須要調(diào)用super方法(調(diào)用父類的constructor),否則就會報錯。
scala
復制代碼
class Person {} class Child extends Person { constructor () { // 如果不調(diào)用 super() 就會報錯 // ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor super() // 調(diào)用父級的constructor console.log(this) // Child {} } }
注意: constructor() 中必須super() 頂部首段執(zhí)行代碼,否則也是一樣報錯;
在使用 super() 時應該注意下面幾個問題:
作者:前端農(nóng)民晨曦
鏈接:https://juejin.cn/post/7098891689955164168
a0這是css的最簡單命名,在css的樣式中我總是糾結如何去命名,時間就浪費在這里面了,干脆就不命名算了,所有css的class都用.a(數(shù)字)命名。
這樣弄的話,我期待的是,我對每一個標簽寫一個樣式,樣式完成后自動去命名,匹配之前相似的樣式完成命名。當然,修改的時候執(zhí)行同樣的操作,如果樣式有對應類名則替換,沒有則添加。
在標簽中,徹底拋棄style屬性,在標簽的class屬性中永遠只有一個類名。整個web項目必須只有一個.css文件。
而這些,需要一個工具,更人性化的工具。
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。