TypeScript 是面向对象的 JavaScript。而其中的类描述了所创建的对象共同的属性和方法。
传统的JavaScript程序使用函数和基于原型的继承来创建可重用的组件,但这对于熟悉使用面向对象方式的程序员来说有些棘手,因为他们用的是基于类的继承并且对象是从类构建出来的。
从ECMAScript 2015,也就是ECMAScript 6,JavaScript程序将可以使用这种基于类的面向对象方法。在TypeScript里允许开发者现在就使用这些特性,并且编译后的JavaScript可以在所有主流浏览器和平台上运行
什么是构造函数,构造函数作用是什么?
构造函数 ,是一种特殊的方法。主要用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。而TypeScript的构造函数用关键字constructor来实现。可以通过this(和java/C#一样代表对象实例的成员访问)关键字来访问当前类体中的属性和方法。
实例化是什么?
一般情况下,创建一个类后并不能直接的对属性和方法进行引用,必须对类进行实例化,即创建一个对象。TypeScript中用new 关键字创建对象。实例化后通过“.”来访问属性和方法
一、ts中类的定义
1. ES5的构造函数
function Cat(name,color) {
this.name=name;
this.color=color;
//this.type='动物';
//this.eat = function(){
// console.log('吃老鼠')
// }
}
//原型中
Cat.prototype.type='动物';
Cat.prototype.eat = function(){
console.log('吃老鼠')
};
var c1 = new Cat('小皮','白色');
2. ES6的构造函数
ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
constructor:类的构造函数,在类被实例化时仅被调用一次,类外部无法使用
class Cat {
constructor(name,color){
this.name=name;
this.color=color;
}
eat(){
console.log('吃老鼠')
}
};
var c2 = new Cat('小皮','白色');
2. TS的构造函数,需要添加类型
我们声明一个 Cat类。这个类有4个成员:一个叫做 name,color的属性,一个构造函数和一个 eat方法。
class Cat {
name:string;
color:string;
constructor(name:string,color:string){ //构造函数 实例化类的时候触发的方法
this.name=name;
this.color=color;
}
eat(){
console.log('吃老鼠')
}
};
var c2 = new Cat('大明','白色');
c2.eat();
最后一行,我们使用 new构造了 Cat类的一个实例。 它会调用之前定义的构造函数,创建一个 Cat类型的新对象,并执行构造函数初始化它。
3. 继承
ts中实现继承 extends、 super
在TypeScript里,我们可以使用常用的面向对象模式。 基于类的程序设计中一种最基本的模式是允许使用继承来扩展现有的类。
class Animal{
name:string;
color:string;
constructor(name:string,color:string){
this.name = name;
this.color = color;
}
say(){
console.log('喜欢吃肉');
}
}
class Dog extends Animal{
weight:string;
constructor(name:string,color:string){
super(name,color); //关键字 调用父类构造函数和方法
this.weight = '456'
}
}
var dog02 = new Dog('小花','红色');
这个例子展示了最基本的继承:类从基类中继承了属性和方法。 这里, Dog是一个 派生类(子类),它派生自 Animal 基类(父类),通过 extends关键字。
派生类通常被称作 子类,基类通常被称作 父类。
派生类包含了一个构造函数,它 必须调用 super(),即在构造函数里访问 this 的属性之前,我们一定要调用 super(),它会执行基类的构造函数。
4. 类的静态属性
静态成员,这些属性存在于类本身上面而不是类的实例上
通过关键字static 申明静态属性, 不需要实例化处理 可以直接通过类来调用
class Animal{
static uname='动物';
static eat(){
console.log('吃老鼠')
}
run(){
console.log('跑');
}
}
var a = new Animal()
a.eat() //error
Animal.eat();
5.修饰属性和方法
ts中三种修饰符 修饰属性和方法 public private protected
- public 公共的, 在当前类里面、 子类 、类外面都可以访问
- protected 保护类型
在当前类里面、子类里面可以访问 ,在类外部没法访问 - private 私有的 在当前类里面可以访问,子类、类外部都没法访问
- constructor:类的构造函数, 在类被实例化时仅被调用一次,类外部无法使用
属性如果不加修饰符 默认就是 公有 (public)
class Animal_01{
// public username:string;
//公共的 在类里面、 子类 、类外面都可以访问
// protected username:string;
//保护类型 在当前类里面、子类里面可以访问 ,在类外部没法访问
private username:string;
//私有的 在当前类里面可以访问,子类、类外部都没法访问
constructor(username:string){
this.username = username;
this.innerCall();
}
public eat():string{
return '吃老鼠';
}
innerCall(){
console.log('在类里面访问username:'+this.username) //在类里面
}
}
class Dog_01 extends Animal_01 {
age:string;
constructor(username:string){
super(username);
this.age= '124'
}
action():string{
console.log('在子类访问username:'+this.username)
return this.username; //在子类访问
}
}
var d1=new Dog_01('小狗');
d1.action() // 在类外部访问
console.log('在类外部访问username:'+d1.username); // 在类外部访问
总结: public:类内部,子类和外部都可引用; protected:只能有类的内部和它的子类访问 private:只能类内部访问;
6 typescript中的多态
多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现
多态属于继承
class Animal {
name:string;
constructor(name:string) {
this.name=name;
}
eat(){ //具体吃什么 ,不知道,具体吃什么?继承它的子类去实现 ,每一个子类的表现不一样
console.log('吃的方法')
}
}
class Dog extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃粮食'
}
}
class Cat extends Animal{
constructor(name:string){
super(name)
}
eat(){
return this.name+'吃老鼠'
}
}
7. typescript中的抽象类
它是提供其他类继承的基类,不能直接被实例化。 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
abstract抽象方法只能放在抽象类里面 抽象类和抽象方法用来定义标准 。 标准:Animal 这个类要求它的子类必须包含eat方法
//标准:
abstract class Animal{
public name:string;
constructor(name:string){
this.name=name;
}
abstract eat():any; //抽象方法不包含具体实现并且必须在派生类中实现。
run(){
console.log('其他方法可以不实现')
}
}
// var a=new Animal('猫类') /*错误的写法*/
class Dog extends Animal{
//抽象类的子类必须实现抽象类里面的抽象方法
constructor(name:any){
super(name)
}
eat(){
console.log(this.name+'吃粮食')
}
}
var d=new Dog('小花花');
d.eat();
命名空间
在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内 同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。
命名空间和模块的区别:
- 命名空间:内部模块,主要用于组织代码,避免命名冲突。
- 模 块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。
namespace A{
interface Animal {
name: string;
eat(): void;
}
export class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name} 在吃狗粮。`);
}
}
export class Cat implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name} 吃猫粮。`);
}
}
}
namespace B{
interface Animal {
name: string;
eat(): void;
}
export class Dog implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name} 在吃狗粮。`);
}
}
export class Cat implements Animal {
name: string;
constructor(theName: string) {
this.name = theName;
}
eat() {
console.log(`${this.name} 在吃猫粮。`);
}
}
}
var c=new B.Cat('小花');
c.eat();