이번에는 JS+TypeScript에서 클래스를 사용하는 방법과 JS+TypeScript에서 클래스를 사용할 때 주의사항에 대해 설명하겠습니다. 다음은 실제 사례입니다.
머리말
프런트엔드 개발자의 경우 클래스는 거의 사용되지 않습니다. 왜냐하면 JavaScript는 함수형 프로그래밍에 가깝고 클래스나 신규의 흔적이 거의 없기 때문입니다. 따라서 디자인 패턴은 대부분의 프론트엔드 개발자들의 단점이기도 합니다.
최근 Angular를 배우면서 많은 클래스를 사용한다는 것을 알게 되었어요. Angular는 정말 심층적으로 공부할 가치가 있는 훌륭한 프레임워크입니다.
이 글에서는 JavaScript와 TypeScript의 클래스를 간략하게 소개합니다.
기본 개념
수업 소개에 앞서 몇 가지 기본 개념을 먼저 소개해야 합니다.
1. 정적 멤버
클래스 자체의 멤버는 상속될 수 있지만 인스턴스에 액세스할 수는 없습니다. 일반적으로 jQuery 시대에 가장 일반적인 $.ajax와 같은 도구 클래스에서 찾을 수 있습니다. $. 사용하기 쉽고 new 또는 함수 호출을 통해 새 인스턴스를 가져와야 합니다.
2. 비공개 멤버
클래스 내부의 멤버는 일반적으로 상속될 수 없으며 내부적으로만 사용할 수 있습니다. 인스턴스는 클로저 내부의 변수와 약간 비슷하지만 현재 JavaScript에서는 직접적으로 사용할 수 없습니다. Private 멤버는 다른 방법을 통해서만 구현할 수 있습니다.
3. Getter/setter
접속자 속성. 인스턴스의 속성에 액세스하거나 수정할 때 Vue는 다른 작업을 수행하기 위해 이 두 작업을 가로챌 수 있습니다. 이 API는 데이터 변경을 추적하는 데 사용됩니다. .
4. 인스턴스 멤버
new로 생성된 인스턴스의 멤버를 말하며, 이 기능을 사용하면 코드 재사용도 가능합니다.
5. 추상 클래스, 추상 메서드
추상 클래스는 인스턴스화할 수 없는 클래스를 의미하며 일반적으로 부모 클래스로 설계됩니다.
추상 메서드는 메서드의 이름, 매개 변수 및 반환 값만 제공하며 구현에 대한 책임은 없습니다. 하위 클래스가 추상 클래스에서 상속하는 경우 하위 클래스는 모든 추상 메서드를 구현해야 합니다. 그렇지 않으면 오류가 보고됩니다.
이 두 개념 모두 JavaScript로 직접 구현할 수는 없지만 TypeScript나 다른 객체 지향 언어로 쉽게 구현할 수 있습니다. 또한 이 기능은 다형성을 달성하는 중요한 수단이기도 합니다.
케이스 소개
클래스를 더 잘 소개하기 위해 이 글에서는 Person, Chinese, American 세 가지 클래스를 예로 들어 설명하겠습니다. 리터럴을 통해 빠르게 알 수 있습니다. Person은 상위 클래스(기본 클래스)이고 Chinese와 American은 하위 클래스(파생 클래스)입니다.
Person에는 이름, 나이, 성별, sayHello 메소드 및 fullName 접근자 속성의 세 가지 속성이 있습니다. 동시에 Person에는 정적 멤버와 전용 멤버도 있습니다. 예를 생각하기가 너무 어렵기 때문에 대신 foo, bar, x, y, z를 사용하겠습니다.
중국과 미국은 하위 클래스로 Person의 인스턴스 멤버와 정적 멤버를 상속합니다. 동시에 그들은 자신만의 방법과 속성도 가지고 있습니다.
중국인은 쿵푸 속성을 갖고 있으며 무술을 연습할 수 있습니다.
미국인은 트위터가 있고 트위터로 보낼 수도 있습니다.
다음으로 JavaScript와 TypeScript를 사용하여 이 사례를 구현하겠습니다.
JavaScript의 Class
JavaScript의 Class는 별도로 논의해야 합니다. ES6은 단지 구문 설탕일 뿐이지만 하위 계층에서는 여전히 프로토타입을 사용하여 상속을 구현하지 못합니다. 이렇게 작성하면 코드가 더 명확해지고 읽기 쉬워집니다.
ES6의 클래스
class Person { // #x = '私有属性x'; // static x = '静态属性x'; // name; // age; // gender; // 上面的写法还在提案中,并没有成为正式标准,不过变化的可能性已经不大了。 // 顺便吐槽一下,用 # 表示私有成员,真的是很无语. /** * Person的静态方法,可以被子类继承 * 可以通过 this 访问静态成员 */ static foo() { console.log(`类 ${this.name} 有一个 ${this.x}`); } constructor(name, age, gender) { this.name = name; this.age = age; this.gender = gender; } /** * 数据存储器,可以访问实例成员,子类的实例可以继承 * 以通过 this 访问实例成员 */ get fullName() { const suffix = this.gender === '男' ? '先生' : '女士'; return this.name + suffix; } set fullName(value) { console.log(`你已改名为 ${value} `); } /** * Person的实例方法,可以被子类的实例继承 * 可以通过 this 访问实例成员 */ sayHello() { console.log(`你好我是 ${this.fullName} ,我 ${this.age} 岁了`); } } Person.x = '静态属性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 = '静态属性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 = '静态属性y'; Person.x; // 静态属性x Person.foo(); // 类 Person 有一个 静态属性x Chinese.x; // 静态属性x Chinese.foo(); // 类 Chinese 有一个 静态属性x Chinese.bar(); // 类 Chinese 的父类是 Person American.x; // 静态属性x American.y; // '静态属性y American.foo(); // 类 American 有一个 静态属性x American.bar(); // 类 American 有自己的 静态属性y ,还继承了父类 Person 的 静态属性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
ES5 이전 클래스의 상속은 본질적으로 먼저 서브클래스의 인스턴스 객체를 생성하고
부모 클래스의 메소드를 Parent.apply 위에 추가하는 것입니다( 이것).
ES6의 상속 메커니즘은 완전히 다릅니다. 먼저 상위 클래스의 인스턴스 객체 this를 생성하는 것이 핵심이므로 먼저 super 메소드를 호출한 다음
하위 클래스의 생성자를 사용하여 이를 수정해야 합니다.
为了实现继承,我们需要先实现一个 extendsClass 函数,它的作用是让子类继承父类的静态成员和实例成员。
function extendsClass(parent, child) { // 防止子类和父类相同名称的成员被父类覆盖 var flag = false; // 继承静态成员 for (var k in parent) { flag = k in child; if (!flag) { child[k] = parent[k]; } } // 继承父类prototype上的成员 // 用一个新的构造函数切断父类和子类之间的数据共享 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 = '静态属性x'; Person.foo = function () { console.log('类 ' + this.name + ' 有一个 ' + 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指向,实现继承父类的实例属性 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 = '静态属性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 中的类,还是没有用到 抽象类,抽象方法,私有方法这三个概念,由于 JavaScript 语言的局限性,想要实现这三种概念是很困难的,但是在 TypeScript 可以轻松的实现这一特性。
首先我们稍微修改一下例子中的描述,Person 是抽象类,因为一个正常的人肯定是有国籍的,Person 的 sayHello 方法是抽象方法,因为每个国家打招呼的方式不一样。另外一个人的性别是只能读取,不能修改的,且是确定的是,不是男生就是女生,所以还要借助一下枚举。
enum Gender { female = 0, male = 1 };
abstract class Person { private x: string = '私有属性x,子类和实例都无法访问'; protected y: string = '私有属性y,子类可以访问,实例无法访问'; name: string; public age: number; public readonly gender: Gender; // 用关键字 readonly 表明这是一个只读属性 public static x: string = '静态属性x'; public static foo() { console.log(`类 ${this.name} 有一个 ${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} `); } // 抽象方法,具体实现交由子类完成 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 = '静态属性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; // 静态属性x Person.foo(); // 类 Person 有一个 静态属性x Chinese.x; // 静态属性x Chinese.foo(); // 类 Chinese 有一个 静态属性x Chinese.bar(); // 类 Chinese 的父类是 Person American.x; // 静态属性x American.y; // '静态属性y American.foo(); // 类 American 有一个 静态属性x American.bar(); // 类 American 有自己的 静态属性y ,还继承了父类 Person 的 静态属性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('推特治国'); // 特朗普 : 推特治国
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 JS+TypeScript에서 클래스를 사용하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!