65.9K
CodeProject 正在变化。 阅读更多。
Home

10 天学会 Angular - 第 1 天 - 第 1 部分

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.84/5 (67投票s)

2017 年 7 月 27 日

CPOL

28分钟阅读

viewsIcon

163929

downloadIcon

5472

最新版本 Angular JavaScript 和 TypeScript 的基础知识

在《7 天学习 MVC 项目》大获成功后,我决定写一个关于目前最流行的 JavaScript 框架之一 Angular 的新系列。希望大家喜欢这个为期 10 天的旅程。我们将通过一个项目逐步学习最新版本的 Angular。

注意:10 天不等于 10 篇文章。为了保持内容简洁明了,有时我们会将单独的一天分成多个部分。

第 1 天将非常基础,主要讲解 JavaScript 和 TypeScript。
第 2 天将讲解 Angular 的基本术语、设置和“Hello World”示例。
从第 3 天开始,我们将启动我们的 Angular 项目,并且随着每一天的进展,您将看到越来越多的高级内容。

正确选择您的一天

我建议大家根据自己的兴趣直接跳到第 1 天、第 2 天或第 3 天。如果您认为自己了解 TypeScript,那么可以直接从第 2 天开始。

为了充分利用本系列文章,我建议大家从第 1 天开始。(至少快速浏览第 1 天作为复习。)

注意:Angular(通常称为 Angular 2 或更高版本)与其前身 AngularJS(通常称为 Angular 1)非常不同。本系列中使用的所有术语和解释完全基于 Angular(即 Angular 2 或更高版本)。

完整系列

  1. 第 1 天 – 第 1 部分
  2. 第 1 天 – 第 2 部分
  3. 第 2 天
  4. 第 3 天
  5. 第 4 天 – 第 1 部分
  6. 第 4 天 - 执行技巧
  7. 第 4 天 – 第 2 部分
  8. 第 4 天 – 第 3 部分
  9. 第 5 天(即将推出)
  10. 第 6 天(即将推出)
  11. 第 7 天(即将推出)
  12. 第 8 天(即将推出)
  13. 第 9 天(即将推出)
  14. 第 10 天(即将推出)

目录 – 第 1 天 – 第 1 部分

什么是 JavaScript,为什么要使用 JavaScript?

在我几乎所有的培训中,我都会问这个问题,大多数时候,我听到的答案是“为了验证”。

JavaScript 远不止于此。HTML 是每个 Web 应用程序的基本需求。无论您是 .NET 还是 Java 开发人员,没有 HTML 都无法创建 Web 应用程序。

HTML 最大的局限性在于它是静态的。如果您创建一个 HTML 页面,以粗体显示“Hello world”,无论您刷新页面多少次,它都会始终显示相同的输出。

为了克服这种静态限制,我们过去常常借助 PHP、ASP.NET 等服务器端技术。这些服务器端技术在每次请求时生成不同的 HTML 并发送回来,从而形成了一个完整的动态应用程序。

重要提示

要学习 Angular,必须具备 JavaScript 和 HTML 的基本知识。当我提到基本知识时,不仅仅是理论知识。它应该是理论 + 实践。您可以查看以下链接以获取一些基本概念:

这种传统方法有什么问题?

问题在于在现代时代,竞争巨大。所有企业都在努力使他们的 Web 应用程序优于竞争对手的应用程序。他们正在尝试构建更快、用户体验更好的 Web 应用程序。

仅依赖服务器端技术会影响我们应用程序的整体性能。试着想象一下服务器的角色(在大多数应用程序中):

  1. 它处理客户端请求
  2. 从不同地方获取数据(可能来自数据库、服务等)
  3. 对这些数据执行一些逻辑
  4. 生成 HTML
  5. 返回响应

试着考虑另一种方法——服务器将数据作为响应发送而不是 HTML。在客户端,HTML 将在 JavaScript 的帮助下动态操作和创建。这种方法的优点是:

  • 性能 - 它将改善用户体验,因为应用程序性能将比以前更好。在这种方法中,服务器上的开销将减少,并且通过网络传输的数据将比以前小。(它将只是数据。以前,它是数据与 HTML 标签的组合。)
  • 更便宜的服务器 - 如今,几乎所有应用程序都正在迁移到云环境。在云中,服务器成本将根据使用情况而定。我们将根据我们需要的 RAM 和硬盘容量、我们消耗的带宽等收取费用。

因此,上述问题的简单答案将如下:

“JavaScript 是一种客户端脚本语言,用于动态操作和创建 HTML。使用 JavaScript 而不是服务器端技术可以提高性能和整体 Web 体验。”

NodeJS 简介

正如我所说,JavaScript 主要用于动态操作和创建 HTML。

NodeJS 通过提供一个完整的环境,让 JavaScript 可以在浏览器之外执行,从而将 JavaScript 提升到一个新的水平。是的,你没有听错。你现在可以在没有浏览器的情况下执行 JavaScript。

到目前为止,您一定见过人们使用 Java、C#、VB.NET 等编程语言开发各种应用程序(例如基于桌面的应用程序、基于 Web 的应用程序、Web 服务器、Web 服务等)。为了做到这一点,他们必须首先在他们的机器中安装适当的框架。例如,如果您想使用 C# 开发应用程序,那么您必须安装 .NET Framework。

安装后,您将能够使用 C# 创建应用程序,并且 .NET Framework 将为您提供开发和执行所需的所有内容。

现在我们也可以使用 JavaScript 开发此类应用程序,为此,我们需要 NodeJS。您可以在 https://node.org.cn/en/ 找到 NodeJS 安装程序。只需点击链接并安装即可。

NPM 简介?

NPM 代表 Node Package Manager。它将作为 NodeJS 安装的一部分安装。

这个命令行工具仅仅是一个用于 JavaScript 和 Node 包的包管理器。

使用此工具,我们可以从 NPM 仓库下载任何 JavaScript 库和 Node 包。

我们也可以选择其他包管理器。Maven、Nuget 和 Bower 就是其中的一些例子。每个包管理器都有其自身的特点。例如,Nuget 因下载与 .NET 相关的包而闻名。

NPM 主要用于 Node 包。Node 包是使用 Node 创建的实用程序。它们可以通过 NPM 简单地下载和安装。TypeScript 编译器就是我们将在下一步安装的 Node 包之一。

注意:在本部分中,我们不会探索任何与 NodeJS 开发相关的内容。我们安装 Node 主要是因为 NPM。NPM 将在本系列的后续部分中使用。

JavaScript 中的命名空间和模块化问题讨论

在我们开始 Angular 之前,我们必须了解 JavaScript 的一个问题以及行业为其实现的标准解决方案。问题是命名空间和模块化。

什么是命名空间?

命名空间让我们将相关的代码/功能分组到一个组中。相似或相关的功能/代码将作为同一个命名空间的一部分编写,这样它就完全独立于其他命名空间。

每个命名空间都有自己的作用域,并且始终在其自身的作用域内执行,这与在全局作用域中执行的其他代码不同。它使得在一个命名空间中声明的变量、函数、类等对其他命名空间不可见,除非它们被显式导出。

默认情况下,在 JavaScript 世界中,我们创建的所有内容都属于全局命名空间。试着想象一下,我们在一个 HTML 文件中尝试重用多个外部 JavaScript 文件。如果所有内容都是全局的,那么这些 JavaScript 文件中定义的内容很可能会发生冲突。多个文件可能最终定义了相同的函数,但逻辑不同。

C# 和 Java 等面向对象语言提供了创建命名空间的功能,这在 JavaScript 中是缺失的。JavaScript 中没有现成的关键字来创建命名空间,但可以通过编写自定义“逻辑”来实现。让我向您展示一种借助“函数作用域”和 IIFE 在 JavaScript 中实现命名空间的方法。

IIFE 代表“立即调用函数表达式”。它是一个在创建后立即执行的函数。

这里是一个简单的 IIFE 的快速预览。

(function () {
    alert('a');
})();

如您所见,我们有一个简单的匿名函数,它将立即执行。

让我们快速演示一下 JavaScript 命名空间。
(学习 Angular 不必进行以下实践。如果您愿意,只需阅读每个步骤即可。)

第 1 步 – 设置文件夹

创建一个新文件夹“JsNamespaceExample”,并在其中创建三项内容。一个名为 Test.html 的 HTML 文件和两个名为“Reusable.js”和“Index.js”的 JavaScript 文件。

第 2 步 – 创建带功能的命名空间

打开“Reusable.js”文件,创建两个简单的函数“add”和“sub”,并将它们封装在 IIFE 中。

(function () {
    function add(x, y) {
        alert(x+y);
    }
    function sub(x, y) {
        alert(x-y);
    }
})();

现在,“add”和“sub”函数对 IIFE 来说是私有的。它们绝不会被其他人的代码替换或覆盖。

第三步——暴露公共函数

这将非常容易。首先让我们看看代码

var MathsNameSpace;
(function (p) {
    function add(x, y) {
        alert(x+y);
    }
    function sub(x, y) {
        alert(x-y);
    }
    p.add = add;
})(MathsNameSpace || (MathsNameSpace = {}));

让我们理解上面的逻辑。

  1. IIFE 接受一个参数。
  2. JavaScript 本质上是动态的,所以“p.add=add”会给“p”添加一个新的属性“add”。
  3. p.add 将指向 IIFE 内部定义的 add 函数。
  4. 在调用 IIFE 时,全局变量作为参数传入。
  5. 这意味着最终,该全局变量将拥有一个名为 add 的属性,它将指向 IIFE 内部定义的 add 函数。

第 3 步 – 调用命名空间函数

打开 Index.js 文件,将以下代码放入其中。

MathsNameSpace.add(1, 2);

如您所见,“Reusable.js”中定义的全局变量在“Index.js”中使用。

第 4 步 – 设置 HTML

打开 Test.html 并在其中写入以下 HTML 代码片段。

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <meta charset="utf-8" />
    <script src="Reusable.js"> </script>
    <script src="Index.js"> </script>
</head>
<body>
</body>
</html>

第五步——执行和测试

只需在某个浏览器中打开 Test.html 文件。

如果您没有理解上述实现命名空间的逻辑,那么完全没有问题。继续前进即可。在行业中,存在许多具有不同语法和逻辑的此类解决方案。稍后,我们将研究 TypeScript,它将使使用命名空间成为一项非常容易的任务。

什么是模块化?

模块化意味着将我们的应用程序代码/功能分组到多个模块中。相似或相关的功能/代码将作为同一个模块的一部分编写,这样它就完全独立于其他模块。

每个模块都有自己的作用域,并且始终在其自身的作用域内执行,这与在全局作用域中执行的其他代码不同。它使得在一个模块中声明的变量、函数、类等对其他模块不可见,除非它们被显式导出。

模块 == 命名空间是真的吗?

完全不是。模块还负责依赖管理。

当涉及到命名空间时,开发人员需要手动处理所有依赖项。例如,在上次演示中,您一定注意到,在 HTML 文件中,我们手动按正确顺序包含了所有 JavaScript 文件(首先是“reusable.js”,然后是“Index.js”)。

如果我们先包含“Index.js”再包含“reusable.js”,或者只包含“index.js”,我们将得不到预期的输出。

试想一下,如果层级结构太大,会发生什么。假设我们有以下情况:

  1. Namespace1 依赖于 Namespace2Namespace3
  2. Namespace2 依赖于 Namespace4Namespace5
  3. Namespace4 依赖于 Namespace6

在这种情况下,我们应该按以下顺序包含 Js 文件

  1. 命名空间6
  2. 命名空间5
  3. 命名空间4
  4. 命名空间3
  5. 命名空间2
  6. 命名空间1

在这种情况下,命名空间是不够的。我们需要更好的解决方案。解决方案是模块,它还负责依赖管理。

JavaScript 目前不支持模块化。ES2015(新版本)内置了模块支持,但不幸的是我们不能百分之百依赖它。目前,ES2015 并非所有浏览器都支持。

在 JavaScript 世界中(至少目前如此),模块化可以通过两种概念逻辑实现。

  • 模块格式化器 - 这是我们编写代码的格式。AMD 和 Common JS 是模块格式化器的两个例子。它只是封装应用程序逻辑的标准方式。
  • 模块加载器 – 它是包含用于处理模块格式化器的 API 的库。SystemJs 和 requireJs 是模块加载器的两个示例。

如果您没有理解定义,请不要担心。

只需继续,查看演示,然后再次返回并阅读定义。
(再次强调,尝试这个实践并非强制。只需浏览这些步骤。这个实践的主要目的是让您一瞥为了在 JavaScript 中获得模块化支持而需要编写的代码。不要过于拘泥于语法。在本系列的后续部分中,我们将看到借助 TypeScript 实现相同目标的更简单方法。)

AMD 与 System JS 演示

第 1 步 – 设置文件夹

创建一个名为“AmdExample”的新文件夹,并在其中创建三项内容。一个名为 Test.html 的 HTML 文件和两个名为“Reusable.js”和“Customer.js”的 JavaScript 文件。

第二步——下载模块加载器

打开命令提示符并导航到“AmdExample”文件夹。使用 npm 下载“systemjs”库,如下所示:

npm install systemjs

注意

命令区分大小写。它是 systemjs 而不是 systemJs

它将在“AmdExample”文件夹内创建一个新的子文件夹,并将下载的 SystemJs 库放置在其中。

第三步——定义可重用模块

在“Reusable.js”文件中以 AMD 格式创建两个函数 getValuegetValue2

define(["exports"], function (exports) {
    function getValue() {
        return getValue2();
    }
    exports.getValue = getValue;
    function getValue2() {
        return "Sukesh Marla";
    }
});

在上面的代码中,我们创建了一个名为“reusable”的新 JavaScript 模块。(文件名成为模块名),使用的格式是 AMD 格式。

  1. 我们必须调用“define”函数。
  2. define”函数期望两个参数
    1. 依赖项——例如,在我们的例子中,它需要访问“exports”
    2. 一个函数——它封装了我们的逻辑,并将依赖项作为参数

defineexport”关键字都定义在 SystemJs 中。

第四步——定义客户模块

将以下代码放入 Customer.js 中。

define(["exports", './reusable.js'], function ( exports, reusabl) {
    "use strict";
    alert(reusabl.getValue());
});

这次,我们创建了一个名为“customer”的 JavaScript 模块。

您还可以看到“customer”模块正在使用“reusable”模块。

第五步——导入启动文件

将以下 HTML 代码放入 Test.html 中。

<!DOCTYPE html>
<html>
<head>
    <title></title>
	<meta charset="utf-8" />
    <script src="../../node_modules/systemjs/dist/system.js"></script>
    <script>
        SystemJS.import('./Customer.js');
    </script>

</head>
<body>

</body>
</html>

如您所见,“Customer.js”使用 SystemJS 加载到 Test.html 中。

加载后,Customer.js 中的语句将逐行执行。

Customer.js 依赖于 Reusable.js,因此在运行时 Reusable.js 将被下载。

第六步——执行

现在为了测试这样的示例,我们必须托管这个 Web 项目。只需在您选择的 Web 服务器中托管这些示例,然后向 Test.html 文件发送请求。

对于此演示和未来的演示,我们将使用一个名为“http-server”的 Node 模块。它是一个非常简单的命令行 http 服务器。它根本不需要任何配置。

使用以下命令安装它。

npm install http-server -g

如您所见,这次我们使用“-g”作为“npm install”的标志。

当我们要安装一个将直接在命令行中使用的 Node 模块时,将使用此标志。安装后,其二进制文件也会出现在您的 PATH 环境变量中。

安装完成后,只需在命令提示符中输入“http-server”。它将启动一个指向同一文件夹的 Web 服务器。服务器启动后,打开浏览器并向 Test.html 文件发送请求。

模块格式化器与模块加载器之间的兼容性

并非所有模块加载器都支持所有模块格式化器。例如,requireJs 只支持 AMD 格式,而 SystemJs 支持包括 AMD 和 Common JS 在内的许多模块格式化器。

让我们通过两个快速演示来正确理解模块加载器和模块格式化器。

什么是 Angular,为什么要使用 Angular?

Angular 最简单的定义应该是:“它是一个用于构建基于 HTML 的动态应用程序的 JavaScript 框架。”

注意:不要混淆“库”和“框架”这两个词。

仅仅是可重用 API 的集合,而框架是构建应用程序的完整平台。

将提供一些即用型函数(或类),而框架将通过编译器、垃圾回收等实用程序、完整的执行运行时以及许多可重用库来帮助开发人员。框架的最佳例子是 .NET 或 Java 框架。

在第 10 天结束时,您将自动意识到将 Angular 称为框架而不是库的原因。

使用 Angular 作为我们的前端框架为我们的前端开发增加了许多价值。

  • 如您所知,JavaScript 主要用于在客户端操作和创建 HTML。Angular 使这变得容易
  • Angular 允许我们以非常结构化的方式开发 UI。与传统开发方法中直接在代码(JavaScript 代码)中访问和操作 HTML 内容不同,Angular 允许我们以一种非常松散耦合的方式进行操作。我们可以看到 UI (HTML) 和 UI 逻辑 (JavaScript 代码) 之间存在清晰的分离
  • Angular 允许我们扩展现有 HTML (UI) 而不影响 JavaScript 逻辑。
  • Angular 允许我们以组件导向的风格开发 UI。这是 HTML 5 世界中的一个新标准,它要求我们将 UI 开发为可重用 Web 组件的集合。

不要为了理解这些要点而绞尽脑汁。我建议您完成 10 天系列,然后再次回顾这些要点。

什么是 TypeScript?

TypeScript 是一种编译语言,它将在编译时生成 JavaScript

生成的 JavaScript 将是相同的传统 JavaScript 代码。

简单来说,“我们将用 TypeScript 编写代码。编译它并生成 JavaScript,然后直接在我们的 HTML 中使用这些自动生成的 JavaScript,而不是手动编写 JavaScript。”

如何设置 TypeScript?

打开命令提示符,输入以下命令

npm install typescript -g

为了测试安装,只需在命令提示符中输入 tsc 并按 Enter。您应该会看到类似以下的内容:

如果您收到消息“npm is not recognized as an internal or external command”,请以管理员身份再次安装 NodeJS。

如果您收到消息“tsc is not recognized as an internal or external command”,请以管理员身份打开命令提示符,然后再次尝试上述命令。

为什么要使用 TypeScript?

你们中的许多人一定在想,如果我们的最终目标只是 JavaScript,为什么我们应该使用 TypeScript 而不是 JavaScript。

TypeScript 将给我们带来以下好处:

  1. 学习曲线

    学习 TypeScript 相对容易。它不会像从头开始学习一种新的编程语言。如果你了解 JavaScript,你就在一定程度上了解 TypeScript。来自 C++ 背景的人会觉得 C# 和 Java 语法很容易,因为 C# 和 Java 都继承了 C++ 的语法。

    同样,TypeScript 也继承了 JavaScript 的语法。因此,TypeScript 被称为 JavaScript 的超集。

    例如,TypeScript 中的 functions 可以定义如下:

    function myFunction(a,b){
    	return a+b;
    }

    If 条件将编写如下:

    if(b== “A”){
    }

    上面的代码片段清晰地描绘了 JavaScript 和 TypeScript 语法之间的相似性。我们将在接下来的部分详细介绍更多 TypeScript 演示。

  2. 编译环境

    JavaScript 不是编译型语言,但 TypeScript 是。它通过减少大量运行时错误使我们的生活变得轻松。

    让我们看三个 JavaScript 示例。

    示例 1

    var a=1;
    console.log(a); //display 1
    a= “Sukesh”;
    console.log(a); //display “Sukesh”

    如您所见,JavaScript 中没有类型安全性,或者简单地说,没有固定的数据类型。一个现在是整数的变量,稍后可能是字符串。这为许多运行时错误打开了大门。

    另一方面,TypeScript 允许我们在声明变量时指定确切的数据类型。如果发生无效赋值,将导致编译错误。

    示例 2

    function myFunction(a,b){
    ...
    }
    myFunction();
    myFunction(1,2,3)
    

    Function 定义了两个参数并调用了两次。第一次调用时没有参数,第二次调用时有三个参数。

    由于 JavaScript 不是编译型语言,它只是简单地工作,并可能导致某种运行时异常。

    TypeScript 不允许这样做。如果编写此类代码,它将生成编译错误。

    示例 3

    function myFunction(a,b){
    console.log ('a');
    }
    function myFunction(a,b,c){
    console.log ('b');
    }
    myFunction(1,2); // display b
    myFunction(1,2,3); // display b

    如您所见,我们有两个同名但参数不同的函数。许多人会称之为函数重载。问题是,JavaScript 中有函数重载吗?没有,我们没有。无论您在调用函数时传递多少个参数,只有一个会持续调用,另一个会被简单忽略。

    TypeScript 目前不支持方法重载,但它甚至不允许您编写两个同名函数。它会抛出编译错误。

  3. 新功能

    目前,我们仅限于“ES5”(当前 JS 标准)特性,因为目前所有浏览器都不能完全兼容 ES2015。

    TypeScript 允许我们做许多我们通常在 JavaScript 中无法做到的事情。编译后,它将为我们生成适当的逻辑。

    例如,TypeScript 支持模块,而 JavaScript 不支持。使用 TypeScript 模块编写的代码将简单地生成 AMD 或“CommonJS”代码。

    (我们很快会看到一个演示。)

  4. 轻松迁移

    归根结底,浏览器只会执行 JavaScript。如果您考虑手动编写 JavaScript 而不是使用 TypeScript,那么将来将代码迁移到新的 ES 标准会变得困难,因为迁移会导致大量的重写。

    对于 TypeScript,这将是一个一步到位的过程。

    (我们很快会看到一个演示。)

TypeScript 基础

现在让我们做一些 TypeScript 演示。

初始设置

  • 确保 NodeJS 已安装。
  • 确保 TypeScript 已安装。
  • 准备您的编辑器。我们需要一个编辑器来编写代码。您可以选择您喜欢的编辑器。您可以使用 Eclipse、Visual Studio、Web Storm、Visual Studio Code,甚至在最坏的情况下使用记事本。(任何允许我们编写 JavaScript 代码的编辑器,也可以用于 TypeScript)。

    为了演示,我将使用 Visual Studio Code,它是微软提供的免费编辑器。可以从以下链接下载。

    https://vscode.js.cn/

演示 1 – var 示例

在 TypeScript 中,我们可以使用以下关键字之一声明变量。

  • var
  • let
  • const

var”是 JavaScript 中声明变量的传统方式。TypeScript 也继承了这一点。让我们对“var”进行一些演示。

第一步——创建 TypeScript 文件

  • 打开 Visual Studio Code
  • 菜单中选择文件>新建文件

    它将简单地启动编辑器。

  • 现在选择 文件>>保存 或按 Ctrl-S。选择您喜欢的文件夹,将“文件名”设置为“varExample.ts”,将“保存类型”选择为“TypeScript”并点击 确定

第二步——编写代码

在其中写入以下代码

var myVar= "Sukesh Marla";
console.log(myVar);

上面的代码看起来像 JavaScript 代码,但实际上,它是 TypeScript 代码。

第三步——编译

  • 打开命令提示符并导航到您的 TypeScript 源文件夹。
  • 只需写入以下命令
    tsc varExample.ts

    它将在同一文件夹中生成一个名为 varExample.js 的新文件。

第四步——测试文件

您可以通过两种方式测试此文件

  1. 创建 HTML 文件,使用 script 标签将生成的“.js”文件插入其中,然后执行 HTML 文件。

    或者

  2. 使用 node 执行 js 文件。为此,打开命令提示符,导航到 Source 文件夹并输入以下命令:
    node varExample.js

    它将执行 JS 文件并在命令行中显示输出

第五步——再试一个例子

将代码更改为以下内容:

console.log(a);

现在像以前一样编译它。它将导致以下错误:

如您所见,我们将在执行阶段之前发现所有问题。

第六步——再试一个例子

现在将代码更改为以下内容,然后再次编译它。

console.log(a);
var a;

这次,它将编译。现在使用“node”命令执行生成的“varExample.js”,如前所述。

将显示以下输出。

您是否期望出现与之前相同的错误?当变量用“var”声明时,声明将被提升。简单来说,无论变量在哪里声明,它都将从第 1 行开始可用。这个概念称为提升

第七步——再试一个例子

现在将代码更改为以下内容:

console.log(a);
var a=5;

编译并执行。

为什么值不是 5?我说变量声明会被提升而不是赋值。

为了方便理解,可以想象 var a=5; 在内部被写成两条语句:var a;a=5;

这两条语句中,第一条语句会被提升。

第八步——再试一个例子

现在将代码更改为以下内容:

console.log(a);
var b=5
if(b>2){
    var a=5;
}

输出将如下所示:

这出乎意料吗?

当变量使用“var”关键字声明时,将不会有块级作用域。通常在其他编程语言中,如果变量在块内部声明,它将无法在块外部访问,但在 JavaScript 中并非如此。

第九步——再试一个例子

让我们再看一个块级作用域问题的例子。尝试以下代码:

var b = 5;
if (b > 2) {
    var b = 6;
    console.log(b);
}
console.log(b);

编译它。生成的 JavaScript 将与源代码完全相同。使用 Node 执行它。

输出将如下:

所以,让我们列出“var”的问题:

  • 变量会被提升
  • 没有块级作用域

这个问题可以使用新的“let”关键字轻松解决。

让我们来看一些关于“let”关键字的演示。

演示 2 – let 示例

第一步——创建 TypeScript 文件

按照以上步骤创建一个名为“letExample.ts”的 TypeScript 文件,并检查以下代码。

第二步——编写代码

尝试以下代码并检查输出。

let myVar= "Sukesh Marla";
console.log(myVar);

第三步——编译

使用 tsc 编译它并检查生成的输出文件

如您所见,在最终的 JavaScript 代码中,“let”变成了“var”,因为当前的 JavaScript (ES5) 只支持 var。如果您担心“let”变成“var”,请不要担心。TypeScript 非常智能地处理了这个问题。在接下来的一个示例中,您将看到这一点。

第四步——再试一个例子

尝试以下代码并检查输出。

console.log(a);
let a;

它将导致错误,因为在“let”的情况下,变量必须先声明然后才能使用。

注意:默认情况下,TypeScript 配置为即使存在编译错误也生成输出。它只是将带有错误的代码原样生成到输出文件中。我们将在后续阶段学习如何覆盖此配置。

第五步——再试一个例子

尝试以下代码并检查输出。

console.log(a);
var b=5
if(b>2){
    let a=5;
}

它将导致错误,因为在“let”的情况下,变量将被视为块级变量。

第六步——再试一个例子

尝试以下代码

var b=5
if(b>2){
   let b=6;
   console.log(b);
}
console.log(b);

编译后,生成的 JavaScript 看起来如下所示:

var b = 5;
if (b > 2) {
    var b_1 = 6;
    console.log(b_1);
}
console.log(b);

如您所见,TypeScript 编译器非常智能。当前的 JavaScript 只有“var”,所以在生成的代码中,它只是改变了变量名本身。

简而言之,使用“let”而不是“var”解决了提升问题和块级作用域问题。编译错误会提示您代码中存在问题。

演示 3 – const 示例

const”与 let 相同,但有一个附加行为。一旦赋值,就不能更改。

按照以上步骤创建一个名为“constExample.ts”的 TypeScript 文件,并检查以下代码。

const a=5;
a=6;

编译它,我们会得到以下错误:

演示 4 – 基本数据类型

与 JavaScript 不同,TypeScript 是类型安全的。在这里,我们可以在声明变量时选择指定数据类型。

按照以上步骤创建一个名为“typeExample.ts”的 TypeScript 文件,并检查以下代码。

let n:number=5;
let s:string="Sukesh";
let b:boolean=true;
n="A";
s=5;
b="A";

编译时,将出现以下错误:

一旦变量声明了数据类型,它将不允许任何无效值。

您是否在思考之前声明变量没有数据类型的情况?

现在有两种变体

  1. 变量将用 varlet 声明,并在同一行赋值。
  2. 变量将用 varlet 声明,并在不同行赋值。

让我们尝试第一种变体

let n =5;
n="A";

编译它。它将生成以下错误:

如您所见,datatype 是整数。当变量没有 datatype 声明时,datatype 将根据第一次赋值决定。这被称为“类型推断”。

第二种变体,我们将在演示 5 之后尝试。

演示 5 – 动态 TypeScript

正如我之前所说,TS 是 JS 的超集。我们在 JS 中能做的任何事情,在 TS 中也能做。

JavaScript 本质上是动态的,而 TypeScript 则为客户端开发人员提供了类型安全的环境。

TypeScript 拥有自己的特性,使动态编码变得更容易。我们将在本课程中探索许多这些特性。

any”数据类型就是其中之一。它允许我们以动态方式处理变量。

检查以下代码。

创建一个名为“dynamic.ts”的 TypeScript 文件,其中包含以下代码片段:

let n:any=5;
console.log(n+1);
n="A";
console.log(n+1);

编译它,您会发现没有任何问题。

使用 Node 命令执行它。输出将如下所示:

如您所见,一个一开始是整数的变量,在后期变成了string

现在让我们尝试一下我们在演示 4 中讨论的第二种变体。

检查以下代码

let n;
n =5;
n="A";

您会注意到代码将简单地编译。默认情况下,当变量在没有 datatype 且未赋任何值的情况下声明时,它会变为“any”类型。

注意

编译后的类型安全环境总是会减少运行时错误的数量。因此,使用“any”并不总是最佳实践。在必须使用时才使用它。在所有其他情况下,请尝试坚持使用特定的数据类型。

演示 6 – 泛型数组

JavaScript 数组本质上是动态的,但在 TypeScript 中,我们支持泛型数组。

按照以上步骤创建一个名为“arrayExample.ts”的 TypeScript 文件,并检查以下代码。

let values:Array<number>=new Array<number>();
values.push(1);
values.push(2);
values.push("Sukesh");

以下是编译结果:

如您所见,我们不能向数组中添加任何无效值。

注意:我们也可以将“any”与数组一起使用。只需声明 Array<any> 类型的变量,它就会变成一个动态数组。

演示 5 – 函数

如前所述,TypeScript 为我们提供了一个编译环境。这对于函数也是如此。

示例 1 – 强制返回

尝试以下代码

function myFunction():number {  
}

编译时,我们将得到以下错误:

TypeScript 强制函数返回值。

示例 2 – 参数检查

现在尝试以下代码

function myFunction(x:number,y:number):number {
    return x+y;
}
myFunction(1,2,3);

编译时,我们将得到以下错误:

TypeScript 强制使用正确的参数调用函数。

示例 3 – 函数重复

尝试以下代码

function myFunction(x:number,y:number):number {
    return x+y;
}
function myFunction(x:number,y:number,z:number):number {
    return x+y;
}

编译时,将出现以下错误:

TypeScript 不允许创建两个同名函数。

示例 4 – 可选参数

借助可选参数,我们可以使 TypeScript 函数的行为与 JavaScript 函数一样。要定义可选参数,我们必须在参数名后加上“?”符号。

检查以下代码

function myFunction(x:number,y?:number):void {
    console.log(x);
    console.log(y);
}
console.log('With two parameters');
myFunction(1,2);

console.log('With 1 parameter');
myFunction(1);

编译它。它会成功。

如您所见,同一个函数可以调用两个参数,也可以只调用一个参数,因为第二个参数是可选参数。

输出如下

示例 5 – 默认参数

TypeScript 函数也可以定义默认参数。

检查以下代码

function myFunction(x:number,y:number=5):void {
    console.log(x);
    console.log(y);
}
console.log('With two parameters');
myFunction(1,2);

console.log('With 1 parameter');
myFunction(1);

编译它。它会成功。

以下是输出。

示例 7 – 无返回类型

创建不指定返回类型的函数与具有“any”作为返回类型相同。

检查以下代码

function myFunction(x:number,y:number){
  if(x>y)
      return  "Sukesh";
  }
  else if(y>x){
      return 55;;
  }
}
console.log(myFunction(1,2));
console.log(myFunction(2,1));
console.log(myFunction(2,2));

编译它并检查输出。

在上述情况下,函数有三种可能性。返回字符串、返回整数或不返回任何内容。

输出将如下:

示例 7 – 带剩余参数的演示

当我们想要定义一个以数组作为参数的函数时,剩余参数使我们的生活变得轻松。创建一个 TypeScript 函数如下:

function myFunction(x:Array<number>):number{
  let sum:number=0;
  for (let e of x) {
      sum+=e;
  }
  return sum;
}
let values:Array<number> =new Array<number>();
values.push(1);
values.push(2);
values.push(3);
console.log(myFunction(values));

现在同样的代码可以使用剩余参数重新编写,如下所示:

function myFunction(...x:Array<number>):number{
  let sum:number=0;
  for (let e of x) {
      sum+=e;
  }
  return sum;
}
console.log(myFunction(1,2,3));

如您所见,只需在参数名称前加上“...”,它就会成为剩余参数,之后,传递多个值作为多个参数,无需显式创建数组。

注意:一个函数中不能有两个剩余参数。

如果您喜欢这篇文章,请不要忘记投票。

如果您已经阅读到本文的这一行,请务必观看下面的 Angular 视频:

总结

第 1 天的第 1 部分到此结束。小憩片刻,吃点零食,玩玩游戏,放松一下,然后继续第 2 部分。

敬请期待!

历史

  • 2017 年 7 月 27 日:初始版本
© . All rights reserved.