TypeScript 快速上手及学习笔记
<p>TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript。</p><p>TypeScript可以在任何浏览器、任何计算机和任何操作系统上运行,并且是开源的。</p>
<h3>什么是 TypeScript</h3>
<p>TypeScript 是 JavaScript 的、<span style="color: rgba(255, 0, 0, 1)">带有类型</span>的<span style="color: rgba(255, 0, 0, 1)">超集</span>,并且能够<span style="color: rgba(255, 0, 0, 1)">编译</span>成普通的 JavaScript。</p>
<p>编译:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014104434383-1064948244.png"></p>
<p>类型:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014110409571-267242702.png"></p>
<p>超集:</p>
<p>TypeScript 本身支持所有 JavaScript 的语法,并在此基础上添加了额外的功能和特性。</p>
<p>TypeScript 是由微软开发的一款开源的编程语言。</p>
<p>TypeScript 是 Javascript 的超集,遵循最新的 ES6、Es5 规范。TypeScript 扩展了 JavaScript 的语法。</p>
<p>TypeScript 更像后端 java、C#这样的面向对象语言,可以让 js 开发大型企业项目。</p>
<p>谷歌也在大力支持 Typescript 的推广,谷歌的 angular2.x+就是基于 Typescript 语法。</p>
<p>最新的 Vue 、React 也可以集成 TypeScript。</p>
<p>Nodejs 框架 Nestjs、midway 中用的就是 TypeScript 语法。</p>
<p>带有类型,是说js在定义变量的时候,类型是动态的,只有在运行的时候才能知道它的具体类型,比如 number 或者 string,并且类型也是可以动态变化的,而 TypeScript 则是要求变量有确定的类型,并且在编写代码的时候就已经确定,如果把字符串赋给类型为 number ,数字类型的变量,就会出错。</p>
<h3>为什么用 TypeScript</h3>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014111010045-1166755087.png"></p>
<p>在 stackoverflow 发起的2020年程序员调查中,TypeScript 在程序员最爱的编程语言中排在了第二位</p>
<p>https://stackoverflow.blog/2020/05/27/2020-stack-overflow-developer-survey-results/</p>
<h3>好处优势:</h3>
<p>类型检查、代码补全、易于维护、入门简单</p>
<p>之所以大家喜欢 TypeScript,是因为:</p>
<ul>
<li>TypeScript 有类型检查机制,我们可以在写代码的时候就能够发现错误,比如给函数误传了类型不同的参数,那么通过 VS Code 对 TypeScript 的强力支持,我们能立刻看到错误。</li>
<li>另外 VS Code 能根据 TypeScript 的类型信息提供更好的代码提示和补全功能。<br>此外,对于大型项目、多人协作编写代码时,类型起到了文档的作用,可以清楚的知道我这个变量是什么类型,或者我定义的函数需要什么样的参数,我的对象里又有哪些属性。这样让代码更易于维护,这也是为什么大公司、大型项目更偏爱 TypeScript</li>
<li>最后 TypeScript 入门的门槛低,只要你会 JavaScript,那么你就已经能编写 TypeScript 代码了。另外因为 JS 的快速发展,好多以前在 typescript 才能用的功能,你可能在JS 里已经用到了,所以说要学习的东西就更少了。</li>
</ul>
<p>除了这些好处之外,它也有其他静态类型语言比如 Java/c++ 的通病,就是代码量会增加,并且有时候类型过于复杂反而使得代码显的更难阅读,不过跟它带来的优势相比,也显得不那么突出了。</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014144613536-2029252819.png"> </p>
<h3>安装TypeScript</h3>
<p>有两种主要的方式来获取TypeScript工具:</p>
<ul>
<li>通过npm(Node.js包管理器)</li>
<li>安装Visual Studio的 TypeScript 插件</li>
</ul>
<p>Visual Studio 2017和Visual Studio 2015 Update 3默认包含了TypeScript。 如果你的Visual Studio还没有安装TypeScript,你可以下载它。</p>
<p>针对使用npm的用户:</p>
<div class="cnblogs_code">
<pre>npm install -g typescript</pre>
</div>
<h3>构建你的第一个TypeScript文件</h3>
<p>在编辑器,将下面的代码输入到<code>greeter.ts</code>文件里:</p>
<h3>编译代码</h3>
<p>我们使用了<code>.ts</code>扩展名,但是这段代码仅仅是JavaScript而已。 你可以直接从现有的JavaScript应用里复制/粘贴这段代码。</p>
<p>在命令行上,运行TypeScript编译器:</p>
<div class="cnblogs_code">
<pre>tsc greeter.ts</pre>
</div>
<p>然后可以看到,输出结果为一个 <span style="color: rgba(255, 0, 0, 1)"><code>greeter.js </code></span>文件,它包含了和输入文件中相同的JavsScript代码。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> greeter.js</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> greeter(person) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "Hello, " +<span style="color: rgba(0, 0, 0, 1)"> person;
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> user = "Jane User"<span style="color: rgba(0, 0, 0, 1)">;
document.body.innerHTML </span>= greeter(user);</pre>
</div>
<p>一切准备就绪,我们可以运行这个使用 TypeScript 写的 JavaScript 应用了!</p>
<p>接下来让我们看看 TypeScript 工具带来的高级功能。 给 <code>person </code>函数的参数添加 <code><span style="color: rgba(255, 0, 0, 1)">:string</span> </code>类型注解,如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> greeter(person: string) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "Hello, " +<span style="color: rgba(0, 0, 0, 1)"> person;
}
let user </span>= "Jane User"<span style="color: rgba(0, 0, 0, 1)">;
document.body.innerHTML </span>= greeter(user);</pre>
</div>
<p>运行编译:</p>
<div class="cnblogs_code">
<pre>tsc greeter.ts</pre>
</div>
<p>可以看到 greeter.js 的代码没变。</p>
<h3>类型注解</h3>
<p>TypeScript里的类型注解是一种轻量级的为函数或变量添加约束的方式。 在这个例子里,我们希望 <code>greeter</code>函数接收一个字符串参数。 </p>
<p>然后尝试把 <code>greeter</code>的调用改成传入一个数组:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> greeter(person: string) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> "Hello, " +<span style="color: rgba(0, 0, 0, 1)"> person;
}
let user </span>= ;
document.body.innerHTML </span>= greeter(user);</pre>
</div>
<p>可以看到报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014151826554-1343552163.png"></p>
<p>重新运行编译也可以看到报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014153736983-631285785.png"></p>
<p>类似地,尝试删除 <span style="color: rgba(255, 0, 0, 1)"><code>greeter </code></span>调用的所有参数。 TypeScript会告诉你使用了非期望个数的参数调用了这个函数。 在这两种情况中,TypeScript提供了静态的代码分析,它可以分析代码结构和提供的类型注解。</p>
<p>要注意的是尽管有错误,<code><span style="color: rgba(255, 0, 0, 1)">greeter.js</span> </code>文件还是被创建了。 就算你的代码里有错误,你仍然可以使用TypeScript。但在这种情况下,TypeScript会警告你代码可能不会按预期执行。</p>
<p> </p>
<p>新建一个 index.ts 文件:</p>
<div class="cnblogs_code">
<pre>let a:number = 10<span style="color: rgba(0, 0, 0, 1)">;
console.log(a);</span></pre>
</div>
<p>编译并运行:可以看到</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014155513796-525620206.png"></p>
<p><span style="color: rgba(255, 0, 0, 1)">另一种编译方法是通过 deno:deno 本身就支持 TypeScript ,所以只需要安装 deno 的运行环境就可以了。</span></p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201014160125459-1305842301.png"></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用 Shell:</span>
<span style="color: rgba(0, 0, 0, 1)">
curl </span>-fsSL https:<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">x.deno.js.cn/install.sh | sh</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 使用 PowerShell:</span>
<span style="color: rgba(0, 0, 0, 1)">
iwr https:</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">x.deno.js.cn/install.ps1 -useb | iex</span></pre>
</div>
<p>安装完成后,输入:</p>
<div class="cnblogs_code">
<pre>deno run index.ts</pre>
</div>
<p>也可以输出结果:10</p>
<p>打开 index.js 可以看到:除了去除了类型没有什么变化</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> a = 10<span style="color: rgba(0, 0, 0, 1)">;
console.log(a);</span></pre>
</div>
<p>有个问题:JavaScript 版本那么多,tsc 怎么知道要编译成那个版本呢?</p>
<p><span style="color: rgba(255, 0, 0, 1)">tsc 默认会编译成 ES3 版。</span></p>
<p>下面我们写一个 async 函数:</p>
<div class="cnblogs_code">
<pre>let a:number = 10<span style="color: rgba(0, 0, 0, 1)">;
console.log(a);
async </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> func() {
}</span></pre>
</div>
<p>再重新编译下,然后打开 index.js 文件,发现生成了很多复杂的代码来支持 async。</p>
<p>那如果我想要生成 ES2017 的代码呢?</p>
<p>需要在根目录下创建一个 tsconfigt.json 文件:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">{
</span>"compilerOptions"<span style="color: rgba(0, 0, 0, 1)">: {
</span>"target": "ES2017"<span style="color: rgba(0, 0, 0, 1)">
}
}</span></pre>
</div>
<p>这时编译可以输入:</p>
<div class="cnblogs_code">
<pre>tsc</pre>
</div>
<p>因为有了 <span style="color: rgba(255, 0, 0, 1)">tscofigt.josn</span> 文件后,这个文件夹<span style="color: rgba(255, 0, 0, 1)">会自动成为 TypeScript 项目</span>,tsc 会自动找到 .ts 文件,并进行编译。<span style="color: rgba(255, 0, 0, 1)">如果指定了文件名,那么 tscofigt.josn 设置就会被忽略</span>。</p>
<p>然后打开 index.js 文件可以看到:</p>
<div class="cnblogs_code">
<pre>let a = 10<span style="color: rgba(0, 0, 0, 1)">;
console.log(a);
async </span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> func() {
}</span></pre>
</div>
<h3>还可以用开发工具 Vscode 自动编译.ts 文件</h3>
<p>在终端中输入:可以生成配置文件 tsconfig.json</p>
<div class="cnblogs_code">
<pre>tsc --init</pre>
</div>
<p>注意:如果你已经创建过了,就不会再生成了。</p>
<h3>TypeScript 基本语法</h3>
<p>布尔类型(boolean)、数字类型(number)、字符串类型(string)、数组类型(array)、元组类型(tuple)、枚举类型(enum)、任意类型(any)、任意类型(any)、对象类型(object)、void类型、never类型、组合类型、类型别名、null 和 undefined</p>
<h4>1、基本类型</h4>
<p>给变量定义类型有两种方式:隐式类型和显式类型</p>
<p><span style="color: rgba(255, 0, 0, 1)">隐式类型</span>:是由 TypeScript 根据变量的值来推断类型,代码写法和js一样,但不同的是:后面不能用其他类型的值来给它重新赋值。</p>
<p>比如:</p>
<div class="cnblogs_code">
<pre>let a = 10<span style="color: rgba(0, 0, 0, 1)">;
a </span>= "hello";</pre>
</div>
<p>可以看到a上报错,鼠标移到a上可以看到:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201015091227657-866875153.png"></p>
<p><span style="color: rgba(255, 0, 0, 1)">显式类型</span>:和之前运行的ts代码示例一样,用 <span style="color: rgba(255, 0, 0, 1)">:</span> + <span style="color: rgba(255, 0, 0, 1)">类型</span> 来规定这个变量是什么类型的。</p>
<h4>·常用类型:</h4>
<p>布尔类型(boolean)、数字类型(number)、字符串类型(string)、null 和 undefined</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre>let b: <span style="color: rgba(0, 0, 255, 1)">boolean</span> = <span style="color: rgba(0, 0, 255, 1)">true</span>;</pre>
</div>
<p>你还可以使用模版字符串,它可以定义多行文本和内嵌表达式。 这种字符串是被反引号包围( `),并且以 ${ expr } 这种形式嵌入表达式</p>
<div class="cnblogs_code">
<pre>let username: string =<span style="color: rgba(0, 0, 0, 1)"> `Gene`;
let age: number </span>= 37<span style="color: rgba(0, 0, 0, 1)">;
let sentence: string </span>= `Hello, my name is ${ username }. I'<span style="color: rgba(0, 0, 0, 1)">ll be ${ age + 1 } years old next month.`;
console.log(sentence); // Hello, my name is Gene. I</span>'ll be 38 years old next month.</pre>
</div>
<p>这与下面定义sentence的方式效果相同:</p>
<div class="cnblogs_code">
<pre>let username: string =<span style="color: rgba(0, 0, 0, 1)"> `Gene`;
let age: number </span>= 37<span style="color: rgba(0, 0, 0, 1)">;
let sentence: string </span>= "Hello, my name is " + username + ".\n" +
"I'll be " + (age + 1) + " years old next month."<span style="color: rgba(0, 0, 0, 1)">;
console.log(sentence);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Hello, my name is Gene.</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> I'll be 38 years old next month.</span></pre>
</div>
<h4>·任意类型 any</h4>
<p>如果想让一个变量可以是<span style="color: rgba(255, 0, 0, 1)">任何类型</span>,就像 js 中可以任意更改的话。那么我们可以把它的类型定义为 <span style="color: rgba(255, 0, 0, 1)">any</span>。</p>
<p>例如:这时可以看到不会报错</p>
<div class="cnblogs_code">
<pre>let a: any = 10<span style="color: rgba(0, 0, 0, 1)">;
a </span>= "hello";</pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">类型也可以用在函数的参数和返回值中</span></p>
<p>比如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> add(a: number, b: number): number {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
add(</span>1, 2<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 小括号后面的:number 是返回值的类型,当然也可以省略不写</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> add(a: number, b: number) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
add(</span>1, 2);</pre>
</div>
<p>注意:<span style="color: rgba(255, 0, 0, 1)">调用函数时必须传递跟参数列表相同的参数(也就是说实参和形参的数量要一致)</span>,不像 js 可以不传或者只传前面的几个参数。</p>
<p>例如:我们只传a的值</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> add(a: number, b: number): number{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a +<span style="color: rgba(0, 0, 0, 1)"> b;
}
add(</span>1);</pre>
</div>
<p>会报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201015094454925-439811167.png"></p>
<h4>·void类型</h4>
<p>某种程度上来说,<code>void </code>类型像是与 <code>any </code>类型相反,它表示没有任何类型。 如果函数不返回值的话,可以使用 :<span style="color: rgba(255, 0, 0, 1)">void 类型,代表函数没有返回值</span>。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> add(a: number, b: number): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(a </span>+<span style="color: rgba(0, 0, 0, 1)"> b);
}</span></pre>
</div>
<h4>2、组合类型</h4>
<p>如果一个变量可以有多个类型,但是又不想使用 any 破坏类型检查,那么可以使用组合类型。<span style="color: rgba(255, 0, 0, 1)">组合类型使用 | 操作符来定义</span>。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre>let a :number | string = 10<span style="color: rgba(0, 0, 0, 1)">;
a </span>= "hello";</pre>
</div>
<p>不过这样代码看起来不太方便,并且这个组合类型只能给 a 使用,如果再有一个变量 b,也可以是number 或者 string 类型,那么还需要再重复定义这个类型。</p>
<p>要解决这个问题,我们可以使用 <span style="color: rgba(255, 0, 0, 1)">type</span> 关键字,来给这个<span style="color: rgba(255, 0, 0, 1)">组合类型起个别名</span>,让代码更易读,也方便其他变量使用。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre>type NumStr = number |<span style="color: rgba(0, 0, 0, 1)"> string;
let a: NumStr </span>= 10<span style="color: rgba(0, 0, 0, 1)">;
a </span>= "hello"<span style="color: rgba(0, 0, 0, 1)">;
let b: NumStr </span>= '123'<span style="color: rgba(0, 0, 0, 1)">;
b </span>= 123;</pre>
</div>
<p>另外组合类型也可以<span style="color: rgba(255, 0, 0, 1)">直接使用字面值来定义</span>,这样就规定了一个变量的取值范围。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre>let c: "on" | "off" = "on"<span style="color: rgba(0, 0, 0, 1)">;
c </span>= "off"<span style="color: rgba(0, 0, 0, 1)">;
c </span>= "other";</pre>
</div>
<p>可以看到最后一条报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201015103421570-535731801.png"></p>
<h4>3、对象类型</h4>
<p>使用 <span style="color: rgba(255, 0, 0, 1)">interface</span> 接口,接口是用来规范一个对象里应该都有哪些属性,包括它的名字和类型</p>
<p>例子:如果有一个 post 文章变量,里面有 title 和 author 属性,并且都是 string 类型的。那么我们可以使用接口来定义一个 post 类型。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface Post {
title: string;
author: string;
}
let post: Post </span>=<span style="color: rgba(0, 0, 0, 1)"> {
title: </span>'标题'<span style="color: rgba(0, 0, 0, 1)">,
author: </span>'作者'<span style="color: rgba(0, 0, 0, 1)">
}</span></pre>
</div>
<p>如果在增加一个属性就会报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201015143659166-190433091.png"></p>
<p>同样,去掉 title 属性,一样会报错:</p>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201015145552407-1394266121.png"></p>
<p><span style="color: rgba(255, 0, 0, 1)">接口</span>除了可以检查对象是否符合规范外,<span style="color: rgba(255, 0, 0, 1)">也可以用于函数参数的类型检查</span></p>
<p><span style="color: rgba(255, 0, 0, 1)">注意:</span>如果传递进来的对象没有定义类型的话,只要它的属性里包括接口中定义的规范,那么就可以通过检查,哪怕它有额外的属性。</p>
<p>例如:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface Post {
title: string;
author: string;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getTitle(post: Post) {
console.log(post.title)
}
let post </span>=<span style="color: rgba(0, 0, 0, 1)"> {
title: </span>'标题'<span style="color: rgba(0, 0, 0, 1)">,
author: </span>'作者'<span style="color: rgba(0, 0, 0, 1)">,
publishDate: </span>'2020-10-10'<span style="color: rgba(0, 0, 0, 1)">
}
getTitle(post); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 标题</span></pre>
</div>
<p>如果想要严格检查对象参数的话,可以像之前那样把 post 对象定义为 Post 接口类型的:</p>
<div class="cnblogs_code">
<pre>let post: Post =<span style="color: rgba(0, 0, 0, 1)"> {
}</span></pre>
</div>
<p>或者直接给函数传递对象字面值:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">getTitle({
title: </span>'标题'<span style="color: rgba(0, 0, 0, 1)">,
author: </span>'作者'<span style="color: rgba(0, 0, 0, 1)">,
}); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 标题</span></pre>
</div>
<h4>4、数组类型</h4>
<p>给数组规定类型,可以保证里面的元素都是同一个类型。以防在统一处理数组元素时,会混进来其他类型的元素,导致异常;或者防止意外给数组元素赋了其他类型的值。</p>
<div class="cnblogs_code">
<pre>let arr: number[] = ;</pre>
</div>
<p>还有一种写法是:<span style="color: rgba(255, 0, 0, 1)">使用数组泛型 <code>Array<元素类型></code>:</span></p>
<div class="cnblogs_code">
<pre>let arr: Array<number> = ;</pre>
</div>
<p>当然也可以使用 <span style="color: rgba(255, 0, 0, 1)">any</span> 定义任意类型的数组:</p>
<div class="cnblogs_code">
<pre>let arr: any[] = ;</pre>
</div>
<h4>5、元祖 (tuple)</h4>
<p>元组类型允许表示一个已知元素数量和类型的数组,<span style="color: rgba(255, 0, 0, 1)">各元素的类型不必相同</span>。</p>
<p>有限元素数量的数组,<span style="color: rgba(0, 0, 0, 1)">每个元素要分别指定是什么类型</span></p>
<div class="cnblogs_code">
<pre>let tup: = ;</pre>
</div>
<h4>6、枚举类型(enum) </h4>
<p><span style="color: rgba(255, 0, 0, 1)"><code>enum </code></span>类型是对 JavaScript 标准数据类型的一个补充。 像 C# 等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。</p>
<p>如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,这种方法称为枚举方法,用这种方法定义的类型称枚举类型。</p>
<div class="cnblogs_code">
<pre>enum Status {success=1, error=2<span style="color: rgba(0, 0, 0, 1)">};
let s:Status </span>=<span style="color: rgba(0, 0, 0, 1)"> Status.success;
console.log(s); </span><span style="color: rgba(0, 128, 0, 1)">//1</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">enum Color {blue, red, orange};
let c:Color </span>=<span style="color: rgba(0, 0, 0, 1)"> Color.red;
console.log(c); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">1 如果标识符没有赋值 它的值就是下标</span></pre>
</div>
<p>枚举类型提供的一个便利是你可以由枚举的值得到它的名字。 例如,我们知道数值为2,但是不确定它映射到 Color 里的哪个名字,我们可以查找相应的名字:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">enum Color {blue , red, orange}
let colorName1: string </span>= Color;
console.log(colorName1);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> orange</span>
<span style="color: rgba(0, 0, 0, 1)">
enum NewColor {blue </span>= 1<span style="color: rgba(0, 0, 0, 1)">, red, orange}
let colorName2: string </span>= NewColor;
console.log(colorName2);</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> // 显示'red'因为上面代码里它的值是2</span></pre>
</div>
<h4>7、对象类型(object)</h4>
<p><span style="color: rgba(255, 0, 0, 1)"><code>object </code></span>表示非原始类型,也就是除<code>number</code>,<code>string</code>,<code>boolean</code>,<code>symbol</code>,<code>null</code>或<code>undefined</code>之外的类型。</p>
<p>使用<code>object</code>类型,就可以更好的表示像<code>Object.create</code>这样的API。例如:</p>
<div class="cnblogs_code">
<pre>declare <span style="color: rgba(0, 0, 255, 1)">function</span> create(o: object | <span style="color: rgba(0, 0, 255, 1)">null</span>): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">;
create({ prop: </span>0 }); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> OK</span>
create(<span style="color: rgba(0, 0, 255, 1)">null</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> OK</span></pre>
</div>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">let</span> arr2:object = ;
console.log(arr2);</span></pre>
</div>
<h4>8、null 和 undefined:其他(never类型)数据类型的子类型</h4>
<p>TypeScript里,<code>undefined </code>和 <code>null </code>两者各自有自己的类型分别叫做 <code>undefined </code>和 <code>null</code>。 和 <code>void </code>相似,它们的本身的类型用处不是很大:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">let num:number;
console.log(num)</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出:undefined 报错</span>
<span style="color: rgba(0, 0, 0, 1)">let num1:undefined;
console.log(num1)</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出:undefined//正确</span>
let num2:number |<span style="color: rgba(0, 0, 0, 1)"> undefined;
num2 </span>= 123<span style="color: rgba(0, 0, 0, 1)">;
console.log(num2);</span></pre>
</div>
<p>默认情况下 null 和 undefined 是所有类型的子类型。 就是说你可以把 null 和undefined 赋值给 number 类型的变量。</p>
<p>然而,当你指定了<span style="color: rgba(255, 0, 0, 1)">--strictNullChecks</span> 标记,null和undefined只能赋值给void和它们各自。 这能避免 很多常见的问题。 也许在某处你想传入一个 string或null或undefined,你可以使用联合类型string | null | undefined。 再次说明,稍后我们会介绍联合类型。</p>
<p><span style="color: rgba(255, 0, 0, 1)">注意</span>:我们鼓励尽可能地使用--strictNullChecks,但在本手册里我们假设这个标记是关闭的。</p>
<h4>9、never类型</h4>
<p><code><span style="color: rgba(255, 0, 0, 1)">never</span> </code>类型表示的是那些永不存在的值的类型。 例如, <code>never </code>类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型; 变量也可能是 <code>never</code>类型,当它们被永不为真的类型保护所约束时。</p>
<p><code>never </code>类型是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明 never 的变量只能被 never 类型所赋值。 即使 <code>any </code>也不可以赋值给 <code>never</code>。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">let</span><span style="color: rgba(0, 0, 0, 1)"> a: never;
a </span>= 123; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">错误写法</span>
a = (<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span> Error("错误"<span style="color: rgba(0, 0, 0, 1)">)
})();
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回never的函数必须存在无法达到的终点</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> error(message: string): never {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Error(message);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 推断的返回值类型为never</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> fail() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> error("Something failed"<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 返回never的函数必须存在无法达到的终点</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> infiniteLoop(): never {
</span><span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
}
}</span></pre>
</div>
<h3>类型断言</h3>
<p>有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型。</p>
<p>通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构。 它没有运行时的影响,只是在编译阶段起作用。 TypeScript会假设你,程序员,已经进行了必须的检查。</p>
<p>类型断言有两种形式。 其一是“<span style="color: rgba(255, 0, 0, 1)">尖括号</span>”语法:</p>
<div class="cnblogs_code">
<pre>let someValue: any = "this is a string"<span style="color: rgba(0, 0, 0, 1)">;
let strLength: number </span>= (<string>someValue).length;</pre>
</div>
<p>另一个为 <code><span style="color: rgba(255, 0, 0, 1)">as</span> </code>语法:</p>
<div class="cnblogs_code">
<pre>let someValue: any = "this is a string"<span style="color: rgba(0, 0, 0, 1)">;
let strLength: number </span>= (someValue as string).length;</pre>
</div>
<p>两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在TypeScript里使用JSX时,只有 <code>as</code>语法断言是被允许的。</p>
<h3>关于<code>let</code></h3>
<p>你可能已经注意到了,我们使用 <code><span style="color: rgba(255, 0, 0, 1)">let</span> </code>关键字来代替大家所熟悉的JavaScript关键字 <code>var</code>。 <span style="color: rgba(255, 0, 0, 1)"><code>let</code>关键字是JavaScript的一个新概念</span>,TypeScript实现了它。 我们会在以后详细介绍它,很多常见的问题都可以通过使用 <code>let</code>来解决,所以<span style="color: rgba(255, 0, 0, 1)">尽可能地使用<code>let</code>来代替<code>var</code>吧</span>。</p>
<h3>变量声明</h3>
<p>let和const是JavaScript里相对较新的变量声明方式。 像我们之前提到过的, let在很多方面与var是相似的,但是可以帮助大家避免在JavaScript里常见一些问题。 const是对let的一个增强,它能阻止对一个变量再次赋值。<br>因为TypeScript是JavaScript的超集,所以它本身就支持let和const。 下面我们会详细说明这些新的声明方式以及为什么推荐使用它们来代替 var。</p>
<h4>var 声明</h4>
<p>一直以来我们都是通过 <span style="color: rgba(255, 0, 0, 1)">var</span> 关键字定义JavaScript变量。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f() {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> a = 10<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> g() {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> b = a + 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> b;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> g =<span style="color: rgba(0, 0, 0, 1)"> f();
g(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns 11;</span></pre>
</div>
<p>上面的例子里,<code>g</code>可以获取到<code>f</code>函数里定义的<code>a</code>变量。 每当 <code>g</code>被调用时,它都可以访问到<code>f</code>里的<code>a</code>变量。 即使当 <code>g</code>在<code>f</code>已经执行完后才被调用,它仍然可以访问及修改<code>a</code>。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f() {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> a = 1<span style="color: rgba(0, 0, 0, 1)">;
a </span>= 2<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> b =<span style="color: rgba(0, 0, 0, 1)"> g();
a </span>= 3<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> b;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> g() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> a;
}
}
f(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns 2</span></pre>
</div>
<h4>作用域规则</h4>
<p>对于熟悉其它语言的人来说,<code>var</code>声明有些奇怪的作用域规则。 看下面的例子:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> f(shouldInitialize: <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (shouldInitialize) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> x = 10<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> x;
}
f(</span><span style="color: rgba(0, 0, 255, 1)">true</span>);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns '10'</span>
f(<span style="color: rgba(0, 0, 255, 1)">false</span>); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns 'undefined'</span></pre>
</div>
<p>变量 <code><span style="color: rgba(255, 0, 0, 1)">x</span> </code>是定义在*<span style="color: rgba(255, 0, 0, 1)"><code>if</code></span>语句里面*,但是我们却可以在语句的外面访问它。 这是因为 <code><span style="color: rgba(255, 0, 0, 1)">var</span> </code>声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问(我们后面会详细介绍),包含它的代码块对此没有什么影响。 有些人称此为 <code><span style="color: rgba(255, 0, 0, 1)">var</span> </code>作用域<em>或</em>函数作用域*。 函数参数也使用函数作用域。</p>
<p>这些作用域规则可能会引发一些错误。 其中之一就是,多次声明同一个变量并不会报错:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sumMatrix(matrix: number[][]) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> sum = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < matrix.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> currentRow =<span style="color: rgba(0, 0, 0, 1)"> matrix;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < currentRow.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
sum </span>+=<span style="color: rgba(0, 0, 0, 1)"> currentRow;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sum;
}</span></pre>
</div>
<p>这里很容易看出一些问题,里层的for循环会覆盖变量i,因为所有i都引用相同的函数作用域内的变量。 有经验的开发者们很清楚,这些问题可能在代码审查时漏掉,引发无穷的麻烦。</p>
<h4>捕获变量怪异之处</h4>
<p>快速的猜一下下面的代码会返回什么:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
setTimeout(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
console.log(i);
}, </span>100 *<span style="color: rgba(0, 0, 0, 1)"> i);
}</span></pre>
</div>
<p>好吧,看一下结果:</p>
<div class="cnblogs_code">
<pre>10
10
10
10
10
10
10
10
10
10</pre>
</div>
<p>很多JavaScript程序员对这种行为已经很熟悉了,但如果你很不解,你并不是一个人。 大多数人期望输出结果是这样:</p>
<div class="cnblogs_code">
<pre>0
1
2
3
4
5
6
7
8
9</pre>
</div>
<p>还记得我们上面提到的捕获变量吗?</p>
<p>我们传给 <span style="color: rgba(255, 0, 0, 1)">setTimeout </span>的每一个函数表达式实际上都引用了相同作用域里的同一个 <span style="color: rgba(255, 0, 0, 1)">i</span>。</p>
<p>让我们花点时间思考一下这是为什么。 <code><span style="color: rgba(255, 0, 0, 1)">setTimeout</span> </code>在若干毫秒后执行一个函数,并且是在 <code><span style="color: rgba(255, 0, 0, 1)">for</span> </code>循环结束后。 <code><span style="color: rgba(255, 0, 0, 1)">for</span> </code>循环结束后,<span style="color: rgba(255, 0, 0, 1)"><code>i </code></span>的值为 <span style="color: rgba(255, 0, 0, 1)"><code>10</code></span>。 所以当函数被调用的时候,它会打印出 <span style="color: rgba(255, 0, 0, 1)"><code>10</code></span>!</p>
<p>一个通常的解决方法是使用立即执行的函数表达式(IIFE)来捕获每次迭代时 <code><span style="color: rgba(255, 0, 0, 1)">i</span> </code>的值:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> capture the current state of 'i'</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> by invoking a function with its current value</span>
(<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">(i) {
setTimeout(</span><span style="color: rgba(0, 0, 255, 1)">function</span>() { console.log(i); }, 100 *<span style="color: rgba(0, 0, 0, 1)"> i);
})(i);
}</span></pre>
</div>
<p>这种奇怪的形式我们已经司空见惯了。 参数 <span style="color: rgba(255, 0, 0, 1)"><code>i </code></span>会覆盖 <code><span style="color: rgba(255, 0, 0, 1)">for</span> </code>循环里的 <span style="color: rgba(255, 0, 0, 1)"><code>i</code></span>,但是因为我们起了同样的名字,所以我们不用怎么改<code>for</code>循环体里的代码。</p>
<h4><code>let</code> 声明</h4>
<p>现在你已经知道了 <code>var </code>存在一些问题,这恰好说明了为什么用 <code><span style="color: rgba(255, 0, 0, 1)">let</span> </code>语句来声明变量。 除了名字不同外, <span style="color: rgba(255, 0, 0, 1)"><code>let </code></span>与 <span style="color: rgba(255, 0, 0, 1)"><code>var </code></span>的写法一致。</p>
<p>主要的区别不在语法上,而是语义,我们接下来会深入研究。</p>
<h4>块作用域</h4>
<p>当用 <span style="color: rgba(255, 0, 0, 1)">let </span>声明一个变量,它使用的是词法作用域或块作用域。 不同于使用 var 声明的变量那样可以在包含它们的函数外访问,块作用域变量在包含它们的块或for循环之外是不能访问的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> f(input: <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)">) {
let a </span>= 100<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (input) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Still okay to reference 'a'</span>
let b = a + 1<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> b;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 报错 Error: 'b' doesn't exist here</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> b;
}</span></pre>
</div>
<p>这里我们定义了2个变量 <code><span style="color: rgba(255, 0, 0, 1)">a</span> </code>和 <span style="color: rgba(255, 0, 0, 1)"><code>b</code></span>。 <code><span style="color: rgba(255, 0, 0, 1)">a</span> </code>的作用域是 <span style="color: rgba(255, 0, 0, 1)"><code>f </code></span>函数体内,而 <code><span style="color: rgba(255, 0, 0, 1)">b</span> </code>的作用域是 <code><span style="color: rgba(255, 0, 0, 1)">if</span> </code>语句块里。</p>
<p>在 <span style="color: rgba(255, 0, 0, 1)"><code>catch </code></span>语句里声明的变量也具有同样的作用域规则。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">throw</span> "oh no!"<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (e) {
console.log(</span>"Oh well."<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 报错 Error: 'e' doesn't exist here</span>
console.log(e);</pre>
</div>
<p>拥有块级作用域的变量的另一个特点是,它们不能在被声明之前读或写。 虽然这些变量始终“存在”于它们的作用域里,但在直到声明它的代码之前的区域都属于 <em>暂时性死区</em>。 它只是用来说明我们不能在 <code><span style="color: rgba(255, 0, 0, 1)">let</span> </code>语句之前访问它们,幸运的是TypeScript可以告诉我们这些信息。</p>
<p>注意一点,我们仍然可以在一个拥有块作用域变量被声明前<em>获取</em>它。 只是我们不能在变量声明前去调用那个函数。 如果生成代码目标为ES2015,现代的运行时会抛出一个错误;然而,现今TypeScript是不会报错的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> foo() {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> okay to capture 'a'</span>
<span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> a;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 不能在'a'被声明前调用'foo'</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> 运行时应该抛出错误</span>
<span style="color: rgba(0, 0, 0, 1)">foo();
let a;</span></pre>
</div>
<h4>重定义及屏蔽</h4>
<p>我们提过使用 <span style="color: rgba(255, 0, 0, 1)"><code>var </code></span>声明时,它不在乎你声明多少次;你只会得到1个。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f(x) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> x;
</span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> x;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span><span style="color: rgba(0, 0, 0, 1)"> x;
}
}</span></pre>
</div>
<p>在上面的例子里,所有x的声明实际上都引用一个相同的 <span style="color: rgba(255, 0, 0, 1)">x</span>,并且这是完全有效的代码。 这经常会成为 bug 的来源。 好的是, <span style="color: rgba(255, 0, 0, 1)">let</span> 声明就不会这么宽松了。</p>
<div class="cnblogs_code">
<pre>let x = 10<span style="color: rgba(0, 0, 0, 1)">;
let x </span>= 20; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 错误,不能在1个作用域里多次声明`x`</span></pre>
</div>
<p>并不是要求两个均是块级作用域的声明TypeScript才会给出一个错误的警告。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f(x) {
let x </span>= 100; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> error: interferes with parameter declaration</span>
<span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> g() {
let x </span>= 100<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> x = 100; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> error: can't have both declarations of 'x'</span>
}</pre>
</div>
<p>并不是说块级作用域变量不能用函数作用域变量来声明。 而是块级作用域变量需要在明显不同的块里声明。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f(condition, x) {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (condition) {
let x </span>= 100<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> x;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> x;
}
f(</span><span style="color: rgba(0, 0, 255, 1)">false</span>, 0); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns 0</span>
f(<span style="color: rgba(0, 0, 255, 1)">true</span>, 0);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> returns 100</span></pre>
</div>
<p>在一个嵌套作用域里引入一个新名字的行为称做屏蔽。 它是一把双刃剑,它可能会不小心地引入新问题,同时也可能会解决一些错误。 例如,假设我们现在用 <span style="color: rgba(255, 0, 0, 1)">let</span> 重写之前的 <span style="color: rgba(255, 0, 0, 1)">sumMatrix</span> 函数。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sumMatrix(matrix: number[][]) {
let sum </span>= 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < matrix.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> currentRow =<span style="color: rgba(0, 0, 0, 1)"> matrix;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < currentRow.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
sum </span>+=<span style="color: rgba(0, 0, 0, 1)"> currentRow;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sum;
}</span></pre>
</div>
<p>这个版本的循环能得到正确的结果,因为内层循环的 <span style="color: rgba(255, 0, 0, 1)">i</span> 可以屏蔽掉外层循环的 <span style="color: rgba(255, 0, 0, 1)">i</span>。</p>
<h4>块级作用域变量的获取</h4>
<p>在我们最初谈及获取用 <span style="color: rgba(255, 0, 0, 1)"><code>var </code></span>声明的变量时,我们简略地探究了一下在获取到了变量之后它的行为是怎样的。 直观地讲,每次进入一个作用域时,它创建了一个变量的 <em>环境</em>。 就算作用域内代码已经执行完毕,这个环境与其捕获的变量依然存在。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> theCityThatAlwaysSleeps() {
let getCity;
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
let city </span>= "Seattle"<span style="color: rgba(0, 0, 0, 1)">;
getCity </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> city;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> getCity();
}
console.log(theCityThatAlwaysSleeps()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Seattle</span></pre>
</div>
<p>因为我们已经在 <span style="color: rgba(255, 0, 0, 1)"><code>city </code></span>的环境里获取到了 <span style="color: rgba(255, 0, 0, 1)"><code>city</code></span>,所以就算 <span style="color: rgba(255, 0, 0, 1)"><code>if </code></span>语句执行结束后我们仍然可以访问它。</p>
<p>回想一下前面 <span style="color: rgba(255, 0, 0, 1)">setTimeout </span>的例子,我们最后需要使用立即执行的函数表达式来获取每次 <span style="color: rgba(255, 0, 0, 1)">for </span>循环迭代里的状态。 实际上,我们做的是为获取到的变量创建了一个新的变量环境。 这样做挺痛苦的,但是幸运的是,你不必在TypeScript里这样做了。 </p>
<p>当 <span style="color: rgba(255, 0, 0, 1)">let </span>声明出现在循环体里时拥有完全不同的行为。 不仅是在循环里引入了一个新的变量环境,而是针对 每次迭代都会创建这样一个新作用域。 这就是我们在使用立即执行的函数表达式时做的事,所以在 <span style="color: rgba(255, 0, 0, 1)">setTimeout </span>例子里我们仅使用 <span style="color: rgba(255, 0, 0, 1)">let </span>声明就可以了。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">for</span> (let i = 0; i < 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
setTimeout(</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)">() {
console.log(i);
}, </span>100 *<span style="color: rgba(0, 0, 0, 1)"> i);
}</span></pre>
</div>
<p>会输出与预料一致的结果:</p>
<div class="cnblogs_code">
<pre>0
1
2
3
4
5
6
7
8
9</pre>
</div>
<h3><code>const</code> 声明</h3>
<p><span style="color: rgba(255, 0, 0, 1)"><code>const</code> </span>声明是声明变量的另一种方式。</p>
<div class="cnblogs_code">
<pre>const numLivesForCat = 9;</pre>
</div>
<p>它们与 <span style="color: rgba(255, 0, 0, 1)"><code>let </code></span>声明相似,但是就像它的名字所表达的,它们被赋值后不能再改变。 换句话说,它们拥有与 <span style="color: rgba(255, 0, 0, 1)"><code>let </code></span>相同的作用域规则,但是<span style="color: rgba(255, 0, 0, 1)">不能对它们重新赋值</span>。</p>
<div class="cnblogs_code">
<pre>const numLivesForCat = 9<span style="color: rgba(0, 0, 0, 1)">;
const kitty </span>=<span style="color: rgba(0, 0, 0, 1)"> {
name: </span>"Aurora"<span style="color: rgba(0, 0, 0, 1)">,
numLives: numLivesForCat,
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Error</span>
kitty =<span style="color: rgba(0, 0, 0, 1)"> {
name: </span>"Danielle"<span style="color: rgba(0, 0, 0, 1)">,
numLives: numLivesForCat
};
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> all "okay"</span>
kitty.name = "Rory"<span style="color: rgba(0, 0, 0, 1)">;
kitty.name </span>= "Kitty"<span style="color: rgba(0, 0, 0, 1)">;
kitty.name </span>= "Cat"<span style="color: rgba(0, 0, 0, 1)">;
kitty.numLives</span>--<span style="color: rgba(0, 0, 0, 1)">;
console.log(kitty); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { name: 'Cat', numLives: 8 }</span></pre>
</div>
<p>除非你使用特殊的方法去避免,实际上 <span style="color: rgba(255, 0, 0, 1)">const </span>变量的内部状态是可修改的。 幸运的是,TypeScript允许你将对象的成员设置成只读的。 接口一章有详细说明。</p>
<h3><code>let</code> vs. <code>const</code></h3>
<p>现在我们有两种作用域相似的声明方式,我们自然会问到底应该使用哪个。 与大多数泛泛的问题一样,答案是:依情况而定。</p>
<p>使用最小特权原则,所有变量除了你计划去修改的都应该使用<span style="color: rgba(255, 0, 0, 1)">const</span>。 基本原则就是如果一个变量不需要对它写入,那么其它使用这些代码的人也不能够写入它们,并且要思考为什么会需要对这些变量重新赋值。 使用 <span style="color: rgba(255, 0, 0, 1)">const</span>也可以让我们更容易的推测数据的流动。</p>
<h3>解构</h3>
<h4>解构数组</h4>
<p>最简单的解构莫过于数组的解构赋值了:</p>
<div class="cnblogs_code">
<pre>let input = ;
let </span>=<span style="color: rgba(0, 0, 0, 1)"> input;
console.log(first); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 1</span>
console.log(second); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 2</span></pre>
</div>
<p>这创建了2个命名变量 first 和 second。 相当于使用了索引,但更为方便:</p>
<div class="cnblogs_code">
<pre>first = input;
second </span>= input;</pre>
</div>
<p>解构作用于已声明的变量会更好:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 交换变量</span>
= ;</pre>
</div>
<p>作用于函数参数:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> f(: ) {
console.log(first);
console.log(second);
}
f([</span>1, 2]);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1 // 2</span></pre>
</div>
<p>你可以在数组里使用 <span style="color: rgba(255, 0, 0, 1)">... </span>语法创建剩余变量:</p>
<div class="cnblogs_code">
<pre>let = ;
console.log(first); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 1</span>
console.log(rest); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs [ 2, 3, 4 ]</span></pre>
</div>
<p>当然,由于是JavaScript, 你可以忽略你不关心的尾随元素:</p>
<div class="cnblogs_code">
<pre>let = ;
console.log(first); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 1</span></pre>
</div>
<p>或其它元素:</p>
<div class="cnblogs_code">
<pre>let [, second, , fourth] = ;
console.log(second); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 2</span>
console.log(fourth); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> outputs 4</span></pre>
</div>
<h4>对象解构</h4>
<p>你也可以解构对象:</p>
<div class="cnblogs_code">
<pre>let o =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>"foo"<span style="color: rgba(0, 0, 0, 1)">,
b: </span>12<span style="color: rgba(0, 0, 0, 1)">,
c: </span>"bar"<span style="color: rgba(0, 0, 0, 1)">
};
let { a, b } </span>=<span style="color: rgba(0, 0, 0, 1)"> o;
console.log(a); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> foo</span>
console.log(b); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 12</span></pre>
</div>
<p>这通过 <span style="color: rgba(255, 0, 0, 1)"><code>o.a</code> </span>and <span style="color: rgba(255, 0, 0, 1)"><code>o.b</code></span> 创建了 <span style="color: rgba(255, 0, 0, 1)"><code>a</code></span> 和 <span style="color: rgba(255, 0, 0, 1)"><code>b</code></span> 。 注意,如果你不需要 <span style="color: rgba(255, 0, 0, 1)"><code>c</code></span> 你可以忽略它。</p>
<p>就像数组解构,你可以用没有声明的赋值:</p>
<div class="cnblogs_code">
<pre>({ a, b } = { a: "baz", b: 101 });</pre>
</div>
<p>注意,我们需要用括号将它括起来,因为Javascript通常会将以 <span style="color: rgba(255, 0, 0, 1)"><code>{</code></span> 起始的语句解析为一个块。</p>
<p>你可以在对象里使用 <span style="color: rgba(255, 0, 0, 1)"><code>... </code></span>语法创建剩余变量:</p>
<div class="cnblogs_code">
<pre>let o =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>"foo"<span style="color: rgba(0, 0, 0, 1)">,
b: </span>12<span style="color: rgba(0, 0, 0, 1)">,
c: </span>"bar"<span style="color: rgba(0, 0, 0, 1)">
};
let { a, ...passthrough } </span>=<span style="color: rgba(0, 0, 0, 1)"> o;
let total </span>= passthrough.b +<span style="color: rgba(0, 0, 0, 1)"> passthrough.c.length;
console.log(total); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 15</span>
console.log(passthrough); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { b: 12, c: 'bar' }</span></pre>
</div>
<h4>属性重命名</h4>
<p>你也可以给属性以不同的名字:</p>
<div class="cnblogs_code">
<pre>let o =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>"foo"<span style="color: rgba(0, 0, 0, 1)">,
b: </span>12<span style="color: rgba(0, 0, 0, 1)">,
c: </span>"bar"<span style="color: rgba(0, 0, 0, 1)">
};
let { a: newName1, b: newName2 } </span>=<span style="color: rgba(0, 0, 0, 1)"> o;
console.log(newName1); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> foo</span>
console.log(newName2); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 12</span></pre>
</div>
<p>这里的语法开始变得混乱。 你可以将 <span style="color: rgba(255, 0, 0, 1)"><code>a: newName1</code></span> 读做 "<span style="color: rgba(255, 0, 0, 1)"><code>a</code></span> 作为 <span style="color: rgba(255, 0, 0, 1)"><code>newName1</code></span>"。 方向是从左到右,好像你写成了以下样子:</p>
<div class="cnblogs_code">
<pre>let newName1 =<span style="color: rgba(0, 0, 0, 1)"> o.a;
let newName2 </span>= o.b;</pre>
</div>
<p>令人困惑的是,这里的冒号不是指示类型的。 如果你想指定它的类型, 仍然需要在其后写上完整的模式。</p>
<div class="cnblogs_code">
<pre>let o =<span style="color: rgba(0, 0, 0, 1)"> {
a: </span>"foo"<span style="color: rgba(0, 0, 0, 1)">,
b: </span>12<span style="color: rgba(0, 0, 0, 1)">,
c: </span>"bar"<span style="color: rgba(0, 0, 0, 1)">
};
let {a, b}: {a: string, b: number} </span>=<span style="color: rgba(0, 0, 0, 1)"> o;
console.log(a); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> foo</span>
console.log(b); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 12</span></pre>
</div>
<h4>默认值</h4>
<p>默认值可以让你在属性为 undefined 时使用缺省值:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> keepWholeObject(wholeObject: { a: string, b?<span style="color: rgba(0, 0, 0, 1)">: number }) {
let { a, b </span>= 1001 } =<span style="color: rgba(0, 0, 0, 1)"> wholeObject;
}</span></pre>
</div>
<p>现在,即使 <span style="color: rgba(255, 0, 0, 1)"><code>b</code></span> 为 <span style="color: rgba(255, 0, 0, 1)">undefined</span> , <span style="color: rgba(255, 0, 0, 1)"><code>keepWholeObject</code> </span>函数的变量 <span style="color: rgba(255, 0, 0, 1)"><code>wholeObject</code> </span>的属性 <span style="color: rgba(255, 0, 0, 1)"><code>a</code></span> 和 <span style="color: rgba(255, 0, 0, 1)"><code>b</code></span> 都会有值。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> keepWholeObject(wholeObject: { a: string, b?<span style="color: rgba(0, 0, 0, 1)">: number }) {
let { a, b </span>= 1001 } =<span style="color: rgba(0, 0, 0, 1)"> wholeObject;
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> {a, b};
}
console.log(keepWholeObject({a: </span>'11'})); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { a: '11', b: 1001 }</span></pre>
</div>
<h3>TypeScript中的函数</h3>
<h4>1、函数的定义</h4>
<p>传递参数和返回值都要进行指定类型<br>返回类型必须是 string 类型,不能写成别的数据类型,否则会报错</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 有返回值</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> run1(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> 'run'<span style="color: rgba(0, 0, 0, 1)">;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 无返回值</span>
<span style="color: rgba(0, 0, 255, 1)">function</span> run2(): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">{
console.log(</span>'run'<span style="color: rgba(0, 0, 0, 1)">);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 箭头函数</span>
const materials =<span style="color: rgba(0, 0, 0, 1)"> [
</span>'Hydrogen'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Helium'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Lithium'<span style="color: rgba(0, 0, 0, 1)">,
</span>'Beryllium'<span style="color: rgba(0, 0, 0, 1)">
];
console.log(materials.map((material): any </span>=> material.length)); <span style="color: rgba(0, 128, 0, 1)">// </span><span style="color: rgba(0, 128, 0, 1)"> 加不加any都可以</span></pre>
</div>
<p>匿名函数的写法:</p>
<div class="cnblogs_code">
<pre> <span style="color: rgba(0, 0, 255, 1)">var</span>run2=<span style="color: rgba(0, 0, 255, 1)">function</span>():string{<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">指定返回值类型为string字符串类型</span>
<span style="color: rgba(0, 0, 255, 1)">return</span> '1243'<span style="color: rgba(0, 0, 0, 1)">;
}
run2(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用方法</span>
console.log(run2()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1243</span></pre>
</div>
<p>定义方法中的传参:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string, age: number): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${name} ---<span style="color: rgba(0, 0, 0, 1)"> ${age}`;
}
console.log(getInfo(</span>"zhangsan", 20)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> zhangsan --- 20</span></pre>
</div>
<h4>2、可选参数</h4>
<p>es5 里面方法的实参和行参可以不一样,但是 ts 中必须一样,如果不一样就需要<span style="color: rgba(255, 0, 0, 1)">配置可选参数,用问号?表示</span></p>
<p>如果调用函数的时候,不传第二个参数,则要在第二个函数 age?上加一个问号。问号就表示这个age可以传,可以不传。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> getInfo(name: string, age?<span style="color: rgba(0, 0, 0, 1)">: number): string {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (age) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${name} ---<span style="color: rgba(0, 0, 0, 1)"> ${age}`;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${name} ---<span style="color: rgba(0, 0, 0, 1)">年龄保密`;
}
}
console.log(getInfo(</span>'zhangsan')); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> zhangsan ---年龄保密</span>
console.log(getInfo('zhangsan', 123)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> zhangsan --- 123</span></pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">注意:可选参数必须配置到参数的最后面。</span></p>
<h4>3、默认参数</h4>
<p>es5 里面没法设置默认参数,es6 和 ts 中都可以设置默认参数 。<span style="color: rgba(255, 0, 0, 1)">位置可以放在第一个参数,也可以放在最后一个参数的位置</span>。</p>
<p>如果没有传年龄的参数,则默认为number=20,如果传参数,就是传的那个年龄的参数,和上面的可选参数是类似的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> getInfo(name: string, age: number = 20<span style="color: rgba(0, 0, 0, 1)">): string {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (age) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${name} ---<span style="color: rgba(0, 0, 0, 1)"> ${age}`;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${name} ---<span style="color: rgba(0, 0, 0, 1)">年龄保密`;
}
}
console.log( getInfo(</span>'张三')); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三 --- 20</span>
console.log(getInfo('张三', 30)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三 --- 30</span></pre>
</div>
<h4>4、剩余参数</h4>
<p>必要参数,默认参数和可选参数有个共同点:它们表示某一个参数。 有时,你想同时操作多个参数,或者你并不知道会有多少参数传递进来。 在 JavaScript 里,你可以使用 arguments 来访问所有传入的参数。在 TypeScript 里,你可以把所有参数收集到一个变量里。</p>
<p><span style="color: rgba(255, 0, 0, 1)">剩余参数会被当做个数不限的可选参数</span>。可以一个都没有,同样也可以有任意个。</p>
<p>例子:求和</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sum(a:number,b:number,c:number,d:number){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a+b+c+<span style="color: rgba(0, 0, 0, 1)">d
}
sum (</span>1,2,3,4<span style="color: rgba(0, 0, 0, 1)">);
console.log(sum (</span>1,2,3,4,)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 10</span></pre>
</div>
<p>例子:求积</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sum(a:number,b:number,c:number,d:number){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> a*b*c*<span style="color: rgba(0, 0, 0, 1)">d
}
sum (</span>1,2,3,4<span style="color: rgba(0, 0, 0, 1)">);
console.log(sum (</span>1,2,3,4,)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 24</span></pre>
</div>
<p><strong><span style="color: rgba(255, 0, 0, 1)">三点运算符</span>,接收形参传过来的值(剩余参数)(把sum里面所有传过来的参数全部赋值给result数组)</strong></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sum(...result: number[]): number {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> sum = 0<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < result.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
sum </span>+=<span style="color: rgba(0, 0, 0, 1)"> result;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sum;
}
console.log(sum(</span>1, 2, 3, 4, 5, 6)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 21</span></pre>
</div>
<p>另一种写法,把1赋给a,2赋给b,后面三个数赋给...result</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> sum(a: number, b: number, ...result: number[]): number {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> sum = a +<span style="color: rgba(0, 0, 0, 1)"> b;
</span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">var</span> i = 0; i < result.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
sum </span>+=<span style="color: rgba(0, 0, 0, 1)"> result;
}
</span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sum;
}
console.log(sum(</span>1, 2, 3, 4, 5, 6)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 21</span></pre>
</div>
<h4>5、函数重载</h4>
<p>java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况</p>
<p>TS中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的</p>
<p>es5中出现同名方法,下面的会替换上面的方法</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 重载就相当于同名的函数,当es5中出现同名方法,下面的会替换上面的方法</span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> css(config){
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> css(config,value){
}</span></pre>
</div>
<p>ts重载,通过为同一个函数提供多个函数类型定义来实现多种功能的目的</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string): string;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(age: number): number;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(str: any): any{
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(<span style="color: rgba(0, 0, 255, 1)">typeof</span>str === 'string'<span style="color: rgba(0, 0, 0, 1)">){
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我叫:'+<span style="color: rgba(0, 0, 0, 1)"> str;
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我年龄:' +<span style="color: rgba(0, 0, 0, 1)"> str;
}
}
console.log(getInfo(</span>'张三')); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我叫:张三</span>
console.log(getInfo(20)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我年龄:20</span></pre>
</div>
<p>TypeScript的重载,分别返回了字符串(张三)和number类型(20)</p>
<p>改下代码:年龄属性变为可选</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string): string;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string, age: number): string;
</span><span style="color: rgba(0, 0, 255, 1)">function</span> getInfo(name: any, age?<span style="color: rgba(0, 0, 0, 1)">: any): any {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (age) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我叫:' + name + ',我的年龄是' +<span style="color: rgba(0, 0, 0, 1)"> age;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我叫:' +<span style="color: rgba(0, 0, 0, 1)"> name;
}
}
console.log(getInfo(</span>'张三')); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我叫:张三</span>
console.log(getInfo('张三', 20)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我叫:张三,我的年龄是20</span></pre>
</div>
<p>再改下:年龄属性给个默认值</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string): string;
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getInfo(name: string, age: number): string;
</span><span style="color: rgba(0, 0, 255, 1)">function</span> getInfo(name: any, age: number = 18<span style="color: rgba(0, 0, 0, 1)">): any {
</span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (age) {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我叫:' + name + ',我的年龄是' +<span style="color: rgba(0, 0, 0, 1)"> age;
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> '我叫:' +<span style="color: rgba(0, 0, 0, 1)"> name;
}
}
console.log(getInfo(</span>'张三')); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我叫:张三,我的年龄是18</span>
console.log(getInfo('张三', 20)); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我叫:张三,我的年龄是20</span></pre>
</div>
<h3>TypeScript中的类</h3>
<h4>1、ts中类的定义</h4>
<p>定义类的关键字为 class,后面紧跟类名,类可以包含以下几个模块(类的数据成员):</p>
<ul>
<li>
<p><strong>字段</strong> − 字段是类里面声明的变量。字段表示对象的有关数据。</p>
</li>
<li>
<p><strong>构造函数</strong> − 类实例化时调用,可以为类的对象分配内存。</p>
</li>
<li>
<p><strong>方法</strong> − 方法为对象要执行的操作。</p>
</li>
</ul>
<p><strong>创建类的数据成员:</strong></p>
<p>以下实例我们声明了类 Car,包含字段为 engine,构造函数在类实例化后初始化字段 engine。<br>this 关键字表示当前类实例化的对象。注意构造函数的参数名与字段名相同,this.engine 表示类的字段。<br>此外我们也在类中定义了一个方法 disp()。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Car {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 字段 </span>
<span style="color: rgba(0, 0, 0, 1)"> engine:string;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构造函数 </span>
<span style="color: rgba(0, 0, 0, 1)"> constructor(engine:string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.engine =<span style="color: rgba(0, 0, 0, 1)"> engine
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 方法 </span>
disp():<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"发动机为 : "+<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.engine)
}
}</span></pre>
</div>
<p>编译上面代码可以得到:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Car {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构造函数 </span>
<span style="color: rgba(0, 0, 0, 1)"> constructor(engine) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.engine =<span style="color: rgba(0, 0, 0, 1)"> engine;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 方法 </span>
<span style="color: rgba(0, 0, 0, 1)"> disp() {
console.log(</span>"发动机为 : " + <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.engine);
}
}</span></pre>
</div>
<p><strong>创建实例化对象:</strong></p>
<p>使用 <span style="color: rgba(255, 0, 0, 1)">new</span> 关键字来实例化类的对象,语法格式如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">var</span> object_name = <span style="color: rgba(0, 0, 255, 1)">new</span> class_name([ arguments ])</pre>
</div>
<p>例子:创建来一个 Car 类,然后通过关键字 new 来创建一个对象并访问属性和方法:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Car {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 字段</span>
<span style="color: rgba(0, 0, 0, 1)">engine:string;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 构造函数</span>
<span style="color: rgba(0, 0, 0, 1)">constructor(engine:string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.engine =<span style="color: rgba(0, 0, 0, 1)"> engine
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 方法</span>
disp():<span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>"函数中显示发动机型号 : " + <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.engine)
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 创建一个对象</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> obj = <span style="color: rgba(0, 0, 255, 1)">new</span> Car("XXSY1"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 访问字段</span>
console.log("读取发动机型号 : " + obj.engine); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 读取发动机型号 : XXSY1</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 访问方法</span>
obj.disp(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 函数中显示发动机型号 : XXSY1</span></pre>
</div>
<p>例子1:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
name: string; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">属性前面省略了public关键词</span>
constructor(n: string) {<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构造函数 实例化类的时候触发的方法</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> n;
}
run(): </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name);
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('张三'<span style="color: rgba(0, 0, 0, 1)">);
p.run(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三</span></pre>
</div>
<p>例子2:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
name: string;
constructor(name: string) {</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构造函数 实例化类的时候触发的方法</span>
<span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
getName(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name;
}
setName(name: string): </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('张三'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.getName()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三</span>
p.setName('李四'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.getName()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四</span></pre>
</div>
<h4>2、ts 中实现继承 extends、super</h4>
<p>类继承使用关键字 <span style="color: rgba(255, 0, 0, 1)">extends</span>,子类除了不能继承父类的私有成员(方法和属性)和构造函数,其他的都可以继承。</p>
<p>TypeScript <span style="color: rgba(255, 0, 0, 1)">一次只能继承一个类</span>,不支持继承多个类,但 TypeScript <span style="color: rgba(255, 0, 0, 1)">支持多重继承</span>(A 继承 B,B 继承 C)。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
name: string;
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('王五'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.run()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 王五在运动</span>
<span style="color: rgba(0, 0, 0, 1)">
class Web <span style="color: rgba(255, 0, 0, 1)">extends</span> Person { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 继承</span>
<span style="color: rgba(0, 0, 0, 1)">constructor(name: string) {
<span style="color: rgba(255, 0, 0, 1)">super</span>(name);</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">初始化父类的构造函数</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
}
work() {
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在工作`)
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> w = <span style="color: rgba(0, 0, 255, 1)">new</span> Web('李四'<span style="color: rgba(0, 0, 0, 1)">);
console.log(w.run()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span>
console.log(w.work()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span></pre>
</div>
<p>类继承后,子类可以对父类的方法重新定义,这个过程称之为方法的重写。</p>
<p>其中 <span style="color: rgba(255, 0, 0, 1)">super</span> 关键字是对父类的直接引用,该关键字可以引用父类的属性和方法。</p>
<p>需要注意的是子类只能继承一个父类,TypeScript 不支持继承多个类,但支持多重继承,如下实例:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
name: string;
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
class Child extends Person {}
class Web extends Child {} </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 多重继承,继承了 Child 和 Person 类</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> w = <span style="color: rgba(0, 0, 255, 1)">new</span> Web('张三'<span style="color: rgba(0, 0, 0, 1)">);
console.log(w.run()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span></pre>
</div>
<h4>3、类里面的修饰符</h4>
<p>TypeScript 中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。TypeScript 支持 3 种不同的访问权限。属性如果不加修饰符 默认就是 公有 (public)</p>
<ul>
<li>
<p><strong>public(默认)</strong> : 公有,可以在任何地方被访问。</p>
</li>
<li>
<p><strong>protected</strong> : 受保护,可以被其自身以及其子类和父类访问。</p>
</li>
<li>
<p><strong>private</strong> : 私有,只能被其定义所在的类访问。</p>
</li>
</ul>
<p><span style="color: rgba(255, 0, 0, 1)">public</span> : 公有,在当前类里面、子类 、类外面都可以访问</p>
<p>在子类中:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
public name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">公有属性</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
class Web extends Person {
constructor(name: string) {
super(name);</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">初始化父类的构造函数</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span>.name}在运动-<span style="color: rgba(0, 0, 0, 1)">子类`
}
work() {
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在工作`)
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> w = <span style="color: rgba(0, 0, 255, 1)">new</span> Web('李四'<span style="color: rgba(0, 0, 0, 1)">);
console.log(w.run()); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动-子类</span>
w.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span></pre>
</div>
<p>类外部访问公有属性:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
public name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">公有属性</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('哈哈哈'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.name); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 哈哈哈</span></pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">protected</span>:保护类型,在类里面、子类里面可以访问,在类外部没法访问</p>
<p>在子类中:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
protected name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">保护属性</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
class Web extends Person {
constructor(name: string) {
super(name);</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">初始化父类的构造函数</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
}
work() {
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在工作`)
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> w = <span style="color: rgba(0, 0, 255, 1)">new</span> Web('李四'<span style="color: rgba(0, 0, 0, 1)">);
w.work(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span>
console.log(w.run()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span></pre>
</div>
<p>类外外部没法访问保护类型的属性:会报错</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
protected name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">保护类型</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('哈哈哈'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.name); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 会报错</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201016154328683-1419607324.png"></p>
<p><span style="color: rgba(255, 0, 0, 1)">private</span> :私有,在类里面可以访问,子类、类外部都没法访问</p>
<p>在子类中:会报错</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
private name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">私有</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}<br>
class Web extends Person {
constructor(name: string) {
super(name)
}
work() {
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在工作`)
}
}</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201016154557128-869510319.png"></p>
<p>在类外部里:会报错</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
private name: string;</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">私有</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run(): string {
</span><span style="color: rgba(0, 0, 255, 1)">return</span> `${<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('哈哈哈'<span style="color: rgba(0, 0, 0, 1)">);
console.log(p.name);
console.log(p.run());</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201016155609082-1557566975.png"></p>
<h4>4、静态属性 静态方法</h4>
<p><span style="color: rgba(255, 0, 0, 1)">static</span> 关键字用于定义类的数据成员(属性和方法)为静态的,静态成员可以直接通过类名调用。 </p>
<p>例子1:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Father {
static myName: string </span>= 'mySkey'<span style="color: rgba(0, 0, 0, 1)">;
static getAge(): number{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> 23<span style="color: rgba(0, 0, 0, 1)">;
}
}
console.log(Father.myName); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> mySkey</span>
console.log(Father.getAge()); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 23</span></pre>
</div>
<p>例子2:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Per {
public name: string;
public age: number </span>= 20<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">静态属性</span>
static sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
run() {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">实例方法</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在运动`)
}
work() {
console.log(`${</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.name}在工作`)
}
static print() {</span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">静态方法里面没法直接调用类里面的属性</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
console.log(</span>'print方法' +<span style="color: rgba(0, 0, 0, 1)"> Per.sex);
}
}
Per.print(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> print方法男</span>
console.log(Per.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span></pre>
</div>
<h4>5、只读</h4>
<p><span style="color: rgba(255, 0, 0, 1)">readonly</span> 申明的只读的属性不能再更改</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Person {
readonly name: string </span>= 'mySkey'<span style="color: rgba(0, 0, 0, 1)">;
}
let mySkey </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Person();
console.log(mySkey.name); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> mySkey</span>
mySkey.name = '1111'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Error 报错</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201019094125520-1069435109.png"> </p>
<h4>6、get 与 set 来截取对对象成员的访问</h4>
<p>TypeScript支持getters/setters来截取对对象成员的访问。 它能帮助你有效的控制对对象成员的访问 </p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 就像女人的年龄是个秘密,只会对不喜欢的人告诉真实的</span>
let isLike: <span style="color: rgba(0, 0, 255, 1)">boolean</span> = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
class Woman{
private _age: number </span>= 16<span style="color: rgba(0, 0, 0, 1)">;
get age(): number{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">._age;
}
set age(num: number){
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!<span style="color: rgba(0, 0, 0, 1)">isLike){
</span><span style="color: rgba(0, 0, 255, 1)">this</span>._age =<span style="color: rgba(0, 0, 0, 1)"> num;
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
console.log(</span>'告诉你的也是假的!!'<span style="color: rgba(0, 0, 0, 1)">)
}
}
}
let woman </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Woman();
woman.age </span>= 23<span style="color: rgba(0, 0, 0, 1)">;
console.log(woman.age); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 23</span>
<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 看吧,不喜欢你,所以你知道了她的真实年龄,如果把isLike改为true,那么她每天就是16了</span>
<span style="color: rgba(0, 0, 0, 1)">
let isLike: </span><span style="color: rgba(0, 0, 255, 1)">boolean</span> = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
class Woman{
private _age: number </span>= 16<span style="color: rgba(0, 0, 0, 1)">;
get age(): number{
</span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">._age;
}
set age(num: number){
</span><span style="color: rgba(0, 0, 255, 1)">if</span>(!<span style="color: rgba(0, 0, 0, 1)">isLike){
</span><span style="color: rgba(0, 0, 255, 1)">this</span>._age =<span style="color: rgba(0, 0, 0, 1)"> num;
}</span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">{
console.log(</span>'告诉你的也是假的!!'<span style="color: rgba(0, 0, 0, 1)">)
}
}
}
let woman </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Woman();
woman.age </span>= 23<span style="color: rgba(0, 0, 0, 1)">;
console.log(woman.age);
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 告诉你的也是假的!!</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> 16</span></pre>
</div>
<h4>7、多态</h4>
<p>父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">class Animal {
name: string;
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
eat() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">具体吃什么不知道 ,具体吃什么?继承它的子类去实现 ,每一个子类的表现不一样</span>
console.log('吃的方法'<span style="color: rgba(0, 0, 0, 1)">)
}
}
class Dog extends Animal {
constructor(name: string) {
super(name)
}
eat() {
console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name + '啃骨头'<span style="color: rgba(0, 0, 0, 1)">)
}
}
class Cat extends Animal {
constructor(name: string) {
super(name)
}
eat() {
console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name + '吃鱼'<span style="color: rgba(0, 0, 0, 1)">)
}
}
let ANAME: string </span>= "Tom"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 0, 255, 1)">var</span> D = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Dog(ANAME);
D.eat(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Tom啃骨头</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> C = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Cat(ANAME);
C.eat(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Tom吃鱼</span></pre>
</div>
<h4>8、抽象类</h4>
<p>typescript 中的抽象类:它是提供其他类继承的基类,不能直接被实例化。</p>
<p>用 <span style="color: rgba(255, 0, 0, 1)">abstract</span> 关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现</p>
<p>abstract 抽象方法<span style="color: rgba(255, 0, 0, 1)">只能放在抽象类里面</span></p>
<p>例子1:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">abstract class Person {
abstract type: string </span>= 'animal'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 抽象类</span>
<span style="color: rgba(0, 0, 0, 1)">sing(){
console.log(</span>'我会唱歌!'<span style="color: rgba(0, 0, 0, 1)">)
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> let person = new Person() // Error 无法创建抽象类的实例</span>
<span style="color: rgba(0, 0, 0, 1)">class Myskey extends Person {
type: string </span>= 'animal123'; <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 无法继承,而且必须重写</span>
<span style="color: rgba(0, 0, 0, 1)">constructor(){
super()
</span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.sing()
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> my = <span style="color: rgba(0, 0, 255, 1)">new</span> Myskey(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 我会唱歌!</span>
console.log(my.type);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> animal123</span></pre>
</div>
<p>例子2:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">abstract class Animal {
public name: string;
constructor(name: string) {
</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}
abstract eat(): any;</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">抽象方法不包含具体实现并且必须在派生类中实现。</span>
<span style="color: rgba(0, 0, 0, 1)">run() {
console.log(</span>'其他方法可以不实现'<span style="color: rgba(0, 0, 0, 1)">)
}
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> var a = new Animal() /*错误的写法*/</span>
<span style="color: rgba(0, 0, 0, 1)">
class Dog extends Animal {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">抽象类的子类必须实现抽象类里面的抽象方法</span>
<span style="color: rgba(0, 0, 0, 1)">constructor(name: any) {
super(name)
}
eat() {
console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name + '吃粮食'<span style="color: rgba(0, 0, 0, 1)">)
}
}
class Cat extends Animal {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">抽象类的子类必须实现抽象类里面的抽象方法</span>
<span style="color: rgba(0, 0, 0, 1)">constructor(name: any) {
super(name)
}
eat() {
console.log(</span><span style="color: rgba(0, 0, 255, 1)">this</span>.name + '吃老鼠'<span style="color: rgba(0, 0, 0, 1)">)
}
}
</span><span style="color: rgba(0, 0, 255, 1)">var</span> d = <span style="color: rgba(0, 0, 255, 1)">new</span> Dog('小花花'<span style="color: rgba(0, 0, 0, 1)">);
d.eat(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 小花花吃粮食</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> c = <span style="color: rgba(0, 0, 255, 1)">new</span> Cat('小花猫'<span style="color: rgba(0, 0, 0, 1)">);
c.eat(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 小花花吃老鼠</span>
</pre>
</div>
<h3>TypeScript中的接口</h3>
<p>接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。</p>
<p>接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。</p>
<p>typescrip 中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等</p>
<h4>1、ts 中自定义方法传入参数,对 json 进行约束</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> printLabel(labelInfo: { label: string }): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(</span>'printLabel'<span style="color: rgba(0, 0, 0, 1)">, labelInfo);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> printLabel('张三'); //错误写法</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> printLabel({name:'张三'});//错误的写法</span>
printLabel({label:'张三'});<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">正确的写法 printLabel { label: '张三' }</span></pre>
</div>
<h4>2、接口 interface:行为和动作的规范,对批量方法进行约束</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">就是传入对象的约束 属性接口</span>
<span style="color: rgba(0, 0, 0, 1)">interface FullName {
firstName: string; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意;结束</span>
<span style="color: rgba(0, 0, 0, 1)">secondName: string;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> printName(name: FullName) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必须传入对象firstNamesecondName</span>
console.log(name.firstName + '--' +<span style="color: rgba(0, 0, 0, 1)"> name.secondName);
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> printName('1213');// 错误</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> obj = { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">传入的参数必须包含 firstNamesecondName</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
age: </span>20<span style="color: rgba(0, 0, 0, 1)">,
firstName: </span>'张'<span style="color: rgba(0, 0, 0, 1)">,
secondName: </span>'三'<span style="color: rgba(0, 0, 0, 1)">
};
printName(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张--三</span></pre>
</div>
<p><img src="https://img2020.cnblogs.com/blog/31691/202010/31691-20201019103607620-1458388181.png"></p>
<p>修改为:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">就是传入对象的约束 属性接口</span>
<span style="color: rgba(0, 0, 0, 1)">interface FullName {
firstName: string; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意;结束</span>
<span style="color: rgba(0, 0, 0, 1)">secondName: string;
age: number;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> printName(name: FullName) {
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 必须传入对象firstNamesecondName</span>
console.log(name.firstName + '--' + name.secondName + '--' +<span style="color: rgba(0, 0, 0, 1)"> name.age );
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> printName('1213');// 错误</span>
<span style="color: rgba(0, 0, 255, 1)">var</span> obj = { <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">传入的参数必须包含 firstNamesecondName</span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
age: </span>20<span style="color: rgba(0, 0, 0, 1)">,
firstName: </span>'张'<span style="color: rgba(0, 0, 0, 1)">,
secondName: </span>'三'<span style="color: rgba(0, 0, 0, 1)">
};
printName(obj); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张--三--20</span></pre>
</div>
<h4>3、参数的顺序可以不一样</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface FullName {
firstName: string;
secondName: string;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getName(name: FullName) {
console.log(name)
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 参数的顺序可以不一样</span>
<span style="color: rgba(0, 0, 0, 1)">getName({
secondName: </span>'secondName'<span style="color: rgba(0, 0, 0, 1)">,
firstName: </span>'firstName'<span style="color: rgba(0, 0, 0, 1)">
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { secondName: 'secondName', firstName: 'firstName' }</span></pre>
</div>
<h4>4、也可以设置可选属性</h4>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface FullName {
firstName: string;
secondName</span>?<span style="color: rgba(0, 0, 0, 1)">: string;
}
</span><span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> getName(name: FullName) {
console.log(name)
}
getName({
firstName: </span>'firstName'<span style="color: rgba(0, 0, 0, 1)">
})
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> { firstName: 'firstName' }</span></pre>
</div>
<p><span style="color: rgba(255, 0, 0, 1)">注意</span>:属性接口中定义的属性,在传入的参数必须全部包含,否则会报错。或者可以设置为可选属性。</p>
<p>例如:ajax</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">interface Config {
type: string;
url: string;
data</span>?<span style="color: rgba(0, 0, 0, 1)">: string;
dataType: string;
}
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">原生js封装的ajax </span>
<span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> ajax(config: Config) {
</span><span style="color: rgba(0, 0, 255, 1)">var</span> xhr = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> XMLHttpRequest();
xhr.open(config.type, config.url, </span><span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">);
xhr.send(config.data);
xhr.onreadystatechange </span>= <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (xhr.readyState == 4 && xhr.status == 200<span style="color: rgba(0, 0, 0, 1)">) {
console.log(</span>'success!!!'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 0, 255, 1)">if</span> (config.dataType == 'json'<span style="color: rgba(0, 0, 0, 1)">) {
console.log(JSON.parse(xhr.responseText));
} </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(xhr.responseText)
}
}
}
}
ajax({
type: </span>'get'<span style="color: rgba(0, 0, 0, 1)">,
data: </span>'name=zhangsan'<span style="color: rgba(0, 0, 0, 1)">,
url: </span>'http://a.itying.com/api/productlist', <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">api</span>
dataType: 'json'<span style="color: rgba(0, 0, 0, 1)">
})</span></pre>
</div>
<h3>TypeScript中的泛型</h3>
<p>软件工程中,我们不仅要创建一致的定义良好的 API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。</p>
<p>在像 C# 和 Java 这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">function</span> add<T>(a: T, b: T): <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> {
console.log(a)
console.log(b)
}
add(</span>1, 2) <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 1 // 2</span>
add('a', 'b') <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> a // b</span></pre>
</div>
<p>接口 + 泛型 -> 函数类型</p>
<div class="cnblogs_code">
<pre>let addFn: AddFn<<span style="color: rgba(0, 0, 255, 1)">boolean</span>> = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> (a, b) {
console.log(a)
console.log(b)
</span><span style="color: rgba(0, 0, 255, 1)">return</span> [{ id: 1, name: '浙大正呈'<span style="color: rgba(0, 0, 0, 1)"> }]
}
interface arrIF {
readonly id: number,
name: string
}
interface AddFn</span><T><span style="color: rgba(0, 0, 0, 1)"> {
(a: T, b: number): arrIF[]
}
console.log(addFn(</span><span style="color: rgba(0, 0, 255, 1)">false</span>, 2<span style="color: rgba(0, 0, 0, 1)">))
</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> false </span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> 2</span><span style="color: rgba(0, 128, 0, 1)">
//</span><span style="color: rgba(0, 128, 0, 1)"> [ { id: 1, name: '浙大正呈' } ]</span></pre>
</div>
<h2 id="already-familiar-with-typescript">TypeScript熟悉使用者?</h2>
<ul>
<li>查看最新TypeScript版本的新特性</li>
<li>深入学习研究TypeScript手册指南</li>
<li>阅读.d.ts创建指南</li>
</ul>
<p> </p>
<p>https://www.jianshu.com/p/0ebd56cb22d2</p>
<p>https://www.bilibili.com/video/BV1Qa4y1E7U1/?spm_id_from=333.788.videocard.15</p>
</div>
<div id="MySignature" role="contentinfo">
<p><img src="http://wenwen.soso.com/p/20110207/20110207114744-127883651.jpg" /></p><br><br>
来源:https://www.cnblogs.com/joe235/p/13814753.html
頁:
[1]