在这一章中介绍的 class 类,希望同学们可以在上一章节中 复习下构造函数、原型、原型链等基础知识

一、TypeScript 中的类

1、先来举个例子:

class Persons {
name: any;
age: number | undefined;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
getName(): void {
console.log(`${this.name}今年已经${this.age}岁了`);
}
} let p11 = new Persons("za", 123);
console.log(p11.getName()); // za今年已经123岁了
  • 转换成 ES5 的代码后:
var Persons = /** @class */ (function() {
function Persons(name, age) {
this.name = name;
this.age = age;
}
Persons.prototype.getName = function() {
console.log(
this.name + "\u4ECA\u5E74\u5DF2\u7ECF" + this.age + "\u5C81\u4E86"
);
};
return Persons;
})();
var p11 = new Persons("za", 123);
console.log(p11.getName()); // za今年已经123岁了

2、这里和我们使用 Es6 中的 class 有一些差别

// javascript 中 class 的定义
class An {
constructor(name) {
this.name = name;
}
getName() {
console.log(this.name);
}
}
var a = new An("zz");
a.getName(); // zz

3、差异在于,我们需要去定义 constructor 构造函数中传入的数据参数的类型

二、TypeScript 中类的继承

class Animal {
name: string | undefined;
food: string;
constructor(name: string, food: string) {
this.name = name;
this.food = food;
}
eat() {
console.log(`${this.name}吃${this.food}`);
}
} class Cat extends Animal {
constructor(name: string, food: string) {
super(name, food);
}
jump() {
console.log(`${this.name}正在跳`);
}
} let xiaohhua = new Cat("xiaohua", "猫粮");
console.log(xiaohhua.eat()); // xiaohua吃猫粮
console.log(xiaohhua.jump()); // xiaohua正在跳

这里和 ES6 中的 class 继承内容基本上没什么出入

三、TypeScript 中公共,私有与受保护的修饰符

这里的修饰符是对类中对 属性和方法的类型的定义

3-1、属性的 public

不定义的类心的话,默认就是 public 类型

class Animals {
public name: string | undefined;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(`${this.name}哇`);
}
}

转换成 es5 代码

"use strict";
var Animals = /** @class */ (function() {
function Animals(name) {
this.name = name;
}
Animals.prototype.eat = function() {
console.log(this.name + "\u54C7");
};
return Animals;
})();
// 和没定义之前一样

3-2、属性的 private

当成员被标记成 private 时,它就不能在声明它的类的外部访问

class Animal2 {
private name: string | undefined;
constructor(name: string) {
this.name = name;
}
eat() {
console.log(`${this.name}哇`);
}
} var a = new Animal2("private");
a.name = "123"; // 报错,name 属性只能在 Animal2 内部使用
new Animal2("private").name = "432"; // 报错: 属性“name”为私有属性,只能在类“Animal2”中访问。

3-3、属性的 protected

当成员被标记成 protected 时,它就不能在声明它的类的外部访问,但是该类的子类可以访问

class Person2 {
protected name: string;
constructor(name: string) {
this.name = name;
}
} class exPerson extends Person2 {
public age: number;
constructor(age: number, name: string) {
super(name);
this.age = age;
this.name = name;
}
public getInfo() {
console.log(`${this.name}哈哈哈哈${this.age}`);
}
} let ps = new exPerson(123, "za"); // 派生类可以继承 protected 属性,但是 ps.name = "zz"; // 报错 外部无法直接访问
console.log(ps); // { name: 'za', age: 123 }

构造函数也能够被 设置成 protected 属性

class Person22 {
protected name: string;
protected constructor(name: string) {
this.name = name;
}
} class exPerson2 extends Person2 {
public age: number;
constructor(age: number, name: string) {
super(name);
this.age = age;
this.name = name;
}
public getInfo() {
console.log(`${this.name}哈哈哈哈${this.age}`);
}
} let exp = new exPerson2(21, "exp-name");
let per22 = new Person22("zs"); // 报错 类“Person22”的构造函数是受保护的,仅可在类声明中访问

3-4、readonly 修饰符

使用 readonly 关键字将属性设置为只读的。 只读属性必须在声明时或构造函数里被初始化

class octPers {
readonly name: string;
readonly age: number = 8;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
} let ns = new octPers("zz", 123);
console.log("---1", ns);
ns.age = 456; // 报错 Cannot assign to 'age' because it is a read-only property.
console.log("---2", ns); // 这里会执行什么内容呢?

四、TypeScript 中 静态方法

这里所谓的静态方法,其实就是将方法直接定义在了 构造函数对象上,只有构造函数本身才能去使用它,任何其他都无法使用(包括它的 派生类)

class staticPerson {
public name: string;
public age: number = 8;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
static getName1() {
console.log("---static-getName---", this);
}
protected getName(): void {
console.log("---protected-getName---", this);
}
} let ress = new staticPerson("zzs", 123);
console.log("---instancing getName", staticPerson.getName1()); // 属性“getName”受保护,只能在类“staticPerson”及其子类中访问。

五、TypeScript 中 继承与多态

这里面其实更多的是 JS 的继承与多态,我们以 ES5 和 ES6 分别对继承和多态进行对比

5-1 ES5 中是如何实现 继承的?

这里我们想想继承,到底是继承什么?如何继承?为什么要继承?

5-1-1 通过类式继承

类的方式,其核心在于将 子类的 prototype 指向了 父类的实例,这样的话,子类的实例的 __proto__ 指向子类的 prototype, 然而 子类的 prototype 被赋予了 父类的实例。我们制作一个简单的图,来说明一下这里如何实现的继承。

var SuperClass = function(name) {
var id = 1;
this.name = name;
this.work = function() {
console.log(this.name + 'in SuperClass');
};
};
SuperClass.prototype.getSuperName = function() {
return this.name;
}; var SubClass = function() {
this.getSubName = function() {
console.log('this is subname');
};
}; SubClass.prototype = new SuperClass('superClass');
var sub = new SubClass(); // 这样有缺点么? 当然有,下面我们来通过例子来说明一下

这种继承的方式的缺点、

var SuperClass = function(name) {
var id = 1;
this.name = name;
this.todo = [1, 2, 3, 4];
this.work = function() {
console.log(this.name + 'in SuperClass');
};
};
SuperClass.prototype.getSuperName = function() {
return this.name;
}; var SubClass = function() {
this.getSubName = function() {
console.log('this is subname');
};
}; SubClass.prototype = new SuperClass('superClass');
var sub = new SubClass();
sub.todo.push('subClass name');
var sub2 = new SubClass();
console.log(sub2.todo); // [ 1, 2, 3, 4, 'subClass name']
// 这里是缺陷一,父类属性会被实例子类修改、污染 console.log(sub.name); //superClass
console.log(sub2.name); //superClass // 子类的实例只能有一个name,这很显然也是不够灵活的,这里就是缺陷二

这里因为子类实例对象1,对于父类共有属性进行了修改,导致子类实例对象2 的对应属性受到了污染。那有没有什么办法可以避免这种污染呢?当然是有的,后面我们会介绍到的。

5-1-2 通过构造函数继承
// 声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig', 'cat'];
this.color = color;
} // 添加原型方法
Animal.prototype.eat = function(food) {
console.log(food);
}; // 声明子类
function Dog() {
Animal.apply(this, arguments);
// 这一步的操作就是改变 Animal 方法的上下文,然后让 Dog 也具备了 父类构造函数内的属性和方法
} var dog1 = new Dog('blue'); // dog1.color -> blue
var dog2 = new Dog('red'); // dog2.color -> red dog1.type.push('haha');
console.log(dog2.type); // [ 'pig', 'cat' ]

我没看到 dog1 修改了继承自父类的属性 type ,但是 dog2 的 type 属性并为被影响到。原因就是我们实例化的时候,创建的实例对象的指针指向的位置是不同的,所以对应的 __proto__ 指向的是 不同的子类构造函数的 prototype。可能会比较绕口,但是本质就是 new 操作生成了2个不同的对象,各自有各自的原型属性,互不干扰。

但是上面也有一个缺陷就是,子类没办法继承到父类原型上的方法和属性

那聪明的前端开发者们,就想到了 集合前2者的优势,进行了 组合式继承。

5-1-3 组合式继承
// 声明父类
function Animal(color) {
this.name = 'animal';
this.type = ['pig', 'cat'];
this.color = color;
} // 添加原型方法
Animal.prototype.eat = function(food) {
console.log(food);
}; // 声明子类
function Dog() {
Animal.apply(this, arguments);
// 这一步的操作就是改变 Animal 方法的上下文,然后让 Dog 也具备了
// 父类构造函数内的属性和方法
}
Dog.prototype = new Animal('Animal Color'); var dog1 = new Dog();
console.log((dog1.color = 'dog1.name'));
var dog2 = new Dog(); console.log(dog2.color); // undefined 这里为什么 dog2.color 是 undefined 而不是 'dog1.name' 呢?
因为,我们子类的构造函数,已经继承了 父类的构造函数内部的属性和方法,然后,在实例我们 子类的时候,子类的实例对象就会有先从本身的对象中去寻找 color 属性。
当找到对应属性的时候,无论是否有值,都会优先返回 实例化对象本身的属性,而不再需要从原型链中查找对应属性。

5-2 ES6 中是如何实现 继承的?

这里我们想想继承,到底是继承什么?如何继承?为什么要继承?

5-2-1 ES6 的继承方式
class Animal {
constructor(name) {
this.name = name;
}
eat(food) {
console.log(`${this.name}吃${food}`);
}
} class Dog extends Animal {
constructor(name) {
super(name);
this.name = name;
}
run() {
console.log('小狗泡泡跑');
}
} let dog1 = new Dog('小狗');
let dog2 = new Dog('小花');
console.log(dog1.name); // 小狗
console.log(dog2.name); // 小花 dog1.__proto__ === Dog.prototype // true
Dog.__proto__ === Animal // true 这里 Dog 的 __proto__ 指向的是 Animal 这个类 因为 Animal 这个类中的 constructor 就是原来的构造函数, 其中剩下的方法、属性都是 prototype 上的公共方法与属性。是可以被子类继承

六、总结

这里全篇文章又总结了下 JS 中继承的原理以及一些我们平时可能忽略的问题,这里就相当于在 学习 ts 之前,带着大家再一起复习一下。好了,本篇文章就先到这里了。


GitHub 地址:(欢迎 star 、欢迎推荐 : )

《前端之路》 - TypeScript(四)class 篇

《前端之路》- TypeScript (四) class 中各类属性、方法,抽象类、多态的更多相关文章

  1. js中__proto__, property, prototype, 对象自身属性方法和原型中的属性方法的区别

    __proto__: 这个属性是实例对象的属性,每个实例对象都有一个__proto__属性,这个属性指向实例化该实例的构造函数的原型对象(prototype). proterty:这个方法是对象的属性 ...

  2. Python之路(第四十六篇)多种方法实现python线程池(threadpool模块\multiprocessing.dummy模块\concurrent.futures模块)

    一.线程池 很久(python2.6)之前python没有官方的线程池模块,只有第三方的threadpool模块, 之后再python2.6加入了multiprocessing.dummy 作为可以使 ...

  3. typescript静态属性,静态方法,抽象类,多态

    /* 1.vscode配置自动编译 1.第一步 tsc --inti 生成tsconfig.json 改 "outDir": "./js", 2.第二步 任务 ...

  4. SSM-SpringMVC-10:SpringMVC中PropertiesMethodNameResolver属性方法名称解析器

    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 上次的以继承MultiActionController可以实现一个处理器中多个处理方法,但是局限出来了,他们的 ...

  5. H5 网站支付宝支付(前端部分)包含微信浏览器中的处理方法。

    手机网站唤起支付宝支付: H5 网站实现支付宝支付是一个很常见的需求: 实现方式主要是在后台配置和预支付, 前端需要做的就是唤起 支付宝App 然后就可以输入密码支付. 这个其实难度很低, 主要就是在 ...

  6. ASP.NET + MVC5 入门完整教程四---MVC 中使用扩展方法

    https://blog.csdn.net/qq_21419015/article/details/80433640 1.示例项目准备1)项目创建新建一个项目,命名为LanguageFeatures ...

  7. 《前端之路》- TypeScript (三) ES5 中实现继承、类以及原理

    目录 一.先讲讲 ES5 中构造函数(类)静态方法和多态 1-1 JS 中原型以及原型链 例子一 1-2 JS 中原型以及原型链中,我们常见的 constructor.prototype.**prot ...

  8. 《前端之路》- TypeScript(二) 函数篇

    目录 一.定义函数方法 二.定义函数传参 三.可选传参 四.默认传参 五.传递剩余参数 六.函数重载 七.箭头函数 八.总结 一.定义函数方法 在 es5 中定时函数的方法有 命名函数和函数表达式(匿 ...

  9. 《前端之路》之 Javascript 模块化管理的来世今生

    目录 第二章 - 04: Javascript 模块化管理的来世今生 一.什么是模块化开发 1-1.模块化第一阶段 1-2.封装到对象 1-3. 对象的优化 二.模块化管理的发展历程 2-1.Comm ...

随机推荐

  1. C++如何保留2位小数输出

    cout<<setiosflags(ios::);//需要头文件#include <iomanip> 然后再输出实数类型变量即可以保留2位小数输出了,当然你要保留三位小数,se ...

  2. 支持向量机 SVM - Wenjing

    概念 将向量映射到一个更高维的空间里,在这个空间里建立有一个最大间隔超平面.在分开数据的超平面的两边建有两个互相平行的超平面,分隔超平面使两个平行超平面的距离最大化.假定平行超平面间的距离或差距越大, ...

  3. Train Problem II (卡特兰数+大数问题)

    卡特兰数: Catalan数 原理: 令h(1)=1,h(0)=1,catalan数满足递归式: h(n)= h(1)*h(n-1) + h(2)*h(n-2) + ... + h(n-1)h(1) ...

  4. zctf 2016 android writeup - Jieming的博客

    本文为2016年zctf中android的writeup. 首先点我下载题目.使用jeb反编译,对username和password进行部分验证后,再将username+password及一个数据库查 ...

  5. 面试的绝招(V1.0)

    <软件自动化测试开发>出版了 测试开发公开课培训大讲堂 微信公众号:测试开发社区 测试开发QQ群:173172133 咨询QQ:7980068 咨询微信:zouhui1003it

  6. LeetCode~1033.移动石子直到连续

    1033.移动石子直到连续 三枚石子放置在数轴上,位置分别为 a,b,c. 每一回合,我们假设这三枚石子当前分别位于位置 x, y, z 且 x < y < z.从位置 x 或者是位置 z ...

  7. numpy.random模块用法总结

    from numpy import random numpy.random.uniform(low=0.0, high=1.0, size=None) 生出size个符合均分布的浮点数,取值范围为[l ...

  8. 初识Arduino

    Arduino是一款便捷灵活.方便上手的开源电子原型平台.包含硬件(各种型号的Arduino板)和软件(Arduino IDE).由一个欧洲开发团队于2005年冬季开发.其成员包括Massimo Ba ...

  9. 快速上手百度大脑EasyDL专业版·物体检测模型(附代码)

    作者:才能我浪费991.    简介:1.1.    什么是EasyDL专业版EasyDL专业版是EasyDL在2019年10月下旬全新推出的针对AI初学者或者AI专业工程师的企业用户及开发者推出的A ...

  10. HTML与CSS 开发常用语义化命名

    一.布局❤️ header 头部/页眉:index 首页/索引:logo 标志:nav/sub_nav 导航/子导航:banner 横幅广告:main/content 主体/内容:container/ ...