亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入理解JavaScript和TypeScript中的class

 更新時(shí)間:2018年04月22日 15:28:26   作者:misaky  
class 聲明創(chuàng)建一個(gè)基于原型繼承的具有給定名稱的新類,下面這篇文章主要給大家介紹了關(guān)于JavaScript和TypeScript中class的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下。

前言

對于一個(gè)前端開發(fā)者來說,很少用到 class ,因?yàn)樵?JavaScript 中更多的是 函數(shù)式 編程,抬手就是一個(gè) function,幾乎不見 class 或 new 的蹤影。所以 設(shè)計(jì)模式 也是大多數(shù)前端開發(fā)者的一個(gè)短板。

最近在學(xué)習(xí) Angular 的過程中發(fā)現(xiàn)其大量的運(yùn)用了 class,不得不佩服,Angular 確實(shí)是一個(gè)優(yōu)秀的、值得深入研究的 框架。

本文將簡單的介紹一下 JavaScript 和 TypeScript 中的 class。

基本概念

在介紹 class 之前,要先介紹一些基本的概念。

1、靜態(tài)成員

類自身的成員,可以繼承,但實(shí)例無法訪問,一般多見于工具類,比如在jQuery時(shí)代最常見的 $.ajax ,ajax 便是 $ 的靜態(tài)方法,使用方便,不需要再通過 new 或者函數(shù)調(diào)用的得到一個(gè)新實(shí)例。

2、私有成員

類內(nèi)部的成員,一般是不能繼承的,只能在內(nèi)部使用,實(shí)例無法訪問,有一點(diǎn)點(diǎn)像閉包內(nèi)部的變量,但是還是一定的差別,目前 JavaScript 無法直接定義私有成員,只能通過其它方式輔助實(shí)現(xiàn)。

3、getter/setter

存取器屬性,當(dāng)我們訪問或者修改一個(gè)實(shí)例的屬性的時(shí)候,我們可通過存取器屬性攔截這兩個(gè)操作,從而做一些其它的事情,vue正是通過這個(gè)api來實(shí)現(xiàn)對數(shù)據(jù)變化的追蹤。

4、實(shí)例成員

指 new 出來的實(shí)例所具有的成員,可以被繼承,也是通過這個(gè)特性實(shí)現(xiàn)了代碼的復(fù)用。

5、抽象類,抽象方法

抽象類指不可以被實(shí)例化的類,通過 new 關(guān)鍵字調(diào)用會報(bào)錯(cuò),一般都被設(shè)計(jì)成父類。

抽象方法,只提供方法的名稱,參數(shù)和返回值,不負(fù)責(zé)實(shí)現(xiàn),具體的實(shí)現(xiàn)由子類去完成,如果一個(gè)子類繼承于抽象類,那么這個(gè)子類必須實(shí)現(xiàn)父類所有的抽象方法,否則會報(bào)錯(cuò)。

這兩個(gè)概念在 JavaScript 都無法直接實(shí)現(xiàn),但在 TypeScript 或 其它面向?qū)ο笳Z言中可以輕松實(shí)現(xiàn),另外這個(gè)特性也是用于實(shí)現(xiàn) 多態(tài) 的重要手段。

案例介紹

為了更好的介紹 class,本文將采用三個(gè) 類 來做例子,分別是 Person、Chinese、American。從字面上可以很快的知道: Person 是 父類(基類) ,Chinese 和 American 是 子類(派生類) 。

Person 有 name、age、gender 三個(gè)屬性,sayHello 方法和 fullName 存取器屬性。同時(shí) Person 還有一些 靜態(tài)成員 和 私有成員 ,由于實(shí)在太難想例子了,所以就用 foo、bar、x、y、z 這些來代替吧。

作為子類的 Chinese 和 American 繼承了 Person 的實(shí)例成員和靜態(tài)成員。同時(shí)它們自身也有一些自己的方法和屬性:

Chinese 有 kungfu 屬性,會習(xí)武 martial。

American 有 twitter,還可以 sendTwitter。

接下來我們就分別使用 JavaScript 和 TypeScript 來實(shí)現(xiàn)這個(gè)案例。

JavaScript 中的 class

JavaScript 中的 class 要分開說,在 ES6 中提供了兩個(gè)關(guān)鍵字 class 和 extends ,雖然它們只是語法糖,底層還是再利用 prototype 實(shí)現(xiàn)繼承的,但是不能否認(rèn),這中寫法確實(shí)讓代碼更清晰,更易讀。

ES6 中的 class

class Person {
 // #x = '私有屬性x';
 // static x = '靜態(tài)屬性x';
 // name;
 // age;
 // gender;

 // 上面的寫法還在提案中,并沒有成為正式標(biāo)準(zhǔn),不過變化的可能性已經(jīng)不大了。
 // 順便吐槽一下,用 # 表示私有成員,真的是很無語.

 /**
  * Person的靜態(tài)方法,可以被子類繼承
  * 可以通過 this 訪問靜態(tài)成員
  */
 static foo() {
  console.log(`類 ${this.name} 有一個(gè) ${this.x}`);
 }

 constructor(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
 }

 /**
  * 數(shù)據(jù)存儲器,可以訪問實(shí)例成員,子類的實(shí)例可以繼承
  * 以通過 this 訪問實(shí)例成員
  */
 get fullName() {
  const suffix = this.gender === '男' ? '先生' : '女士';
  return this.name + suffix;
 }

 set fullName(value) {
  console.log(`你已改名為 ${value} `);
 }

 /**
  * Person的實(shí)例方法,可以被子類的實(shí)例繼承
  * 可以通過 this 訪問實(shí)例成員
  */
 sayHello() {
  console.log(`你好我是 ${this.fullName} ,我 ${this.age} 歲了`);
 }
}
Person.x = '靜態(tài)屬性x';
class Chinese extends Person {
 static bar() {
  console.log(`類 ${this.name} 的父類是 ${super.name}`);
  super.foo();
 }

 constructor(name, age, gender, kungfu) {
  super(name, age, gender);
  this.kungfu = kungfu;
 }

 martial() {
  console.log(`${this.name} 正在修煉 ${this.kungfu} `);
 }
}
class American extends Person {

 // static y = '靜態(tài)屬性y';

 static bar() {
  console.log(`類 ${this.name} 有自己的 ${this.y} ,還繼承了父類 ${super.name} 的 ${super.x}`);
 }

 constructor(name, age, gender, twitter) {
  super(name, age, gender);
  this.twitter = twitter;
 }

 sendTwitter(msg) {
  console.log(`${this.name} : `);
  console.log(` ${msg}`);
 }
}
American.y = '靜態(tài)屬性y';
Person.x;  // 靜態(tài)屬性x
Person.foo(); // 類 Person 有一個(gè) 靜態(tài)屬性x

Chinese.x;  // 靜態(tài)屬性x
Chinese.foo(); // 類 Chinese 有一個(gè) 靜態(tài)屬性x
Chinese.bar(); // 類 Chinese 的父類是 Person

American.x;  // 靜態(tài)屬性x
American.y;  // '靜態(tài)屬性y
American.foo(); // 類 American 有一個(gè) 靜態(tài)屬性x
American.bar(); // 類 American 有自己的 靜態(tài)屬性y ,還繼承了父類 Person 的 靜態(tài)屬性x

const p = new Person('Lucy', 20, '女');
const c = new Chinese('韓梅梅', 18, '女', '詠春拳');
const a = new American('特朗普', 72, '男', 'Donald J. Trump');

c.sayHello(); // 你好我是 韓梅梅女士 ,我 18 歲了
c.martial(); // 韓梅梅 正在修煉 詠春拳 
a.sayHello(); // 你好我是 特朗普先生 ,我 72 歲了
a.sendTwitter('推特治國'); // 特朗普 : 推特治國

ES6 之前的 class

ES5 的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對象 this,

然后再將父類的方法添加到 this 上面 Parent.apply(this) 。

ES6 的繼承機(jī)制完全不同,實(shí)質(zhì)是先創(chuàng)造父類的實(shí)例對象 this,所以必須先調(diào)用 super 方法,

然后再用子類的構(gòu)造函數(shù)修改this。

為了實(shí)現(xiàn)繼承,我們需要先實(shí)現(xiàn)一個(gè) extendsClass 函數(shù),它的作用是讓子類繼承父類的靜態(tài)成員和實(shí)例成員。

function extendsClass(parent, child) {
 // 防止子類和父類相同名稱的成員被父類覆蓋
 var flag = false;

 // 繼承靜態(tài)成員
 for (var k in parent) {
  flag = k in child;
  if (!flag) {
   child[k] = parent[k];
  }
 }

 // 繼承父類prototype上的成員
 // 用一個(gè)新的構(gòu)造函數(shù)切斷父類和子類之間的數(shù)據(jù)共享
 var F = function () { }
 F.prototype = parent.prototype;
 var o = new F();
 for (var k in o) {
  flag = k in child.prototype;
  if (!flag) {
   child.prototype[k] = o[k];
  }
 }
}
function Person(name, age, gender) {
 this.name = name;
 this.age = age;
 this.gender = this.gender;
 // 如果將 getter/setter 寫在 prototype 會獲取不到
 Object.defineProperty(this, 'fullName', {
  get: function () {
   var suffix = this.gender === '男' ? '先生' : '女士';
   return this.name + suffix;
  },
  set: function () {
   console.log('你已改名為 ' + value + ' ');
  },
 });
}

Person.x = '靜態(tài)屬性x';
Person.foo = function () {
 console.log('類 ' + this.name + ' 有一個(gè) ' + this.x);
}

Person.prototype = {
 constructor: Person,
 // get fullName() { },
 // set fullName(value) { },
 sayHello: function () {
  console.log('你好我是 ' + this.fullName + ' ,我 ' + this.age + ' 了');
 },
};
function Chinese(name, age, gender, kungfu) {
 // 用call改變this指向,實(shí)現(xiàn)繼承父類的實(shí)例屬性
 Person.call(this, name, age, gender);
 this.kungfu = kungfu;
}

Chinese.bar = function () {
 console.log('類 ' + this.name + ' 的父類是 ' + Person.name);
 Person.foo();
}

Chinese.prototype = {
 constructor: Chinese,
 martial: function () {
  console.log(this.name + ' 正在修煉 ' + this.kungfu + ' ');
 }
};

extendsClass(Person, Chinese);
function American(name, age, gender, twitter) {
 Person.call(this, name, age, gender);
 this.twitter = twitter;
}

American.y = '靜態(tài)屬性y';
American.bar = function () {
 console.log('類 ' + this.name + ' 有自己的 ' + this.y + ' ,還繼承了父類 ' + Person.name + ' 的 ' + Person.x);
}

American.prototype = {
 constructor: American,
 sendTwitter: function (msg) {
  console.log(this.name + ' : ');
  console.log(' ' + msg);
 }
};

extendsClass(Person, American);

TypeScript 中的 class

講完了 JavaScript 中的類,還是沒有用到 抽象類,抽象方法,私有方法這三個(gè)概念,由于 JavaScript 語言的局限性,想要實(shí)現(xiàn)這三種概念是很困難的,但是在 TypeScript 可以輕松的實(shí)現(xiàn)這一特性。

首先我們稍微修改一下例子中的描述,Person 是抽象類,因?yàn)橐粋€(gè)正常的人肯定是有國籍的,Person 的 sayHello 方法是抽象方法,因?yàn)槊總€(gè)國家打招呼的方式不一樣。另外一個(gè)人的性別是只能讀取,不能修改的,且是確定的是,不是男生就是女生,所以還要借助一下枚舉。

enum Gender {
 female = 0,
 male = 1
};
abstract class Person {
 private x: string = '私有屬性x,子類和實(shí)例都無法訪問';
 protected y: string = '私有屬性y,子類可以訪問,實(shí)例無法訪問';

 name: string;
 public age: number;
 public readonly gender: Gender; // 用關(guān)鍵字 readonly 表明這是一個(gè)只讀屬性

 public static x: string = '靜態(tài)屬性x';
 public static foo() {
  console.log(`類 ${this.name} 有一個(gè) ${this.x}`);
 }

 constructor(name: string, age: number, gender: Gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
 }

 get fullName(): string {
  const suffix = this.gender === 1 ? '先生' : '女士';
  return this.name + suffix;
 }

 set FullName(value: string) {
  console.log(`你已改名為 ${value} `);
 }

 // 抽象方法,具體實(shí)現(xiàn)交由子類完成
 abstract sayHello(): void;
}
class Chinese extends Person {
 public kungfu: string;
 public static bar() {
  console.log(`類 ${this.name} 的父類是 ${super.name}`);
  super.foo();
 }

 public constructor(name: string, age: number, gender: Gender, kungfu: string) {
  super(name, age, gender);
  this.kungfu = kungfu;
 }

 public sayHello(): void {
  console.log(`你好我是 ${this.fullName} ,我 ${this.age} 歲了`);
 }

 public martial() {
  console.log(`${this.name} 正在修煉 ${this.kungfu} `);
 }
}
class American extends Person {
 static y = '靜態(tài)屬性y';
 public static bar() {
  console.log(`類 ${this.name} 有自己的 ${this.y} ,還繼承了父類 ${super.name} 的 ${super.x}`);
 }

 public twitter: string;

 public constructor(name: string, age: number, gender: Gender, twitter: string) {
  super(name, age, gender);
  this.twitter = twitter;
 }

 public sayHello(): void {
  console.log(`Hello, I am ${this.fullName} , I'm ${this.age} years old`);
 }

 public sendTwitter(msg: string): void {
  console.log(`${this.name} : `);
  console.log(` ${msg}`);
 }
}
Person.x;  // 靜態(tài)屬性x
Person.foo(); // 類 Person 有一個(gè) 靜態(tài)屬性x

Chinese.x;  // 靜態(tài)屬性x
Chinese.foo(); // 類 Chinese 有一個(gè) 靜態(tài)屬性x
Chinese.bar(); // 類 Chinese 的父類是 Person

American.x;  // 靜態(tài)屬性x
American.y;  // '靜態(tài)屬性y
American.foo(); // 類 American 有一個(gè) 靜態(tài)屬性x
American.bar(); // 類 American 有自己的 靜態(tài)屬性y ,還繼承了父類 Person 的 靜態(tài)屬性x

const c: Chinese = new Chinese('韓梅梅', 18, Gender.female, '詠春拳');
const a: American = new American('特朗普', 72, Gender.male, 'Donald J. Trump');

c.sayHello(); // 你好我是 韓梅梅女士 ,我 18 歲了
c.martial(); // 韓梅梅 正在修煉 詠春拳 
a.sayHello(); // Hello, I am 特朗普先生 , I'm 72 years old
a.sendTwitter('推特治國'); // 特朗普 : 推特治國

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • 微信小程序使用slider實(shí)現(xiàn)音頻進(jìn)度條

    微信小程序使用slider實(shí)現(xiàn)音頻進(jìn)度條

    這篇文章主要為大家詳細(xì)介紹了微信小程序使用slider實(shí)現(xiàn)音頻進(jìn)度條,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-06-06
  • JS實(shí)現(xiàn)的文件拖拽上傳功能示例

    JS實(shí)現(xiàn)的文件拖拽上傳功能示例

    這篇文章主要介紹了JS實(shí)現(xiàn)的文件拖拽上傳功能,涉及javascript事件觸發(fā)、頁面元素屬性動態(tài)修改等相關(guān)操作技巧,需要的朋友可以參考下
    2018-05-05
  • JavaScript的History API使搜索引擎抓取AJAX內(nèi)容

    JavaScript的History API使搜索引擎抓取AJAX內(nèi)容

    這篇文章主要介紹了JavaScript的History API使搜索引擎抓取AJAX內(nèi)容 的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • 微信小程序頁面與組件之間信息傳遞與函數(shù)調(diào)用

    微信小程序頁面與組件之間信息傳遞與函數(shù)調(diào)用

    不管是vue還是react中,都在強(qiáng)調(diào)組件思想,所以下面這篇文章主要給大家介紹了關(guān)于微信小程序頁面與組件之間信息傳遞與函數(shù)調(diào)用的相關(guān)資料,需要的朋友可以參考下
    2021-05-05
  • 前端必會的圖片懶加載(三種方式)

    前端必會的圖片懶加載(三種方式)

    在我們訪問一個(gè)圖片展示比較多的網(wǎng)頁時(shí),加載速度慢很多時(shí)候正是因?yàn)閳D片多導(dǎo)致,本文主要介紹了前端必會的圖片懶加載(三種方式),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • JS HTML5實(shí)現(xiàn)拖拽移動列表效果

    JS HTML5實(shí)現(xiàn)拖拽移動列表效果

    這篇文章主要為大家詳細(xì)介紹了JS HTML5實(shí)現(xiàn)拖拽移動列表效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-07-07
  • 詳解javascript 變量提升(Hoisting)

    詳解javascript 變量提升(Hoisting)

    這篇文章主要介紹了詳解javascript 變量提升(Hoisting),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-03-03
  • 原生js+canvas實(shí)現(xiàn)驗(yàn)證碼

    原生js+canvas實(shí)現(xiàn)驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了原生js+canvas實(shí)現(xiàn)驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖效果

    微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖效果

    滑塊拼圖(Slider?Puzzle)是一種經(jīng)典的智力游戲,通常由一個(gè)3x3或更大的格子組成,其中一個(gè)格子為空,玩家通過滑動拼圖塊來達(dá)到特定的圖案或順序,這篇文章主要介紹了微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖,需要的朋友可以參考下
    2024-08-08
  • js與C#進(jìn)行時(shí)間戳轉(zhuǎn)換

    js與C#進(jìn)行時(shí)間戳轉(zhuǎn)換

    最近在做一個(gè)項(xiàng)目,需要JS時(shí)間戳轉(zhuǎn)成C#里的時(shí)間,再把C#里的時(shí)間戳轉(zhuǎn)成JS的時(shí)間,就仔細(xì)研究了下js與C#進(jìn)行轉(zhuǎn)換的注意要點(diǎn),這里記錄下來,有需要的小伙伴自己拿走。
    2014-11-11

最新評論