当前位置: 首页 > wzjs >正文

海南高端网站建设定制知春路网站建设

海南高端网站建设定制,知春路网站建设,合肥大型网站设计,wordpress 短代码 if is single我怕时间太快, 不能把你看仔细。 我怕时间太慢, 日夜担心失去你。 TypeScript提供了对ES2015中引入的 class 关键词的完全支持。 与其他JavaScript语言功能一样,TypeScript增加了类型注释和其他语法,允许你表达类和其他类型之…

 我怕时间太快,

不能把你看仔细。

我怕时间太慢,

日夜担心失去你。


 

TypeScript提供了对ES2015中引入的 class 关键词的完全支持。

与其他JavaScript语言功能一样,TypeScript增加了类型注释和其他语法,允许你表达类和其他类型之间 的关系。

类成员

这里有一个最基本的类——一个空的类:

class Point {}

这个类还不是很有用,所以我们开始添加一些成员。

类属性

在一个类上声明字段,创建一个公共的可写属性

class Point {x: number;y: number;
}const pt = new Point();
pt.x = 0;
pt.y = 0;

与其他位置一样,类型注解是可选的,但如果不指定,将是一个隐含的 any 类型。

字段也可以有初始化器;这些初始化器将在类被实例化时自动运行。

class Point {x = 0;y = 0;
}const pt = new Point();
// Prints 0, 0
console.log(`${pt.x}, ${pt.y}`);

就像 const 、 let 和 var 一样,一个类属性的初始化器将被用来推断其类型。

const pt = new Point();
pt.x = "0";

 strictPropertyInitialization

strictPropertyInitialization 设置控制是否需要在构造函数中初始化类字段。

class BadGreeter {name: string;
}

 

 

class GoodGreeter {name: string;constructor() {this.name = "hello";}

请注意,该字段需要在构造函数本身中初始化。TypeScript不会分析你从构造函数中调用的方法来检测 初始化,因为派生类可能会覆盖这些方法而无法初始化成员。

如果你打算通过构造函数以外的方式来确定初始化一个字段(例如,也许一个外部库为你填充了你的类 的一部分),你可以使用确定的赋值断言操作符 !。

class OKGreeter {// 没有初始化,但没报错。name!: string;
}

readonly

字段的前缀可以是 readonly 修饰符。这可以防止在构造函数之外对该字段进行赋值。

class Greeter {readonly name: string = "world";constructor(otherName?: string) {if (otherName !== undefined) {this.name = otherName;}}err() {this.name = "not ok";}
}
const g = new Greeter();
g.name = "also not ok";

构造器

 类构造函数与函数非常相似。你可以添加带有类型注释的参数、默认值和重载:

class Point {x: number;y: number;// 带默认值的正常签名constructor(x = 0, y = 0) {this.x = x;this.y = y;}
}
class Point {// 重载constructor(x: number, y: string);constructor(s: string);constructor(xs: any, y?: any) {// ...}
}

类的构造函数签名和函数签名之间只有一些区别: 

  • 构造函数不能有类型参数--这属于外层类的声明
  •  构造函数不能有返回类型注释——类的实例类型总是被返回的。

Super 调用

就像在JavaScript中一样,如果你有一个基类,在使用任何 this. 成员之前,你需要在构造器主体中调 用 super(); 。

class Base {k = 4;
}class Derived extends Base {constructor() {// 在ES5中打印一个错误的值;在ES6中抛出异常。console.log(this.k);super();}
}

在JavaScript中,忘记调用 super 是一个很容易犯的错误,但TypeScript会在必要时告诉你。 

方法

一个类上的函数属性被称为方法。方法可以使用与函数和构造函数相同的所有类型注释。

class Point {x = 10;y = 10;scale(n: number): void {this.x *= n;this.y *= n;}
}

除了标准的类型注解,TypeScript并没有为方法添加其他新的东西。

请注意,在一个方法体中,仍然必须通过 this 访问字段和其他方法。方法体中的非限定名称将总是指 代包围范围内的东西。

let x: number = 0;class C {x: string = "hello";m() {// 这是在试图修改第1行的'x',而不是类属性。x = "world";}
}

Getters / Setters

类也可以有访问器:

class C {_length = 0;get length() {return this._length;}set length(value) {this._length = value;}
}

TypeScript对访问器有一些特殊的推理规则:

  • 如果存在 get ,但没有 set ,则该属性自动是只读的
  • 如果没有指定 setter 参数的类型,它将从 getter 的返回类型中推断出来
  • 访问器和设置器必须有相同的成员可见性

 从TypeScript 4.3开始,可以有不同类型的访问器用于获取和设置。

class Thing {_size = 0;get size(): number {return this._size;}set size(value: string | number | boolean) {let num = Number(value);// 不允许NaN、Infinity等if (!Number.isFinite(num)) {this._size = 0;return;}this._size = num;}
}

索引签名

类可以声明索引签名;这些签名的作用与其他对象类型的索引签名相同。

class MyClass {[s: string]: boolean | ((s: string) => boolean);check(s: string) {return this[s] as boolean;}
}

因为索引签名类型需要同时捕获方法的类型,所以要有用地使用这些类型并不容易。一般来说,最好将 索引数据存储在另一个地方,而不是在类实例本身。

类继承

像其他具有面向对象特性的语言一样,JavaScript中的类可以继承自基类。

implements 子句

你可以使用一个 implements 子句来检查一个类,是否满足了一个特定的接口。如果一个类不能正确地 实现它,就会发出一个错误。

interface Pingable {ping(): void;
}class Sonar implements Pingable {ping() {console.log("ping!");}
}class Ball implements Pingable {pong() {console.log("pong!");}
}

类也可以实现多个接口,例如 class C implements A, B {

重要的是要明白, implements 子句只是检查类是否可以被当作接口类型来对待。它根本不会改变类的 类型或其方法。一个常见的错误来源是认为 implements 子句会改变类的类型--它不会!它不会 

interface Checkable {check(name: string): boolean;
}class NameChecker implements Checkable {check(s) {// any:注意这里没有错误return s.toLowercse() === "ok";}
}

在这个例子中,我们也许期望 s 的类型会受到 check 的 name: string 参数的影响。事实并非如此--实 现子句并没有改变类主体的检查方式或其类型的推断。

同样地,实现一个带有可选属性的接口并不能创建该属性。

interface A {x: number;y?: number;
}
class C implements A {x = 0;
}
const c = new C();
c.y = 10;

extends 子句

 类可以从基类中扩展出来。派生类拥有其基类的所有属性和方法,也可以定义额外的成员。

class Animal {move() {console.log("Moving along!");}
}class Dog extends Animal {woof(times: number) {for (let i = 0; i < times; i++) {console.log("woof!");}}
}const d = new Dog();
// 基类的类方法
d.move();
// 派生的类方法
d.woof(3);

重写方法

派生类也可以覆盖基类的一个字段或属性。你可以使用 super. 语法来访问基类方法。注意,因为 JavaScript类是一个简单的查找对象,没有 "超级字段 "的概念。

TypeScript强制要求派生类总是其基类的一个子类型。


例如,这里有一个合法的方法来覆盖一个方法。

class Base {greet() {console.log("Hello, world!");}
}class Derived extends Base {greet(name?: string) {if (name === undefined) {super.greet();} else {console.log(`Hello, ${name.toUpperCase()}`);}}
}const d = new Derived();
d.greet();
d.greet("reader");

派生类遵循其基类契约是很重要的。请记住,通过基类引用来引用派生类实例是非常常见的(而且总是 合法的!)。

// 通过基类引用对派生实例进行取别名
const b: Base = d;
// 没问题
b.greet();

如果 Derived 没有遵守Base的约定怎么办?

class Base {greet() {console.log("Hello, world!");}
}class Derived extends Base {// 使这个参数成为必需的greet(name: string) {console.log(`Hello, ${name.toUpperCase()}`);}
}

如果我们不顾错误编译这段代码,这个样本就会崩溃:  

const b: Base = new Derived();
// 崩溃,因为 "名称 "将是 undefined。
b.greet();

初始化顺序

 在某些情况下,JavaScript类的初始化顺序可能会令人惊讶。让我们考虑一下这段代码:

class Base {name = "base";constructor() {console.log("My name is " + this.name);}
}class Derived extends Base {name = "derived";
}// 打印 "base", 而不是 "derived"
const d = new Derived();

这里发生了什么?

按照JavaScript的定义,类初始化的顺序是:

  • 基类的字段被初始化
  • 基类构造函数运行
  • 派生类的字段被初始化
  • 派生类构造函数运行

这意味着基类构造函数在自己的构造函数中看到了自己的name值,因为派生类的字段初始化还没有运行。

继承内置类型

在ES2015中,返回对象的构造函数隐含地替代了 super(...) 的任何调用者的 this 的值。生成的构造 函数代码有必要捕获 super(...) 的任何潜在返回值并将其替换为 this 。

因此,子类化 Error 、 Array 等可能不再像预期那样工作。这是由于 Error 、 Array 等的构造函数使 用ECMAScript 6的 new.target 来调整原型链;然而,在ECMAScript 5中调用构造函数时,没有办法确 保 new.target 的值。其他的下级编译器一般默认有同样的限制。

对于一个像下面这样的子类:

class MsgError extends Error {constructor(m: string) {super(m);}sayHello() {return "hello " + this.message;}
}

你可能会发现:

方法在构造这些子类所返回的对象上可能是未定义的,所以调用 sayHello 会导致错误。

 instanceof 将在子类的实例和它们的实例之间被打破,所以 (new MsgError())instanceof MsgError 将返回 false 。

你可以在任何 super(...) 调用后立即手动调整原型。

class MsgError extends Error {constructor(m: string) {super(m);// 明确地设置原型。Object.setPrototypeOf(this, MsgError.prototype);}sayHello() {return "hello " + this.message;}
}

然而, MsgError 的任何子类也必须手动设置原型。对于不支持 Object.setPrototypeOf 的运行时, 你可以使用 __proto__ 来代替。 

不幸的是,这些变通方法在 Internet Explorer 10 和更早的版本上不起作用。我们可以手动将原型中 的方法复制到实例本身(例如 MsgError.prototype 到 this ),但是原型链本身不能被修复。

成员的可见性

public

类成员的默认可见性是公共( public )的。一个公共( public )成员可以在任何地方被访问。

class Greeter {public greet() {console.log("hi!");}
}
const g = new Greeter();
g.greet();

因为 public 已经是默认的可见性修饰符,所以你永远不需要在类成员上写它,但为了风格/可读性的原 因,可能会选择这样做。

protected

受保护的( protected )成员只对它们所声明的类的子类可见。

class Greeter {public greet() {console.log("Hello, " + this.getName());}protected getName() {return "hi";}
}class SpecialGreeter extends Greeter {public howdy() {// 在此可以访问受保护的成员console.log("Howdy, " + this.getName());}
}
const g = new SpecialGreeter();
g.greet(); // 没有问题
g.getName(); // 无权访问

受保护成员的暴露

 派生类需要遵循它们的基类契约,但可以选择公开具有更多能力的基类的子类型。这包括将受保护的成 员变成公开。

class Base {protected m = 10;
}
class Derived extends Base {// 没有修饰符,所以默认为'公共'('public')m = 15;
}
const d = new Derived();
console.log(d.m); // OK

private

private 和 protected 一样,但不允许从子类中访问该成员。

class Base {private x = 0;
}
const b = new Base();
// 不能从类外访问
console.log(b.x);
class Base {private x = 0;
}
const b = new Base();
class Derived extends Base {showX() {// 不能在子类中访问console.log(this.x);}
}

因为私有( private )成员对派生类是不可见的,所以派生类不能增加其可见性。

静态成员

类可以有静态成员。这些成员并不与类的特定实例相关联。它们可以通过类的构造函数对象本身来访问。

class MyClass {static x = 0;static printX() {console.log(MyClass.x);}
}
console.log(MyClass.x);
MyClass.printX();

静态成员也可以使用相同的 public 、 protected 和 private 可见性修饰符。

class MyClass {private static x = 0;
}
console.log(MyClass.x);

静态成员也会被继承。

class Base {static getGreeting() {return "Hello world";}
}
class Derived extends Base {myGreeting = Derived.getGreeting();
}

特殊静态名称

一般来说,从函数原型覆盖属性是不安全的/不可能的。因为类本身就是可以用 new 调用的函数,所以某 些静态名称不能使用。像 name 、 length 和 call 这样的函数属性,定义为静态成员是无效的。

为什么没有静态类?

TypeScript(和JavaScript)没有像C#和Java那样有一个叫做静态类的结构。

这些结构体的存在,只是因为这些语言强制所有的数据和函数都在一个类里面;因为这个限制在 TypeScript中不存在,所以不需要它们。一个只有一个实例的类,在JavaScript/TypeScript中通常只是 表示为一个普通的对象。

例如,我们不需要TypeScript中的 "静态类 "语法,因为一个普通的对象(甚至是顶级函数)也可以完成 这个工作。

// 不需要 "static" class
class MyStaticClass {static doSomething() {}
}// 首选 (备选 1)
function doSomething() {}// 首选 (备选 2)
const MyHelperObject = {dosomething() {},
};

类里的 static区块

静态块允许你写一串有自己作用域的语句,可以访问包含类中的私有字段。这意味着我们可以用写语句 的所有能力来写初始化代码,不泄露变量,并能完全访问我们类的内部结构。

class Foo {static #count = 0;get count() {return Foo.#count;}static {try {const lastInstances = {length: 100};Foo.#count += lastInstances.length;}catch {}}
}

泛型类

类,和接口一样,可以是泛型的。当一个泛型类用new实例化时,其类型参数的推断方式与函数调用的 方式相同。

class Box<Type> {contents: Type;constructor(value: Type) {this.contents = value;}
}// const b: Box<string>
const b = new Box("hello!");

类可以像接口一样使用通用约束和默认值。

  • 静态成员中的类型参数

这段代码是不合法的,可能并不明显,为什么呢?

class Box<Type> {// 静态成员不能引用类的类型参数。static defaultValue: Type;
}
// Box<string>.defaultValue = 'hello'
// console.log(Box<number>.defaultValue)

请记住,类型总是被完全擦除的! 在运行时,只有一个Box.defaultValue属性。这意味着设置 Box.defaultValue(如果有可能的话)也会改变Box.defaultValue,这可不是什么好事。一个泛型类的 静态成员永远不能引用该类的类型参数。

类运行时中的this

重要的是要记住,TypeScript并没有改变JavaScript的运行时行为,而JavaScript的运行时行为偶尔很奇特。

比如,JavaScript对这一点的处理确实是不寻常的:

class MyClass {name = "MyClass";getName() {return this.name;}
}
const c = new MyClass();
const obj = {name: "obj",getName: c.getName,
};// 输出 "obj", 而不是 "MyClass"
console.log(obj.getName());

默认情况下,函数内this的值取决于函数的调用方式。在这个例子中,因为函数是通过obj引 用调用的,所以它的this值是obj而不是类实例。

在ts中有两个方法来防止和减轻这个错误:


箭头函数

如果你有一个经常会被调用的函数,失去了它的 this 上下文,那么使用一个箭头函数而不是方法定义 是有意义的。

class MyClass {name = "MyClass";getName = () => {return this.name;};
}
const c = new MyClass();
const g = c.getName;
// 输出 "MyClass"
console.log(g());

这有一些权衡:

  • this 值保证在运行时是正确的,即使是没有经过TypeScript检查的代码也是如此。
  • 这将使用更多的内存,因为每个类实例将有它自己的副本,每个函数都是这样定义的。
  • 你不能在派生类中使用 super.getName ,因为在原型链中没有入口可以获取基类方法。

this 参数

在方法或函数定义中,一个名为 this 的初始参数在TypeScript中具有特殊的意义。这些参数在编译过程 中会被删除。

// 带有 "this" 参数的 TypeScript 输入
function fn(this: SomeType, x: number) {/* ... */
}
// 编译后的JavaScript结果
function fn(x) {/* ... */
}

TypeScript检查调用带有 this 参数的函数,是否在正确的上下文中进行。我们可以不使用箭头函数,而 是在方法定义中添加一个 this 参数,以静态地确保方法被正确调用。

class MyClass {name = "MyClass";getName(this: MyClass) {return this.name;}
}
const c = new MyClass();
// 正确
c.getName();// 错误
const g = c.getName;
console.log(g());

这种方法做出了与箭头函数方法相反的取舍:

  • JavaScript调用者仍然可能在不知不觉中错误地使用类方法
  • 每个类定义只有一个函数被分配,而不是每个类实例一个函数
  • 基类方法定义仍然可以通过 super 调用。

this类型

在类中,一个叫做 this 的特殊类型动态地指向当前类的类型。

class Box {  contents: string = "";  // (method) Box.set(value: string): this  set(value: string) {this.contents = value;return this;  }
}

在这里,TypeScript推断出 set 的返回类型是 this ,而不是 Box 。现在让我们做一个Box的子类:

class ClearableBox extends Box {clear() {this.contents = "";}
} 
const a = new ClearableBox();
// const b: ClearableBox
const b = a.set("hello");
console.log(b)

你也可以在参数类型注释中使用 this :

class Box {content: string = "";  sameAs(other: this) {return other.content === this.content;}
}
const box = new Box()
console.log(box.sameAs(box))

这与其他写法不同:Box,如果你有一个派生类,它的 sameAs 方法现在只接受该同一派生类的其他实例。

class Box {content: string = ""; sameAs(other: this) { return other.content === this.content; }
} 
class DerivedBox extends Box {otherContent: string = "?"; 
} 
const base = new Box(); 
const derived = new DerivedBox(); 
derived.sameAs(base);

基于类型守卫的this

你可以在类和接口的方法的返回位置使用 this is Type 。当与类型缩小混合时(例如if语句),目标 对象的类型将被缩小到指定的Type。

class FileSystemObject {isFile(): this is FileRep {return this instanceof FileRep;}isDirectory(): this is Directory {return this instanceof Directory;}isNetworked(): this is Networked & this {return this.networked;}constructor(public path: string, private networked: boolean) {}
}
class FileRep extends FileSystemObject {constructor(path: string, public content: string) {super(path, false);}
}
class Directory extends FileSystemObject {children: FileSystemObject[];
}
interface Networked {host: string;
}
const fso: FileSystemObject = new FileRep("foo/bar.txt", "foo");
if (fso.isFile()) { // const fso: FileRep  fso.content;
} else if (fso.isDirectory()) {  // const fso: Directory  fso.children;
} else if (fso.isNetworked()) {  // const fso: Networked & FileSystemObject  fso.host;
}

基于 this 的类型保护的一个常见用例,是允许对一个特定字段进行懒惰验证。例如,这种情况下,当 hasValue 被验证为真时,就会从框内持有的值中删除一个未定义值。

class Box <T> {value?: T;hasValue(): this is { value: T} {return this.value !== undefined;}
}
const box = new Box();
box.value = "Gameboy"; 
// (property) Box<unknown>.value?: unknownbox.value;
if (box.hasValue()) { // (property) value: unknownbox.value;
}

参数属性

TypeScript提供了特殊的语法,可以将构造函数参数变成具有相同名称和值的类属性。这些被称为参数 属性,通过在构造函数参数前加上可见性修饰符 public 、 private 、 protected 或 readonly 中的一 个来创建。由此产生的字段会得到这些修饰符。

class Params {constructor(public readonly x: number, protected y: number, private z: number) 
{ // No body necessary  }
}
const a = new Params(1, 2, 3);
// (property) Params.x: number
console.log(a.x);
console.log(a.z);

类表达式

类表达式与类声明非常相似。唯一真正的区别是,类表达式不需要一个名字,尽管我们可以通过它们最 终绑定的任何标识符来引用它们。

const someClass = class<Type> {content: Type;  constructor(value: Type) {    this.content = value;  }
}; 
// const m: someClass<string>
const m = new someClass("Hello, world");

抽象类和成员

TypeScript中的类、方法和字段可以是抽象的。

一个抽象的方法或抽象的字段是一个没有提供实现的方法或字段。这些成员必须存在于一个抽象类中, 不能直接实例化。

抽象类的作用是作为子类的基类,实现所有的抽象成员。当一个类没有任何抽象成员时,我们就说它是具体的。

让我们看一个例子:

abstract class Base {abstract getName(): string;printName() {console.log("Hello, " + this.getName());}
}
const b = new Base();

我们不能用 new 来实例化 Base ,因为它是抽象的。相反,我们需要创建一个派生类并实现抽象成员。

class Derived extends Base {getName() {return "world";}
}
const d = new Derived();
d.printName();

类之间的关系

在大多数情况下,TypeScript中的类在结构上与其他类型相同,是可以比较的。

例如,这两个类可以互相替代使用,因为它们是相同的:

class Point1 {x = 0;y = 0;
}
class Point2 {x = 0;y = 0;
} 
// 正确
const p: Point1 = new Point2();

同样地,即使没有明确的继承,类之间的子类型关系也是存在的:

class Person {name: string;age: number;
}
class Employee {name: string;age: number;salary: number;
} 
// 正确
const p: Person = new Employee();

这听起来很简单,但有几种情况似乎比其他情况更奇怪。

空的类没有成员。在一个结构化类型系统中,一个没有成员的类型通常是其他任何东西的超类型。所以 如果你写了一个空类(不要!),任何东西都可以用来代替它。

class Empty {}
function fn(x: Empty) { // 不能用'x'做任何事
}
// 以下调用均可
!fn(window);
fn({});
fn(fn);

 

谢谢啦 

http://www.dtcms.com/wzjs/573775.html

相关文章:

  • 免费自助建网站软件邯郸本地网站
  • 宁波手机建站模板网页设计网站开发需要哪些知识
  • 百度网盘怎么做网站2023网页游戏大全
  • 网站开发网站制作海尔网站的建设目标
  • 庆阳网站设计 贝壳下拉新网站快速收录
  • 定制型网站制作价格旅游公司网站建设
  • 上海最专业的网站设计制wordpress的文件结构
  • 电商网站 手续如何进行网站网站调试
  • 如何做网站美工flask 电影网站开发
  • 做一款小程序需要多少钱宁波正规seo推广公司
  • 玉溪网站开发做怎么网站
  • 企业为什么做网站系统南沙定制型网站建设
  • 高端企业网站开发深圳的互联网企业
  • 制作网站后台电子商务网络营销是什么
  • 网站广告布局无法进行网站备案
  • 湖南铁军工程建设有限公司官方网站yzipi主题wordpress
  • 长沙建网站联系电话宜城网站建设
  • 网站定制开发四大基本原则绵阳建设局网站皱劲松
  • 江西赣建建设监理网站哪个浏览器能打开那种网站
  • 安徽专业网站建设大全推荐暴雪游戏
  • 北京网站优化哪家好网站首页优化
  • 兰州建设一个网站多少钱泉州关键词自动排名
  • wordpress制作大型网站锦州网站优化
  • 龙岗网站建设哪家好为何建设银行的网站登不上去
  • 网站建设共享wordpress 会员聊天
  • 免费做国际网站申请个人网站有什么用
  • 虚拟空间网站ftp如何差异化同步如何搭建钓鱼网站
  • 郧阳网站建设如何网上注册公司流程
  • 南京做企业网站公司哪家好嘉兴模板建站平台
  • 可信网站认证费用建设网站定位分析