javascript入门_JavaScript入门手册(2020版)

javascript入门

JavaScript is one of the most popular programming languages in the world.

JavaScript是世界上最受欢迎的编程语言之一。

I believe it's a great choice for your first programming language ever.

我相信这是您有史以来第一门编程语言的绝佳选择。

We mainly use JavaScript to create

我们主要使用JavaScript创建

  • websites

    网站
  • web applications

    网络应用
  • server-side applications using Node.js

    使用Node.js的服务器端应用程序

but JavaScript is not limited to these things, and it can also be used to

但是JavaScript不仅限于这些东西,它还可以用于

  • create mobile applications using tools like React Native

    使用React Native等工具创建移动应用程序
  • create programs for microcontrollers and the internet of things

    为微控制器和物联网创建程序
  • create smartwatch applications

    创建smartwatch应用程序

It can basically do anything. It's so popular that everything new that shows up is going to have some kind of JavaScript integration at some point.

它基本上可以做任何事情。 它是如此流行,以至于出现的所有新事物都将在某种程度上进行某种JavaScript集成。

JavaScript is a programming language that is:

JavaScript是一种编程语言,它是:

  • high level: it provides abstractions that allow you to ignore the details of the machine where it's running on. It manages memory automatically with a garbage collector, so you can focus on the code instead of managing memory like other languages like C would need, and provides many constructs which allow you to deal with highly powerful variables and objects.

    高级别 :它提供抽象,使您可以忽略正在运行的计算机的详细信息。 它使用垃圾回收器自动管理内存,因此您可以专注于代码,而不必像C之类的其他语言那样管理内存,并提供许多构造,使您可以处理功能强大的变量和对象。

  • dynamic: opposed to static programming languages, a dynamic language executes at runtime many of the things that a static language does at compile time. This has pros and cons, and it gives us powerful features like dynamic typing, late binding, reflection, functional programming, object runtime alteration, closures and much more. Don't worry if those things are unknown to you - you'll know all of them by the end of the course.

    动态的 :与静态编程语言相反,动态语言在运行时执行静态语言在编译时执行的许多操作。 这具有优缺点,并且为我们提供了强大的功能,例如动态类型输入,后期绑定,反射,函数式编程,对象运行时更改,闭包等等。 如果您不知道这些事情,请不要担心-在课程结束时,您将了解所有这些内容。

  • dynamically typed: a variable does not enforce a type. You can reassign any type to a variable, for example, assigning an integer to a variable that holds a string.

    动态类型的 :变量不强制类型。 您可以将任何类型重新分配给变量,例如,将整数分配给包含字符串的变量。

  • loosely typed: as opposed to strong typing, loosely (or weakly) typed languages do not enforce the type of an object, allowing more flexibility but denying us type safety and type checking (something that TypeScript - which builds on top of JavaScript - provides)

    松散类型 :与强类型相反,松散(或弱类)语言不会强制执行对象的类型,从而提供了更大的灵活性,但拒绝了我们进行类型安全性和类型检查(基于JavaScript的TypeScript提供的功能)

  • interpreted: it's commonly known as an interpreted language, which means that it does not need a compilation stage before a program can run, as opposed to C, Java or Go for example. In practice, browsers do compile JavaScript before executing it, for performance reasons, but this is transparent to you - there is no additional step involved.

    解释型 :它通常称为解释型语言,这意味着它可以在程序可以运行之前不需要编译阶段,例如,与C,Java或Go相对。 实际上,出于性能原因,浏览器会在执行JavaScript之前先对其进行编译,但这对您来说是透明的-无需执行其他任何步骤。

  • multi-paradigm: the language does not enforce any particular programming paradigm, unlike Java for example, which forces the use of object-oriented programming, or C that forces imperative programming. You can write JavaScript using an object-oriented paradigm, using prototypes and the new (as of ES6) classes syntax. You can write JavaScript in a functional programming style, with its first-class functions, or even in an imperative style (C-like).

    多范式语言不强制执行任何特定的编程范式,例如不同于Java,Java强制使用面向对象的编程,而C则强制执行命令式编程。 您可以使用面向对象的范例,原型和新的(从ES6开始)类语法来编写JavaScript。 您可以使用功能性编程风格,一流的功能甚至是命令式风格(类似于C)来编写JavaScript。

In case you're wondering, JavaScript has nothing to do with Java, it's a poor name choice but we have to live with it.

如果您想知道, JavaScript与Java无关 ,这是一个糟糕的选择,但我们必须忍受它。

手册摘要 (Summary of the handbook)

  1. A little bit of history

    一点历史

  2. Just JavaScript

    只是JavaScript

  3. A brief intro to the syntax of JavaScript

    JavaScript语法简介

  4. Semicolons

    分号

  5. Values

    价值观

  6. Variables

    变数

  7. Types

    种类

  8. Expressions

    表达方式

  9. Operators

    经营者

  10. Precedence rules

    优先规则

  11. Comparison operators

    比较运算符

  12. Conditionals

    有条件的

  13. Arrays

    数组

  14. Strings

    弦乐

  15. Loops

    循环

  16. Functions

    功能

  17. Arrow functions

    箭头功能

  18. Objects

    对象

  19. Object Properties

    对象属性

  20. Object Methods

    对象方法

  21. Classes

    班级

  22. Inheritance

    遗产

  23. Asynchonous Programming and Callbacks

    异步编程和回调

  24. Promises

    承诺

  25. Async and Await

    异步并等待

  26. Variable scope

    可变范围

  27. Conclusion

    结论

Update: You can now get a PDF and ePub version of this JavaScript Beginner's Handbook.

更新: 您现在可以获得本JavaScript初学者手册的PDF和ePub版本

一点历史 (A little bit of history)

Created in 1995, JavaScript has gone a very long way since its humble beginnings.

自1995年创建以来,JavaScript的不起眼发展就已经走了很长一段路。

It was the first scripting language that was supported natively by web browsers, and thanks to this it gained a competitive advantage over any other language and today it's still the only scripting language that we can use to build Web Applications.

它是Web浏览器本地支持的第一种脚本语言,并且由于它,它比其他任何语言都具有竞争优势,并且今天它仍然是我们可以用来构建Web应用程序的唯一脚本语言。

Other languages exist, but all must compile to JavaScript - or more recently to WebAssembly, but this is another story.

还存在其他语言,但是所有语言都必须编译为JavaScript,或者最近才可以编译为WebAssembly,但这是另一回事了。

In the begining, JavaScript was not nearly powerful as it is today, and it was mainly used for fancy animations and the marvel known at the time as Dynamic HTML.

刚开始时,JavaScript并不像今天那样强大,它主要用于精美的动画和当时称为Dynamic HTML的奇迹。

With the growing needs that the web platform demanded (and continues to demand), JavaScript had the responsibility to grow as well, to accommodate the needs of one of the most widely used ecosystems of the world.

随着Web平台不断增长的需求(并继续满足),JavaScript 有责任不断增长,以适应世界上使用最广泛的生态系统之一的需求。

JavaScript is also now widely used outside of the browser. The rise of Node.js in the last few years unlocked backend development, once the domain of Java, Ruby, Python, PHP, and more traditional server-side languages.

现在,JavaScript在浏览器之外也被广泛使用。 过去几年,Node.js的兴起解锁了后端开发,而后端开发曾经是Java,Ruby,Python,PHP和更传统的服务器端语言的领域。

JavaScript is now also the language powering databases and many more applications, and it's even possible to develop embedded applications, mobile apps, TV apps, and much more. What started as a tiny language inside the browser is now the most popular language in the world.

现在,JavaScript也是语言为数据库和更多应用程序提供了动力,甚至有可能开发嵌入式应用程序,移动应用程序,电视应用程序等。 从浏览器内部的一种很小的语言开始,到现在是世界上最受欢迎的语言。

只是JavaScript (Just JavaScript)

Sometimes it's hard to separate JavaScript from the features of the environment it is used in.

有时很难将JavaScript与使用环境的功能区分开。

For example, the console.log() line you can find in many code examples is not JavaScript. Instead, it's part of the vast library of APIs provided to us in the browser.

例如,您可以在许多代码示例中找到的console.log()行不是JavaScript。 相反,它是浏览器中提供给我们的庞大API库的一部分。

In the same way, on the server it can be sometimes hard to separate the JavaScript language features from the APIs provided by Node.js.

同样,有时在服务器上有时很难将JavaScript语言功能与Node.js提供的API分开。

Is a particular feature provided by React or Vue? Or is it "plain JavaScript", or "vanilla JavaScript" as it's often called?

React或Vue是否提供特定功能? 还是通常所说的“普通JavaScript”或“普通JavaScript”?

In this book I talk about JavaScript, the language.

在这本书中,我将讨论JavaScript,即语言。

Without complicating your learning process with things that are outside of it, and provided by external ecosystems.

不会使您的学习过程与外部生态系统所提供的外部事物复杂化。

JavaScript语法简介 (A brief intro to the syntax of JavaScript)

In this little introduction I want to tell you about 5 concepts:

在这个小介绍中,我想向您介绍5个概念:

  • white space

    空白空间
  • case sensitivity

    区分大小写
  • literals

    文字
  • identifiers

    身份标识
  • comments

    注释

空格 (White space)

JavaScript does not consider white space meaningful. Spaces and line breaks can be added in any fashion you might like, at least in theory.

JavaScript认为空白没有意义。 至少从理论上讲 ,可以以任何您喜欢的方式添加空格和换行符。

In practice, you will most likely keep a well defined style and adhere to what people commonly use, and enforce this using a linter or a style tool such as Prettier.

在实践中,您很可能会保持定义明确的样式并遵守人们常用的样式,并使用短绒棉布或样式工具(例如Prettier)来强制实施。

For example, I always use 2 space characters for each indentation.

例如,我总是对每个缩进使用2个空格字符。

区分大小写 (Case sensitive)

JavaScript is case sensitive. A variable named something is different than Something.

JavaScript区分大小写。 名为something的变量不同于Something

The same goes for any identifier.

任何标识符也是如此。

文字 (Literals)

We define literal as a value that is written in the source code, for example, a number, a string, a boolean or also more advanced constructs, like Object Literals or Array Literals:

我们将文字定义为在源代码中写入的值,例如,数字,字符串,布尔值或其他更高级的构造,例如对象文字或数组文字:

5
'Test'
true
['a', 'b']
{color: 'red', shape: 'Rectangle'}

身份标识 (Identifiers)

An identifier is a sequence of characters that can be used to identify a variable, a function, or an object. It can start with a letter, the dollar sign $ or an underscore _, and it can contain digits. Using Unicode, a letter can be any allowed character, for example, an emoji 😄.

标识符是可以用来标识变量,函数或对象的字符序列。 它可以以字母,美元符号$或下划线_开头,并且可以包含数字。 使用Unicode,字母可以是任何允许的字符,例如emoji😄。

Test
test
TEST
_test
Test1
$test

The dollar sign is commonly used to reference DOM elements.

美元符号通常用于引用DOM元素。

Some names are reserved for JavaScript internal use, and we can't use them as identifiers.

有些名称保留给JavaScript内部使用,我们不能将它们用作标识符。

注释 (Comments)

Comments are one of the most important parts of any program, in any programming language. They are important because they let us annotate the code and add important information that otherwise would not be available to other people (or ourselves) reading the code.

注释是任何程序设计语言中任何程序最重要的部分之一。 它们之所以重要,是因为它们使我们能够注释代码并添加重要的信息,否则其他人(或我们自己)将无法阅读该代码。

In JavaScript, we can write a comment on a single line using //. Everything after // is not considered as code by the JavaScript interpreter.

在JavaScript中,我们可以使用//在一行上写注释。 JavaScript解释器不会将//之后的所有内容都视为代码。

Like this:

像这样:

// a comment
true //another comment

Another type of comment is a multi-line comment. It starts with /* and ends with */.

另一种注释类型是多行注释。 它以/*开头,以*/结束。

Everything in between is not considered as code:

介于两者之间的所有内容均不视为代码:

/* some kind
of 
comment 

*/

分号 (Semicolons)

Every line in a JavaScript program is optionally terminated using semicolons.

JavaScript程序中的每一行都可以选择使用分号终止。

I said optionally, because the JavaScript interpreter is smart enough to introduce semicolons for you.

我选择说是因为JavaScript解释器足够聪明,可以为您介绍分号。

In most cases, you can omit semicolons altogether from your programs without even thinking about it.

在大多数情况下,您甚至可以不考虑程序中的分号。

This fact is very controversial. Some developers will always use semicolons, some others will never use semicolons, and you'll always find code that uses semicolons and code that does not.

这个事实是很有争议的。 一些开发人员将始终使用分号,而另一些开发人员将永远不使用分号,并且您将始终找到使用分号的代码和不使用分号的代码。

My personal preference is to avoid semicolons, so my examples in the book will not include them.

我个人倾向于避免使用分号,因此本书中的示例将不包括分号。

价值观 (Values)

A hello string is a value. A number like 12 is a value.

hello字符串是一个 。 像12这样的数字是一个

hello and 12 are values. string and number are the types of those values.

hello12是值。 stringnumber是这些值的类型

The type is the kind of value, its category. We have many different types in JavaScript, and we'll talk about them in detail later on. Each type has its own characteristics.

类型是价值的种类,是其类别。 我们在JavaScript中有许多不同的类型,我们将在后面详细讨论它们。 每种类型都有其自身的特征。

When we need to have a reference to a value, we assign it to a variable. The variable can have a name, and the value is what's stored in a variable, so we can later access that value through the variable name.

当需要引用值时,可以将其分配给变量 。 变量可以有一个名称,而值是存储在变量中的值,因此我们以后可以通过变量名访问该值。

变数 (Variables)

A variable is a value assigned to an identifier, so you can reference and use it later in the program.

变量是分配给标识符的值,因此您以后可以在程序中引用和使用它。

This is because JavaScript is loosely typed, a concept you'll frequently hear about.

这是因为JavaScript是松散类型的 ,您会经常听到这个概念。

A variable must be declared before you can use it.

必须先声明变量,然后才能使用它。

We have 2 main ways to declare variables. The first is to use const:

我们有两种声明变量的主要方法。 首先是使用const

const a = 0

The second way is to use let:

第二种方法是使用let

let a = 0

What's the difference?

有什么不同?

const defines a constant reference to a value. This means the reference cannot be changed. You cannot reassign a new value to it.

const定义对值的常量引用。 这意味着参考不能更改。 您不能为它重新分配新值。

Using let you can assign a new value to it.

使用let可以为其分配一个新值。

For example, you cannot do this:

例如,您不能执行以下操作:

const a = 0
a = 1

Because you'll get an error: TypeError: Assignment to constant variable..

因为会出现错误: TypeError: Assignment to constant variable.

On the other hand, you can do it using let:

另一方面,您可以使用let

let a = 0
a = 1

const does not mean "constant" in the way some other languages like C mean. In particular, it does not mean the value cannot change - it means it cannot be reassigned. If the variable points to an object or an array (we'll see more about objects and arrays later) the content of the object or the array can freely change.

const不像其他语言(如C)那样表示“常数”。 特别是,这并不意味着值不能更改-意味着不能重新分配。 如果变量指向一个对象或数组(我们将在以后看到更多有关对象和数组的信息),则该对象或数组的内容可以自由更改。

const variables must be initialized at the declaration time:

const变量必须在声明时初始化:

const a = 0

but let values can be initialized later:

但是let值可以在以后初始化:

let a
a = 0

You can declare multiple variables at once in the same statement:

您可以在同一条语句中一次声明多个变量:

const a = 1, b = 2
let c = 1, d = 2

But you cannot redeclare the same variable more than one time:

但是您不能多次声明同一变量:

let a = 1
let a = 2

or you'd get a "duplicate declaration" error.

否则会出现“重复声明”错误。

My advice is to always use const and only use let when you know you'll need to reassign a value to that variable. Why? Because the less power our code has, the better. If we know a value cannot be reassigned, it's one less source for bugs.

我的建议是始终使用const并且仅在知道需要将值重新分配给该变量时才使用let 。 为什么? 因为我们的代码功能越少越好。 如果我们知道不能重新分配一个值,那么它的错误源就会少一些。

Now that we saw how to work with const and let, I want to mention var.

现在我们已经了解了如何使用constlet ,我想提到var

Until 2015, var was the only way we could declare a variable in JavaScript. Today, a modern codebase will most likely just use const and let. There are some fundamental differences which I detail in this post but if you're just starting out, you might not care about them. Just use const and let.

直到2015年, var才是我们可以在JavaScript中声明变量的唯一方法。 今天,现代代码库很可能只使用constlet 。 我在本文中详细介绍一些基本差异,但是如果您只是刚入门,则可能不关心它们。 只需使用constlet

种类 (Types)

Variables in JavaScript do not have any type attached.

JavaScript中的变量没有附加任何类型。

They are untyped.

它们是无类型的

Once you assign a value with some type to a variable, you can later reassign the variable to host a value of any other type without any issues.

为变量分配某种类型的值后,以后可以重新分配该变量以托管任何其他类型的值,而不会出现任何问题。

In JavaScript we have 2 main kinds of types: primitive types and object types.

在JavaScript中,我们有两种主要类型: 基本类型对象类型

原始类型 (Primitive types)

Primitive types are

基本类型是

  • numbers

    数字
  • strings

  • booleans

    布尔值
  • symbols

    符号

And two special types: null and undefined.

还有两种特殊类型: nullundefined

对象类型 (Object types)

Any value that's not of a primitive type (a string, a number, a boolean, null or undefined) is an object.

任何不是原始类型的值(字符串,数字,布尔值,null或未定义)都是object

Object types have properties and also have methods that can act on those properties.

对象类型有属性 ,也具有可对这些属性执行的方法

We'll talk more about objects later on.

稍后我们将详细讨论对象。

表达方式 (Expressions)

An expression is a single unit of JavaScript code that the JavaScript engine can evaluate, and return a value.

表达式是JavaScript引擎可以评估并返回值的单个JavaScript代码单元。

Expressions can vary in complexity.

表达式的复杂度可能有所不同。

We start from the very simple ones, called primary expressions:

我们从一个非常简单的表达式开始,即基本表达式:

2
0.02
'something'
true
false
this //the current scope
undefined
i //where i is a variable or a constant

Arithmetic expressions are expressions that take a variable and an operator (more on operators soon), and result in a number:

算术表达式是一个带有变量和一个运算符的表达式(很快将有更多关于运算符的表达式),并产生一个数字:

1 / 2
i++
i -= 2
i * 2

String expressions are expressions that result in a string:

字符串表达式是产生字符串的表达式:

'A ' + 'string'

Logical expressions make use of logical operators and resolve to a boolean value:

逻辑表达式使用逻辑运算符并解析为布尔值:

a && b
a || b
!a

More advanced expressions involve objects, functions, and arrays, and I'll introduce them later.

更高级的表达式涉及对象,函数和数组,稍后将介绍它们。

经营者 (Operators)

Operators allow you to get two simple expressions and combine them to form a more complex expression.

运算符使您可以获得两个简单的表达式,并将它们组合起来以形成一个更复杂的表达式。

We can classify operators based on the operands they work with. Some operators work with 1 operand. Most work with 2 operands. Just one operator works with 3 operands.

我们可以根据使用的运算符对运算符进行分类。 一些运算符使用1个操作数。 大多数使用2个操作数。 仅有一个运算符可处理3个操作数。

In this first introduction to operators, we'll introduce the operators you are most likely familiar with: operators with 2 operands.

在对运算符的第一个介绍中,我们将介绍您最可能熟悉的运算符:具有2个操作数的运算符。

I already introduced one when talking about variables: the assignment operator =. You use = to assign a value to a variable:

在讨论变量时,我已经介绍了一个:赋值运算符= 。 您可以使用=将值分配给变量:

let b = 2

Let's now introduce another set of binary operators that you're already familiar with from basic math.

现在让我们介绍一下您已经从基本数学中熟悉的另一组二进制运算符。

加法运算符(+) (The addition operator (+))

const three = 1 + 2
const four = three + 1

The + operator also does string concatenation if you use strings, so pay attention:

如果使用字符串,则+运算符还会进行字符串连接,因此请注意:

const three = 1 + 2
three + 1 // 4
'three' + 1 // three1

减法运算符(-) (The subtraction operator (-))

const two = 4 - 2

除法运算符(/) (The division operator (/))

Returns the quotient of the first operator and the second:

返回第一个运算符和第二个运算符的商:

const result = 20 / 5 //result === 4
const result = 20 / 7 //result === 2.857142857142857

If you divide by zero, JavaScript does not raise any error but returns the Infinity value (or -Infinity if the value is negative).

如果除以零,则JavaScript不会引发任何错误,但会返回Infinity值(如果该值为负,则返回-Infinity )。

1 / 0 //Infinity
-1 / 0 //-Infinity

余数运算符(%) (The remainder operator (%))

The remainder is a very useful calculation in many use cases:

余数在许多用例中都是非常有用的计算:

const result = 20 % 5 //result === 0
const result = 20 % 7 //result === 6

A remainder by zero is always NaN, a special value that means "Not a Number":

零值始终为NaN ,这是一个特殊值,表示“不是数字”:

1 % 0 //NaN
-1 % 0 //NaN

乘法运算符(*) (The multiplication operator (*))

Multiply two numbers

将两个数字相乘

1 * 2 //2
-1 * 2 //-2

求幂运算符(**) (The exponentiation operator (**))

Raise the first operand to the power of the second operand

将第一个操作数提高到第二个操作数的幂

1 ** 2 //1
2 ** 1 //2
2 ** 2 //4
2 ** 8 //256
8 ** 2 //64

优先规则 (Precedence rules)

Every complex statement with multiple operators in the same line will introduce precedence problems.

在同一行中具有多个运算符的每个复杂语句都会引入优先级问题。

Take this example:

举个例子:

let a = 1 * 2 + 5 / 2 % 2

The result is 2.5, but why?

结果是2.5,但是为什么呢?

What operations are executed first, and which need to wait?

首先执行哪些操作,哪些需要等待?

Some operations have more precedence than the others. The precedence rules are listed in this table:

一些操作比其他操作具有更高的优先级。 优先级规则在此表中列出:

OperatorDescription
* / %multiplication/division
+ -addition/subtraction
=assignment
操作员 描述
* / % 乘法/除法
+ - 加/减
= 分配

Operations on the same level (like + and -) are executed in the order they are found, from left to right.

同一级别的操作(如+- )将按从左到右的顺序执行。

Following these rules, the operation above can be solved in this way:

遵循以下规则,可以通过以下方式解决以上操作:

let a = 1 * 2 + 5 / 2 % 2
let a = 2 + 5 / 2 % 2
let a = 2 + 2.5 % 2
let a = 2 + 0.5
let a = 2.5

比较运算符 (Comparison operators)

After assignment and math operators, the third set of operators I want to introduce is conditional operators.

在分配运算符和数学运算符之后,我要介绍的第三组运算符是条件运算符。

You can use the following operators to compare two numbers, or two strings.

您可以使用以下运算符比较两个数字或两个字符串。

Comparison operators always return a boolean, a value that's true or false).

比较运算符始终返回布尔值,即truefalse )。

Those are disequality comparison operators:

这些是不平等比较运算符

  • < means "less than"

    <表示“小于”

  • <= means "less than or equal to"

    <=表示“小于或等于”

  • > means "greater than"

    >表示“大于”

  • >= means "greater than or equal to"

    >=表示“大于或等于”

Example:

例:

let a = 2
a >= 1 //true

In addition to those, we have 4 equality operators. They accept two values, and return a boolean:

除此之外,我们还有4个相等运算符 。 它们接受两个值,并返回一个布尔值:

  • === checks for equality

    ===检查是否相等

  • !== checks for inequality

    !==检查不平等

Note that we also have == and != in JavaScript, but I highly suggest to only use === and !== because they can prevent some subtle problems.

注意我们在JavaScript中也有==!= ,但是我强烈建议只使用===!==因为它们可以防止一些细微的问题。

有条件的 (Conditionals)

With the comparison operators in place, we can talk about conditionals.

有了比较运算符之后,我们就可以讨论条件了。

An if statement is used to make the program take a route, or another, depending on the result of an expression evaluation.

根据表达式求值的结果,使用if语句使程序采用一条路线或另一条路线。

This is the simplest example, which always executes:

这是最简单的示例,始终执行:

if (true) {
  //do something
}

on the contrary, this is never executed:

相反,这永远不会执行:

if (false) {
  //do something (? never ?)
}

The conditional checks the expression you pass to it for a true or false value. If you pass a number, that always evaluates to true unless it's 0. If you pass a string, it always evaluates to true unless it's an empty string. Those are general rules of casting types to a boolean.

条件检查您传递给它的表达式的真值或假值。 如果传递一个数字,除非它为0,否则始终为true。如果传递一个字符串,则除非它为一个空字符串,否则始终为true。 这些是将类型强制转换为布尔值的一般规则。

Did you notice the curly braces? That is called a block, and it is used to group a list of different statements.

你注意到花括号了吗? 这称为block ,它用于对不同语句的列表进行分组。

A block can be put wherever you can have a single statement. And if you have a single statement to execute after the conditionals, you can omit the block, and just write the statement:

只要有一条语句,就可以放置一个块。 而且,如果您在条件之后执行一条语句,则可以省略该块,而只需编写该语句:

if (true) doSomething()

But I always like to use curly braces to be more clear.

但是我一直喜欢使用花括号来使其更清晰。

You can provide a second part to the if statement: else.

您可以为if语句提供第二部分: else

You attach a statement that is going to be executed if the if condition is false:

如果if条件为false,则附加一条将要执行的语句:

if (true) {
  //do something
} else {
  //do something else
}

Since else accepts a statement, you can nest another if/else statement inside it:

由于else接受一个语句,因此可以在其中嵌套另一个if / else语句:

if (a === true) {
  //do something
} else if (b === true) {
  //do something else
} else {
  //fallback
}

数组 (Arrays)

An array is a collection of elements.

数组是元素的集合。

Arrays in JavaScript are not a type on their own.

JavaScript中的数组本身不是一种类型

Arrays are objects.

数组是对象

We can initialize an empty array in these 2 different ways:

我们可以通过以下两种不同的方式初始化一个空数组:

const a = []
const a = Array()

The first is using the array literal syntax. The second uses the Array built-in function.

第一种是使用数组文字语法 。 第二个使用Array内置函数。

You can pre-fill the array using this syntax:

您可以使用以下语法预先填充数组:

const a = [1, 2, 3]
const a = Array.of(1, 2, 3)

An array can hold any value, even values of different types:

数组可以包含任何值,甚至可以包含不同类型的值:

const a = [1, 'Flavio', ['a', 'b']]

Since we can add an array into an array, we can create multi-dimensional arrays, which have very useful applications (e.g. a matrix):

由于我们可以将数组添加到数组中,因此我们可以创建多维数组,这些数组具有非常有用的应用程序(例如矩阵):

const matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

matrix[0][0] //1
matrix[2][0] //7

You can access any element of the array by referencing its index, which starts from zero:

您可以通过引用从零开始的索引来访问数组的任何元素:

a[0] //1
a[1] //2
a[2] //3

You can initialize a new array with a set of values using this syntax, which first initializes an array of 12 elements, and fills each element with the number 0:

您可以使用以下语法使用一组值初始化一个新数组,该语法首先初始化一个包含12个元素的数组,然后用数字0填充每个元素:

Array(12).fill(0)

You can get the number of elements in the array by checking its length property:

您可以通过检查其length属性来获取数组中元素的数量:

const a = [1, 2, 3]
a.length //3

Note that you can set the length of the array. If you assign a bigger number than the arrays current capacity, nothing happens. If you assign a smaller number, the array is cut at that position:

请注意,您可以设置数组的长度。 如果分配的数字大于阵列的当前容量,则不会发生任何事情。 如果分配较小的数字,则会在该位置切割数组:

const a = [1, 2, 3]
a //[ 1, 2, 3 ]
a.length = 2
a //[ 1, 2 ]

如何将项目添加到数组 (How to add an item to an array)

We can add an element at the end of an array using the push() method:

我们可以使用push()方法在数组的末尾添加一个元素:

a.push(4)

We can add an element at the beginning of an array using the unshift() method:

我们可以使用unshift()方法在数组的开头添加一个元素:

a.unshift(0)
a.unshift(-2, -1)

如何从数组中删除项目 (How to remove an item from an array)

We can remove an item from the end of an array using the pop() method:

我们可以使用pop()方法从数组末尾删除一个项目:

a.pop()

We can remove an item from the beginning of an array using the shift() method:

我们可以使用shift()方法从数组的开头删除一项:

a.shift()

如何加入两个或多个数组 (How to join two or more arrays)

You can join multiple arrays by using concat():

您可以使用concat()连接多个数组:

const a = [1, 2]
const b = [3, 4]
const c = a.concat(b) //[1,2,3,4]
a //[1,2]
b //[3,4]

You can also use the spread operator (...) in this way:

您还可以通过以下方式使用扩展运算符( ... ):

const a = [1, 2]
const b = [3, 4]
const c = [...a, ...b]
c //[1,2,3,4]

如何在数组中查找特定项目 (How to find a specific item in the array)

You can use the find() method of an array:

您可以使用数组的find()方法:

a.find((element, index, array) => {
  //return true or false
})

Returns the first item that returns true, and returns undefined if the element is not found.

返回返回true的第一项,如果未找到该元素,则返回undefined

A commonly used syntax is:

常用的语法是:

a.find(x => x.id === my_id)

The above line will return the first element in the array that has id === my_id.

上一行将返回数组中具有id === my_id的第一个元素。

findIndex() works similarly to find(), but returns the index of the first item that returns true, and if not found, it returns undefined:

findIndex()find()类似,但返回返回true的第一项的索引,如果找不到,则返回undefined

a.findIndex((element, index, array) => {
  //return true or false
})

Another method is includes():

另一种方法是includes()

a.includes(value)

Returns true if a contains value.

返回true如果a包含value

a.includes(value, i)

Returns true if a contains value after the position i.

如果a在位置i之后包含value ,则返回true。

弦乐 (Strings)

A string is a sequence of characters.

字符串是字符序列。

It can be also defined as a string literal, which is enclosed in quotes or double quotes:

也可以将其定义为字符串文字,用引号或双引号引起来:

'A string'
"Another string"

I personally prefer single quotes all the time, and use double quotes only in HTML to define attributes.

我个人更喜欢一直使用单引号,并且仅在HTML中使用双引号定义属性。

You assign a string value to a variable like this:

您将一个字符串值分配给这样的变量:

const name = 'Flavio'

You can determine the length of a string using the length property of it:

您可以使用字符串的length属性确定字符串的length

'Flavio'.length //6
const name = 'Flavio'
name.length //6

This is an empty string: ''. Its length property is 0:

这是一个空字符串: '' 。 其length属性为0:

''.length //0

Two strings can be joined using the + operator:

可以使用+运算符连接两个字符串:

"A " + "string"

You can use the + operator to interpolate variables:

您可以使用+运算符来插值变量:

const name = 'Flavio'
"My name is " + name //My name is Flavio

Another way to define strings is to use template literals, defined inside backticks. They are especially useful to make multiline strings much simpler. With single or double quotes you can't define a multiline string easily - you'd need to use escaping characters.

定义字符串的另一种方法是使用在反引号内定义的模板文字。 它们对于使多行字符串更简单特别有用。 使用单引号或双引号不能轻易定义多行字符串-您需要使用转义字符。

Once a template literal is opened with the backtick, you just press enter to create a new line, with no special characters, and it's rendered as-is:

使用反引号打开模板文字后,只需按Enter键即可创建新行(不包含任何特殊字符),并按原样呈现:

const string = `Hey
this

string
is awesome!`

Template literals are also great because they provide an easy way to interpolate variables and expressions into strings.

模板文字也很棒,因为它们提供了一种将变量和表达式插入字符串的简便方法。

You do so by using the ${...} syntax:

您可以使用${...}语法来实现:

const var = 'test'
const string = `something ${var}` 
//something test

inside the ${} you can add anything, even expressions:

${}您可以添加任何内容,甚至是表达式:

const string = `something ${1 + 2 + 3}`
const string2 = `something 
  ${foo() ? 'x' : 'y'}`

循环 (Loops)

Loops are one of the main control structures of JavaScript.

循环是JavaScript的主要控制结构之一。

With a loop we can automate and repeat a block of code however many times we want it to run, even indefinitely.

通过循环,我们可以使代码块自动化并重复执行,无论我们希望运行它多少次(甚至无限期地执行)。

JavaScript provides many way to iterate through loops.

JavaScript提供了许多遍历循环的方法。

I want to focus on 3 ways:

我想关注3种方式:

  • while loops

    while循环
  • for loops

    for循环
  • for..of loops

    for..of循环

while (while)

The while loop is the simplest looping structure that JavaScript provides us.

while循环是JavaScript提供给我们的最简单的循环结构。

We add a condition after the while keyword, and we provide a block that is run until the condition evaluates to true.

我们在while关键字之后添加一个条件,并提供一个运行到条件评估为true

Example:

例:

const list = ['a', 'b', 'c']
let i = 0
while (i < list.length) {
  console.log(list[i]) //value
  console.log(i) //index
  i = i + 1
}

You can interrupt a while loop using the break keyword, like this:

您可以使用break关键字中断while循环,如下所示:

while (true) {
  if (somethingIsTrue) break
}

and if you decide that in the middle of a loop you want to skip the current iteration, you can jump to the next iteration using continue:

并且如果您确定要在循环中间跳过当前迭代,则可以使用continue跳至下一个迭代:

while (true) {
  if (somethingIsTrue) continue

  //do something else
}

Very similar to while, we have do..while loops. It's basically the same as while, except the condition is evaluated after the code block is executed.

while非常相似,我们有do..while循环。 它与while基本上相同,除了条件是代码块执行之后评估条件。

This means the block is always executed at least once.

这意味着该块始终至少执行一次

Example:

例:

const list = ['a', 'b', 'c']
let i = 0
do {
  console.log(list[i]) //value
  console.log(i) //index
  i = i + 1
} while (i < list.length)

for (for)

The second very important looping structure in JavaScript is the for loop.

JavaScript中第二个非常重要的循环结构是for循环

We use the for keyword and we pass a set of 3 instructions: the initialization, the condition, and the increment part.

我们使用for关键字,并传递一组3条指令:初始化,条件和增量部分。

Example:

例:

const list = ['a', 'b', 'c']

for (let i = 0; i < list.length; i++) {
  console.log(list[i]) //value
  console.log(i) //index
}

Just like with while loops, you can interrupt a for loop using break and you can fast forward to the next iteration of a for loop using continue.

就像while循环一样,您可以使用break中断for循环,并可以使用continue前进至for循环的下一个迭代。

for...of (for...of)

This loop is relatively recent (introduced in 2015) and it's a simplified version of the for loop:

该循环是相对较新的(于2015年引入),它是for循环的简化版本:

const list = ['a', 'b', 'c']

for (const value of list) {
  console.log(value) //value
}

功能 (Functions)

In any moderately complex JavaScript program, everything happens inside functions.

在任何中等复杂JavaScript程序中,一切都发生在函数内部。

Functions are a core, essential part of JavaScript.

函数是JavaScript的核心,必不可少的部分。

What is a function?

什么是功能?

A function is a block of code, self contained.

函数是一个代码块,是自包含的。

Here's a function declaration:

这是一个函数声明

function getData() {
  // do something
}

A function can be run any time you want by invoking it, like this:

可以通过调用函数在任何时候运行它,如下所示:

getData()

A function can have one or more argument:

一个函数可以具有一个或多个参数:

function getData() {
  //do something
}

function getData(color) {
  //do something
}

function getData(color, age) {
  //do something
}

When we can pass an argument, we invoke the function passing parameters:

当我们可以传递参数时,我们调用传递参数的函数:

function getData(color, age) {
  //do something
}

getData('green', 24)
getData('black')

Note that in the second invokation I passed the black string parameter as the color argument, but no age. In this case, age inside the function is undefined.

请注意,在第二次调用中,我传递了black字符串参数作为color参数,但没有age 。 在这种情况下,函数内部的ageundefined

We can check if a value is not undefined using this conditional:

我们可以使用以下条件检查值是否未定义:

function getData(color, age) {
  //do something
  if (typeof age !== 'undefined') {
    //...
  }
}

typeof is a unary operator that allows us to check the type of a variable.

typeof是一元运算符,可让我们检查变量的类型。

You can also check in this way:

您还可以通过以下方式进行检查:

function getData(color, age) {
  //do something
  if (age) {
    //...
  }
}

Although the conditional will also be true if age is null, 0 or an empty string.

尽管agenull0或空字符串时条件也将为true。

You can have default values for parameters, in case they are not passed:

如果未传递参数,则可以具有参数的缺省值:

function getData(color = 'black', age = 25) {
  //do something
}

You can pass any value as a parameter: numbers, strings, booleans, arrays, objects, and also functions.

您可以将任何值作为参数传递:数字,字符串,布尔值,数组,对象以及函数。

A function has a return value. By default a function returns undefined, unless you add a return keyword with a value:

函数具有返回值。 默认情况下,函数返回undefined ,除非您添加带有值的return关键字:

function getData() {
  // do something
  return 'hi!'
}

We can assign this return value to a variable when we invoke the function:

我们可以在调用函数时将此返回值分配给变量:

function getData() {
  // do something
  return 'hi!'
}

let result = getData()

result now holds a string with the the hi! value.

result现在包含一个带有hi!的字符串hi! 值。

You can only return one value.

您只能返回一个值。

To return multiple values, you can return an object, or an array, like this:

要返回多个值,可以返回一个对象或数组,如下所示:

function getData() {
  return ['Flavio', 37]
}

let [name, age] = getData()

Functions can be defined inside other functions:

可以在其他函数中定义函数:

const getData = () => {
  const dosomething = () => {}
  dosomething()
  return 'test'
}

The nested function cannot be called from the outside of the enclosing function.

不能从封闭函数的外部调用嵌套函数。

You can return a function from a function, too.

您也可以从函数返回函数。

箭头功能 (Arrow functions)

Arrow functions are a recent introduction to JavaScript.

箭头函数是JavaScript的最新介绍。

They are very often used instead of "regular" functions, the ones I described in the previous chapter. You'll find both forms used everywhere.

我经常在上一章中介绍过这些函数,而不是“常规”函数。 您会发现两种形式都在各处使用。

Visually, they allows you to write functions with a shorter syntax, from:

从视觉上看,它们使您可以使用较短的语法编写函数,这些函数来自:

function getData() {
  //...
}

to

() => {
  //...
}

But.. notice that we don't have a name here.

但是..请注意,我们在这里没有名字。

Arrow functions are anonymous. We must assign them to a variable.

箭头函数是匿名的。 我们必须将它们分配给变量。

We can assign a regular function to a variable, like this:

我们可以将常规函数分配给变量,如下所示:

let getData = function getData() {
  //...
}

When we do so, we can remove the name from the function:

这样做时,我们可以从函数中删除名称:

let getData = function() {
  //...
}

and invoke the function using the variable name:

并使用变量名调用该函数:

let getData = function() {
  //...
}
getData()

That's the same thing we do with arrow functions:

这与箭头功能相同:

let getData = () => {
  //...
}
getData()

If the function body contains just a single statement, you can omit the parentheses and write everything on a single line:

如果函数主体仅包含一条语句,则可以省略括号,并将所有内容写在一行上:

const getData = () => console.log('hi!')

Parameters are passed in the parentheses:

参数在括号中传递:

const getData = (param1, param2) => 
  console.log(param1, param2)

If you have one (and just one) parameter, you could omit the parentheses completely:

如果有一个(只有一个)参数,则可以完全省略括号:

const getData = param => console.log(param)

Arrow functions allow you to have an implicit return - values are returned without having to use the return keyword.

箭头函数使您可以隐式返回-无需使用return关键字即可返回值。

It works when there is a one-line statement in the function body:

当函数体中有单行语句时,它可以工作:

const getData = () => 'test'

getData() //'test'

Like with regular functions, we can have default values for parameters in case they are not passed:

与常规函数一样,如果不传递参数,我们可以为它们提供默认值:

const getData = (color = 'black', 
                 age = 2) => {
  //do something
}

And like regular functions, we can only return one value.

与常规函数一样,我们只能返回一个值。

Arrow functions can also contain other arrow functions, or even regular functions.

箭头功能还可以包含其他箭头功能,甚至是常规功能。

The two types of functions are very similar, so you might ask why arrow functions were introduced. The big difference with regular functions is when they are used as object methods. This is something we'll soon look into.

两种功能非常相似,因此您可能会问为什么引入了箭头功能。 常规函数的最大区别是将它们用作对象方法时。 这是我们很快将要研究的问题。

对象 (Objects)

Any value that's not of a primitive type (a string, a number, a boolean, a symbol, null, or undefined) is an object.

任何不是原始类型的值(字符串,数字,布尔值,符号,空值或未定义)都是一个object

Here's how we define an object:

我们定义对象的方法如下:

const car = {

}

This is the object literal syntax, which is one of the nicest things in JavaScript.

这是对象文字语法,这是JavaScript中最好的东西之一。

You can also use the new Object syntax:

您还可以使用new Object语法:

const car = new Object()

Another syntax is to use Object.create():

另一种语法是使用Object.create()

const car = Object.create()

You can also initialize an object using the new keyword before a function with a capital letter. This function serves as a constructor for that object. In there, we can initialize the arguments we receive as parameters, to setup the initial state of the object:

您还可以在带有大写字母的函数之前使用new关键字初始化对象。 该函数用作该对象的构造函数。 在这里,我们可以将接收到的参数初始化为参数,以设置对象的初始状态:

function Car(brand, model) {
  this.brand = brand
  this.model = model
}

We initialize a new object using:

我们使用以下命令初始化一个新对象:

const myCar = new Car('Ford', 'Fiesta')
myCar.brand //'Ford'
myCar.model //'Fiesta'

Objects are always passed by reference.

对象总是通过引用传递

If you assign a variable the same value of another, if it's a primitive type like a number or a string, they are passed by value:

如果为变量分配与另一个变量相同的值,则它是数字或字符串之类的原始类型,则按值传递它们:

Take this example:

举个例子:

let age = 36
let myAge = age
myAge = 37
age //36
const car = {
  color: 'blue'
}
const anotherCar = car
anotherCar.color = 'yellow'
car.color //'yellow'

Even arrays or functions are, under the hood, objects, so it's very important to understand how they work.

甚至数组或函数实际上都是对象,因此了解它们的工作方式非常重要。

对象属性 (Object Properties)

Objects have properties, which are composed by a label associated with a value.

对象具有属性 ,由与值关联的标签组成。

The value of a property can be of any type, which means that it can be an array, a function, and it can even be an object, as objects can nest other objects.

属性的值可以是任何类型,这意味着它可以是数组,函数,甚至可以是对象,因为对象可以嵌套其他对象。

This is the object literal syntax we saw in the previous chapter:

这是我们在上一章中看到的对象文字语法:

const car = {

}

We can define a color property in this way:

我们可以通过以下方式定义color属性:

const car = {
  color: 'blue'
}

Here we have a car object with a property named color, with value blue.

在这里,我们有一个car对象,其属性名为color ,值为blue

Labels can be any string, but beware of special characters - if I wanted to include a character not valid as a variable name in the property name, I would have had to use quotes around it:

标签可以是任何字符串,但要注意特殊字符-如果我想在属性名称中包括一个无效的字符作为变量名,则必须在其周围使用引号:

const car = {
  color: 'blue',
  'the color': 'blue'
}

Invalid variable name characters include spaces, hyphens, and other special characters.

无效的变量名称字符包括空格,连字符和其他特殊字符。

As you can see, when we have multiple properties, we separate each property with a comma.

如您所见,当我们有多个属性时,我们用逗号分隔每个属性。

We can retrieve the value of a property using 2 different syntaxes.

我们可以使用2种不同的语法来检索属性的值。

The first is dot notation:

第一个是点符号

car.color //'blue'

The second (which is the only one we can use for properties with invalid names), is to use square brackets:

第二个(这是我们唯一可以用于名称无效的属性的方法)是使用方括号:

car['the color'] //'blue'

If you access a nonexistant property, you'll get the undefined value:

如果访问不存在的属性,则将获得undefined值:

car.brand //undefined

As mentioned before, objects can have nested objects as properties:

如前所述,对象可以将嵌套对象作为属性:

const car = {
  brand: {
    name: 'Ford'
  },
  color: 'blue'
}

In this example, you can access the brand name using

在此示例中,您可以使用以下方式访问品牌名称

car.brand.name

or

要么

car['brand']['name']

You can set the value of a property when you define the object.

定义对象时,可以设置属性的值。

But you can always update it later on:

但您随时可以在以后进行更新:

const car = {
  color: 'blue'
}

car.color = 'yellow'
car['color'] = 'red'

And you can also add new properties to an object:

您还可以向对象添加新属性:

car.model = 'Fiesta'

car.model //'Fiesta'

Given the object

给定对象

const car = {
  color: 'blue',
  brand: 'Ford'
}

you can delete a property from this object using

您可以使用以下命令从此对象中删除属性

delete car.brand

对象方法 (Object Methods)

I talked about functions in a previous chapter.

我在上一章中谈到了函数。

Functions can be assigned to a function property, and in this case they are called methods.

可以将函数分配给函数属性,在这种情况下,它们称为方法

In this example, the start property has a function assigned, and we can invoke it by using the dot syntax we used for properties, with the parentheses at the end:

在此示例中,已为start属性分配了一个函数,我们可以使用用于属性的点语法来调用它,并在括号的末尾加上括号:

const car = {
  brand: 'Ford',
  model: 'Fiesta',
  start: function() {
    console.log('Started')
  }
}

car.start()

Inside a method defined using a function() {} syntax we have access to the object instance by referencing this.

在使用function() {}语法定义的方法内部,我们可以通过引用this来访问对象实例。

In the following example, we have access to the brand and model properties values using this.brand and this.model:

在以下示例中,我们可以使用this.brandthis.model来访问brandmodel属性值:

const car = {
  brand: 'Ford',
  model: 'Fiesta',
  start: function() {
    console.log(`Started 
      ${this.brand} ${this.model}`)
  }
}

car.start()

It's important to note this distinction between regular functions and arrow functions - we don't have access to this if we use an arrow function:

请务必注意常规函数和箭头函数之间的区别-如果使用箭头函数,则无法访问this函数:

const car = {
  brand: 'Ford',
  model: 'Fiesta',
  start: () => {
    console.log(`Started 
      ${this.brand} ${this.model}`) //not going to work
  }
}

car.start()

This is because arrow functions are not bound to the object.

这是因为箭头功能未绑定到对象

This is the reason why regular functions are often used as object methods.

这就是为什么常规函数经常用作对象方法的原因。

Methods can accept parameters, like regular functions:

方法可以接受参数,例如常规函数:

const car = {
  brand: 'Ford',
  model: 'Fiesta',
  goTo: function(destination) {
    console.log(`Going to ${destination}`)
  }
}

car.goTo('Rome')

班级 (Classes)

We talked about objects, which are one of the most interesting parts of JavaScript.

我们讨论了对象,它们是JavaScript最有趣的部分之一。

In this chapter we'll go up one level by introducing classes.

在本章中,我们将通过介绍类来上一层。

What are classes? They are a way to define a common pattern for multiple objects.

什么是课程? 它们是为多个对象定义通用模式的一种方式。

Let's take a person object:

让我们来一个人对象:

const person = {
  name: 'Flavio'
}

We can create a class named Person (note the capital P, a convention when using classes), that has a name property:

我们可以创建一个名为Person的类(使用类时请注意大写P ,这是一个约定),该类具有name属性:

class Person {
  name
}

Now from this class, we initialize a flavio object like this:

现在,从此类中,我们初始化一个flavio对象,如下所示:

const flavio = new Person()

flavio is called an instance of the Person class.

flavio被称为Person类的实例

We can set the value of the name property:

我们可以设置name属性的值:

flavio.name = 'Flavio'

and we can access it using

我们可以使用

flavio.name

like we do for object properties.

就像我们对对象属性所做的一样。

Classes can hold properties, like name, and methods.

类可以保存属性,例如name和method。

Methods are defined in this way:

方法以这种方式定义:

class Person {
  hello() {
    return 'Hello, I am Flavio'
  }
}

and we can invoke methods on an instance of the class:

我们可以在类的实例上调用方法:

class Person {
  hello() {
    return 'Hello, I am Flavio'
  }
}
const flavio = new Person()
flavio.hello()

There is a special method called constructor() that we can use to initialize the class properties when we create a new object instance.

创建一个新的对象实例时,可以使用一种特殊的方法constructor()来初始化类属性。

It works like this:

它是这样的:

class Person {
  constructor(name) {
    this.name = name
  }

  hello() {
    return 'Hello, I am ' + this.name + '.'
  }
}

Note how we use this to access the object instance.

注意我们如何使用this来访问对象实例。

Now we can instantiate a new object from the class, pass in a string, and when we call hello we'll get a personalized message:

现在,我们可以从类中实例化一个新对象,传递一个字符串,当我们调用hello ,将收到一条个性化消息:

const flavio = new Person('flavio')
flavio.hello() //'Hello, I am flavio.'

When the object is initialized, the constructor method is called with any parameters passed.

初始化对象时,将使用传递的任何参数来调用constructor方法。

Normally methods are defined on the object instance, not on the class.

通常,方法是在对象实例上定义的,而不是在类上定义的。

You can define a method as static to allow it to be executed on the class instead:

您可以将方法定义为static方法,以允许在类上执行该方法:

class Person {
  static genericHello() {
    return 'Hello'
  }
}

Person.genericHello() //Hello

This is very useful, at times.

有时,这很有用。

遗产 (Inheritance)

A class can extend another class, and objects initialized using that class inherit all the methods of both classes.

一个类可以扩展另一个类,并且使用该类初始化的对象将继承这两个类的所有方法。

Suppose we have a class Person:

假设我们有一个Person类:

class Person {
  hello() {
    return 'Hello, I am a Person'
  }
}

We can define a new class, Programmer, that extends Person:

我们可以定义一个新类Programmer ,它扩展了Person

class Programmer extends Person {

}

Now if we instantiate a new object with the class Programmer, it has access to the hello() method:

现在,如果我们使用Programmer类实例化一个新对象,则可以访问hello()方法:

const flavio = new Programmer()
flavio.hello() //'Hello, I am a Person'

Inside a child class, you can reference the parent class by calling super():

在子类内部,可以通过调用super()来引用父类:

class Programmer extends Person {
  hello() {
    return super.hello() + 
      '. I am also a programmer.'
  }
}

const flavio = new Programmer()
flavio.hello()

The above program prints Hello, I am a Person. I am also a programmer..

上面的程序打印“ 你好,我是一个人”。 我也是一名程序员。

异步编程和回调 (Asynchonous Programming and Callbacks)

Most of the time, JavaScript code is run synchronously.

大多数时候,JavaScript代码是同步运行的。

This means that a line of code is executed, then the next one is executed, and so on.

这意味着先执行一行代码,然后再执行下一行,依此类推。

Everything is as you expect, and how it works in most programming languages.

一切都是您所期望的,以及它在大多数编程语言中如何工作。

However, there are times when you cannot just wait for a line of code to execute.

但是,有时您不能只等待一行代码执行。

You can't just wait 2 seconds for a big file to load, and halt the program completely.

您不能只等待2秒钟来加载一个大文件,然后完全停止该程序。

You can't just wait for a network resource to be downloaded before doing something else.

您不能仅等待网络资源下载再执行其他操作。

JavaScript solves this problem by using callbacks.

JavaScript通过使用回调解决了这个问题。

One of the simplest examples of how to use callbacks is with timers. Timers are not part of JavaScript, but they are provided by the browser and Node.js. Let me talk about one of the timers we have: setTimeout().

有关如何使用回调的最简单示例之一是使用计时器。 计时器不是JavaScript的一部分,但由浏览器和Node.js提供。 让我说说我们拥有的计时器之一: setTimeout()

The setTimeout() function accepts 2 arguments: a function, and a number. The number is the milliseconds that must pass before the function is ran.

setTimeout()函数接受2个参数:函数和数字。 该数字是函数运行前必须经过的毫秒数。

Example:

例:

setTimeout(() => {
  // runs after 2 seconds
  console.log('inside the function')
}, 2000)

The function containing the console.log('inside the function') line will be executed after 2 seconds.

包含console.log('inside the function')console.log('inside the function')将在2秒钟后执行。

If you add a console.log('before') prior to the function, and console.log('after') after it:

如果在函数console.log('before')添加console.log('before') ,并在函数console.log('after')

console.log('before')
setTimeout(() => {
  // runs after 2 seconds
  console.log('inside the function')
}, 2000)
console.log('after')

You will see this happening in your console:

您将在控制台中看到这种情况:

before
after
inside the function

The callback function is executed asynchronously.

回调函数是异步执行的。

This is a very common pattern when working with the file system, the network, events, or the DOM in the browser.

当使用文件系统,网络,事件或浏览器中的DOM时,这是一种非常常见的模式。

All of the things I mentioned are not "core" JavaScript, so they are not explained in this handbook, but you'll find lots of examples in my other handbooks available at https://flaviocopes.com.

我提到的所有内容都不是“核心” JavaScript,因此本手册中没有对它们进行说明,但是您可以在https://flaviocopes.com上的其他手册中找到很多示例。

Here's how we can implement callbacks in our code.

这是我们如何在代码中实现回调的方法。

We define a function that accepts a callback parameter, which is a function.

我们定义一个函数,该函数接受一个callback参数。

When the code is ready to invoke the callback, we invoke it by passing the result:

当代码准备好调用回调时,我们通过传递结果来调用它:

const doSomething = callback => {
  //do things
  //do things
  const result = /* .. */
  callback(result)
}

Code using this function would use it like this:

使用此功能的代码将像这样使用它:

doSomething(result => {
  console.log(result)
})

承诺 (Promises)

Promises are an alternative way to deal with asynchronous code.

承诺是处理异步代码的另一种方法。

As we saw in the previous chapter, with callbacks we'd be passing a function to another function call that would be called when the function has finished processing.

如上一章所述,通过回调,我们会将一个函数传递给另一个函数调用,该函数在处理完成后将被调用。

Like this:

像这样:

doSomething(result => {
  console.log(result)
})

When the doSomething() code ends, it calls the function received as a parameter:

doSomething()代码结束时,它将调用作为参数接收的函数:

const doSomething = callback => {
  //do things
  //do things
  const result = /* .. */
  callback(result)
}

The main problem with this approach is that if we need to use the result of this function in the rest of our code, all our code must be nested inside the callback, and if we have to do 2-3 callbacks we enter in what is usually defined "callback hell" with many levels of functions indented into other functions:

这种方法的主要问题是,如果我们需要在其余代码中使用该函数的结果,则我们所有的代码都必须嵌套在回调中,如果我们必须执行2-3个回调,则应输入通常定义为“回调地狱”,其中许多功能都可以缩进其他功能中:

doSomething(result => {
  doSomethingElse(anotherResult => {
    doSomethingElseAgain(yetAnotherResult => {
      console.log(result)
    })
  }) 
})

Promises are one way to deal with this.

承诺是处理此问题的一种方法。

Instead of doing:

而不是做:

doSomething(result => {
  console.log(result)
})

We call a promise-based function in this way:

我们以这种方式调用基于promise的函数:

doSomething()
  .then(result => {
    console.log(result)
  })

We first call the function, then we have a then() method that is called when the function ends.

我们首先调用该函数,然后有一个then()方法在函数结束时被调用。

The indentation does not matter, but you'll often use this style for clarity.

缩进并不重要,但是为了清楚起见,您通常会使用这种样式。

It's common to detect errors using a catch() method:

使用catch()方法检测错误是很常见的:

doSomething()
  .then(result => {
    console.log(result)
  })
  .catch(error => {
    console.log(error)
  })

Now, to be able to use this syntax, the doSomething() function implementation must be a little bit special. It must use the Promises API.

现在,要能够使用此语法, doSomething()函数的实现必须有点特殊。 它必须使用Promises API。

Instead of declaring it as a normal function:

而不是将其声明为正常功能:

const doSomething = () => {
  
}

We declare it as a promise object:

我们将其声明为Promise对象:

const doSomething = new Promise()

and we pass a function in the Promise constructor:

然后我们在Promise构造函数中传递一个函数:

const doSomething = new Promise(() => {

})

This function receives 2 parameters. The first is a function we call to resolve the promise, the second a function we call to reject the promise.

该函数接收2个参数。 第一个函数是我们用来解决承诺的函数,第二个函数是我们用来拒绝承诺的函数。

const doSomething = new Promise(
  (resolve, reject) => {
    
})

Resolving a promise means to complete it successfully (which results in calling the then() method in whatever uses it).

兑现承诺意味着成功完成承诺(这会导致在使用承诺的情况下调用then()方法)。

Rejecting a promise means ending it with an error (which results in calling the catch() method in whatever uses it).

拒绝承诺意味着以错误结束(这会导致在使用该承诺的任何地方调用catch()方法)。

Here's how:

这是如何做:

const doSomething = new Promise(
  (resolve, reject) => {
    //some code
    const success = /* ... */
    if (success) {
      resolve('ok')
    } else {
      reject('this error occurred')
    }
  }
)

We can pass a parameter to the resolve and reject functions, of any type we want.

我们可以将参数传递给所需的任何类型的resolve和reject函数。

异步并等待 (Async and Await)

Async functions are a higher level abstraction of promises.

异步功能是对Promise的更高级别的抽象。

An async function returns a promise, like in this example:

An async function returns a promise, like in this example:

const getData = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => 
      resolve('some data'), 2000)
  })
}

Any code that wants to use this function will use the await keyword right before the function:

Any code that wants to use this function will use the await keyword right before the function:

const data = await getData()

and doing so, any data returned by the promise is going to be assigned to the data variable.

and doing so, any data returned by the promise is going to be assigned to the data variable.

In our case, the data is the "some data" string.

In our case, the data is the "some data" string.

With one particular caveat: whenever we use the await keyword, we must do so inside a function defined as async.

With one particular caveat: whenever we use the await keyword, we must do so inside a function defined as async .

Like this:

像这样:

const doSomething = async () => {
  const data = await getData()
  console.log(data)
}

The async/await duo allows us to have a cleaner code and a simple mental model to work with asynchronous code.

The async/await duo allows us to have a cleaner code and a simple mental model to work with asynchronous code.

As you can see in the example above, our code looks very simple. Compare it to code using promises, or callback functions.

As you can see in the example above, our code looks very simple. Compare it to code using promises, or callback functions.

And this is a very simple example, the major benefits will arise when the code is much more complex.

And this is a very simple example, the major benefits will arise when the code is much more complex.

As an example, here's how you would get a JSON resource using the Fetch API, and parse it, using promises:

As an example, here's how you would get a JSON resource using the Fetch API, and parse it, using promises:

const getFirstUserData = () => {
  // get users list
  return fetch('/users.json') 
    // parse JSON
    .then(response => response.json()) 
    // pick first user
    .then(users => users[0]) 
    // get user data
    .then(user => 
      fetch(`/users/${user.name}`)) 
    // parse JSON
    .then(userResponse => response.json()) 
}

getFirstUserData()

And here is the same functionality provided using await/async:

And here is the same functionality provided using await/async:

const getFirstUserData = async () => {
  // get users list
  const response = await fetch('/users.json') 
  // parse JSON
  const users = await response.json() 
  // pick first user
  const user = users[0] 
  // get user data
  const userResponse = 
    await fetch(`/users/${user.name}`)
  // parse JSON
  const userData = await user.json() 
  return userData
}

getFirstUserData()

可变范围 (Variable scope)

When I introduced variables, I talked about using const, let, and var.

When I introduced variables, I talked about using const , let , and var .

Scope is the set of variables that's visible to a part of the program.

Scope is the set of variables that's visible to a part of the program.

In JavaScript we have a global scope, block scope and function scope.

In JavaScript we have a global scope, block scope and function scope.

If a variable is defined outside of a function or block, it's attached to the global object and it has a global scope, which mean it's available in every part of a program.

If a variable is defined outside of a function or block, it's attached to the global object and it has a global scope, which mean it's available in every part of a program.

There is a very important difference between var, let and const declarations.

There is a very important difference between var , let and const declarations.

A variable defined as var inside a function is only visible inside that function, similar to a function's arguments.

A variable defined as var inside a function is only visible inside that function, similar to a function's arguments.

A variable defined as const or let on the other hand is only visible inside the block where it is defined.

A variable defined as const or let on the other hand is only visible inside the block where it is defined.

A block is a set of instructions grouped into a pair of curly braces, like the ones we can find inside an if statement, a for loop, or a function.

A block is a set of instructions grouped into a pair of curly braces, like the ones we can find inside an if statement, a for loop, or a function.

It's important to understand that a block does not define a new scope for var, but it does for let and const.

It's important to understand that a block does not define a new scope for var , but it does for let and const .

This has very practical implications.

This has very practical implications.

Suppose you define a var variable inside an if conditional in a function

Suppose you define a var variable inside an if conditional in a function

function getData() {
  if (true) {
    var data = 'some data'
    console.log(data) 
  }
}

If you call this function, you'll get some data printed to the console.

If you call this function, you'll get some data printed to the console.

If you try to move console.log(data) after the if, it still works:

If you try to move console.log(data) after the if , it still works:

function getData() {
  if (true) {
    var data = 'some data'
  }
  console.log(data) 
}

But if you switch var data to let data:

But if you switch var data to let data :

function getData() {
  if (true) {
    let data = 'some data'
  }
  console.log(data) 
}

You'll get an error: ReferenceError: data is not defined.

You'll get an error: ReferenceError: data is not defined .

This is because var is function scoped, and there's a special thing happening here called hoisting. In short, the var declaration is moved to the top of the closest function by JavaScript before it runs the code. This is what the function looks like to JS internally, more or less:

This is because var is function scoped, and there's a special thing happening here called hoisting. In short, the var declaration is moved to the top of the closest function by JavaScript before it runs the code. This is what the function looks like to JS internally, more or less:

function getData() {
  var data
  if (true) {
    data = 'some data'
  }
  console.log(data) 
}

This is why you can also console.log(data) at the top of a function, even before it's declared, and you'll get undefined as a value for that variable:

This is why you can also console.log(data) at the top of a function, even before it's declared, and you'll get undefined as a value for that variable:

function getData() {
  console.log(data) 
  if (true) {
    var data = 'some data'
  }
}

but if you switch to let, you'll get an error ReferenceError: data is not defined, because hoisting does not happen to let declarations.

but if you switch to let , you'll get an error ReferenceError: data is not defined , because hoisting does not happen to let declarations.

const follows the same rules as let: it's block scoped.

const follows the same rules as let : it's block scoped.

It can be tricky at first, but once you realize this difference, then you'll see why var is considered a bad practice nowadays compared to let - they have less moving parts, and their scope is limited to the block, which also makes them very good as loop variables because they cease to exist after a loop has ended:

It can be tricky at first, but once you realize this difference, then you'll see why var is considered a bad practice nowadays compared to let - they have less moving parts, and their scope is limited to the block, which also makes them very good as loop variables because they cease to exist after a loop has ended:

function doLoop() {
  for (var i = 0; i < 10; i++) {
    console.log(i)
  }
  console.log(i)
}

doLoop()

When you exit the loop, i will be a valid variable with value 10.

When you exit the loop, i will be a valid variable with value 10.

If you switch to let, when you try to console.log(i) will result in an error ReferenceError: i is not defined.

If you switch to let , when you try to console.log(i) will result in an error ReferenceError: i is not defined .

结论 (Conclusion)

Thanks a lot for reading this book.

Thanks a lot for reading this book.

I hope it will inspire you to learn more about JavaScript.

I hope it will inspire you to learn more about JavaScript.

For more on JavaScript, check out my blog flaviocopes.com.

For more on JavaScript, check out my blog flaviocopes.com .

Note: You can get a PDF and ePub version of this JavaScript Beginner's Handbook

Note: You can get a PDF and ePub version of this JavaScript Beginner's Handbook

翻译自: https://www.freecodecamp.org/news/the-complete-javascript-handbook-f26b2c71719c/

javascript入门

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值