今天,在JavaScript手册的翻译的第三部分中,我们将讨论声明变量的不同方法,数据类型,表达式以及使用对象的功能。
→
第1部分:第一个程序,语言功能,标准→
第2部分:代码样式和程序结构→
第3部分:变量,数据类型,表达式,对象→
第4部分:功能→
第5部分:数组和循环→
第6部分:异常,分号,通配符文字→
第7部分:严格模式,此关键字,事件,模块,数学计算→
第8部分:ES6功能概述→
第9部分:ES7,ES8和ES9标准概述
变数
变量是分配了值的标识符。 可以在程序中访问变量,以这种方式使用为其分配的值。
JavaScript本身的变量不包含有关将存储在其中的值类型的信息。 这意味着通过写入变量(例如字符串),以后可以在其中写入数字。 这样的操作不会引起程序错误。 因此,JavaScript有时被称为“非类型化”语言。
在使用变量之前,必须使用
var或
let关键字对其进行声明。 当涉及常量时,将使用
const关键字。 在不使用这些关键字的情况下,可以声明变量并为其分配一个特定值,但是不建议这样做。
▍关键字var
在ES2015标准之前,使用
var关键字是声明变量的唯一方法。
var a = 0
如果在此构造中省略
var ,则该值将分配给未声明的变量。 该操作的结果取决于程序运行的模式。
因此,如果启用了所谓的严格模式,则将导致错误。 如果未启用严格模式,则将发生隐式变量声明,并将其分配给全局对象。 特别是,这意味着即使在函数完成工作后,在某个函数中以这种方式隐式声明的变量也将可用。 通常,期望函数中声明的变量不会“超出”其限制。 看起来像这样:
function notVar() { bNotVar = 1 // } notVar() console.log(bNotVar)
它会
1控制台上得到
1 ,通常没有人期望程序会出现这种行为,表达式
bNotVar = 1看起来并不像尝试声明和初始化变量,而是试图访问在函数外部
bNotVar = 1的变量(这是很正常的)。 结果,变量的隐式声明会使读取代码的人感到困惑,并可能导致程序异常。 稍后我们将讨论功能和范围,现在,当表达式的含义是声明变量时,请始终尝试使用专用关键字。 如果在此示例中,函数主体被重写为
var bNotVar = 1 ,则尝试启动上述代码片段将导致错误消息(可以在浏览器控制台中看到)。
例如,它可能看起来像这样:
Uncaught ReferenceError: bNotVar is not defined 。 其含义可以归结为以下事实:程序无法使用不存在的变量运行。 初次启动程序时,看到这样的错误消息比编写无法理解的,可能表现异常的代码要好得多。
如果在声明变量时未对其进行初始化,未为其分配任何值,则将自动为其分配
undefined的值。
var a //typeof a === 'undefined'
通过使用
var关键字声明的变量可以通过为它们分配新的值来重复声明(但这会使读取代码的人感到困惑)。
var a = 1 var a = 2
您可以在一个表达式中声明几个变量:
var a = 1, b = 2
变量的范围称为程序的范围,在该程序中可以访问(可见)此变量。
使用函数外部的
var关键字初始化的变量分配给全局对象。 它具有全局范围,可从程序中的任何位置访问。 如果使用函数内部的
var关键字声明了变量,则该变量仅在该函数内部可见,是该函数的局部变量。
如果在使用
var的函数中声明了变量,且其名称与全局范围内某个变量的名称匹配,则它将“覆盖”全局变量。 也就是说,在函数内部访问此类变量时,它将使用其本地版本。
重要的是要理解,块(用大括号括起来的代码区域)不会创建新的可见性区域。 调用函数时会创建一个新的作用域。
var关键字具有所谓的功能范围,而不是功能块。
如果在功能代码中声明了变量,则整个功能代码都可以看到该变量。 即使在函数代码的末尾用
var声明了变量,您也可以在代码的开头引用它,因为引发变量(提升)的机制在JavaScript中起作用。 该机制“提高”变量声明,但不提高其初始化操作。 这可能会引起混乱,因此将其作为在函数开始时声明变量的规则。
let关键字let
let关键字出现在ES2015中,可以简化为
var的“块”版本。 使用
let关键字声明的变量的范围仅限于声明了它的块,运算符或表达式以及嵌套块。
如果“ let”一词本身看起来不太清楚,则可以想象使用了“ let”一词。 然后,可以将表达式
let color = 'red'转换为英语:“让颜色为红色”,并转换为俄语:“使颜色为红色”。
通过使用
let关键字,您可以消除与
var关键字相关联的歧义(例如,您不能使用
let两次声明相同的变量)。 例如,在初始化循环时,在函数外部使用
let不会创建全局变量。
例如,这样的代码将导致错误:
for (let i = 0; i < 5; i++) { console.log(i) } console.log(i)
如果在初始化循环时使用计数器
var声明计数器
i ,则在完成循环后,
i将在循环外部可用。
如今,在基于现代标准开发JS程序时,您可以完全放弃
var而仅使用
let和
const关键字。
▍关键字const
使用
var或
let关键字声明的变量可以被覆盖。 如果使用
const代替这些关键字,则不能为通过常量帮助声明和初始化的常量分配新值。
const a = 'test'
在此示例中,不能为常数
a分配新值。 但应注意,如果
a不是原始值(例如数字),而是对象,则使用
const关键字不会保护该对象不受更改。
当他们说将对象写入变量时,实际上是指变量引用该对象。 此链接无法更改,并且链接可以指向的对象也可以更改。
const关键字不会使对象不可变。 它只是防止以相应的常量编写的对其引用的更改。 看起来是这样的:
const obj = {} console.log(obj.a) obj.a = 1 // console.log(obj.a) //obj = 5 //
在
obj常量中,初始化后会写入一个新的空对象。 尝试访问其不存在的属性
a不会导致错误。 控制台变得
undefined 。 之后,我们向对象添加一个新属性,然后再次尝试访问它。 这次,此属性的值
1进入控制台。 如果取消注释示例的最后一行,则尝试执行此代码将导致错误。
const关键字与
let非常相似,尤其是它具有块作用域。
在现代条件下,完全可以接受使用
const关键字,仅在特殊情况下才允许使用,声明其值不打算更改的所有实体。 怎么了 事实是,最好努力使用最简单的可用结构,以免使程序复杂化并避免错误。
资料类型
JavaScript有时被称为“非类型化”语言,但事实并非如此。 确实可以将不同类型的值写入变量,但是JavaScript中还是有数据类型。 特别是,我们正在谈论原始和对象数据类型。
为了确定某个值的数据类型,可以使用
typeof运算符。 它返回一个指示操作数类型的字符串。
▍原始数据类型
以下是原始JavaScript数据类型的列表:
numberstring (字符串)boolean (布尔值)null (特殊null值)undefined (特殊值undefined )symbol (在特殊情况下使用的符号,出现在ES6中)
此处,数据类型的名称以
typeof运算符返回它们的形式给出。
让我们讨论一下此列表中最常用的数据类型。
类型编号
JavaScript中
number类型的值表示为64位双精度浮点数。
在代码中,数字文字在十进制系统中表示为整数和小数。 您可以使用其他方法来记录数字。 例如,如果在数字文字的开头有前缀
0x它被视为以十六进制表示的数字。 数字也可以用指数符号表示(在这种数字中,您可以找到字母
e )。
以下是整数条目的示例:
10 5354576767321 0xCC //
这是分数。
3.14 .1234 5.2e4 //5.2 * 10^4
数值文字(此行为也是某些其他原始类型的特征),当您尝试将它们作为对象访问时,在操作期间会自动将其转换为相应的对象,这些对象称为“对象包装器”。 在这种情况下,我们正在谈论对象包装器
Number 。
例如,此处看起来像是尝试访问变量
a ,其中在谷歌浏览器控制台中将数字文字作为对象写入其中。
数字对象换行工具提示例如,如果您使用
Number类型的对象的
toString()方法,它将返回数字的字符串表示形式。 看起来像可以在浏览器控制台(以及常规代码)中执行的相应命令,如下所示:
a.toString()
注意方法名称后面的双括号。 如果您不放置它们,则系统不会给出错误,但是,控制台将显示一些与数字5完全不同的东西,而不是预期的输出。
全局
Number对象可以以构造函数的形式使用,可以在其帮助下创建新的数字(尽管这种形式几乎从未使用过),也可以将其用作独立实体,而无需创建它的实例(即,一些数字表示)帮助)。 例如,其
Number.MAX_VALUE属性包含可以用JavaScript表示的最大数值。
类型字符串
string类型的值是
string序列。 这些值被指定为用单引号或双引号引起来的字符串文字。
'A string' "Another string"
可以使用反斜杠字符将字符串值分为几部分。
"A \ string"
字符串可能包含所谓的转义序列,当将字符串打印到控制台时会对其进行解释。 例如,序列
\n表示换行符。 反斜杠字符还可以用于将引号添加到包含在同一引号中的字符串。 用
\转义引号字符会导致系统无法将其视为特殊字符。
'I\'ma developer'
可以使用
+运算符来连接字符串。
"A " + "string"
模板文字
ES2015引入了所谓的模式文字或模式字符串。 它们是用反引号(
` )括起来的字符串,并具有一些有趣的属性。
`a string`
例如,在模板文字中,您可以替换某些值,这些值是评估JavaScript表达式的结果。
`a string with ${something}` `a string with ${something+somethingElse}` `a string with ${obj.something()}`
使用反引号使编写多行字符串文字变得容易:
`a string with ${something}`
布尔型
JavaScript有两个使用布尔值的保留字-分别为
true (true)和
false (false)。 比较运算(例如
== ,
=== ,
< ,
> )返回
true或
false 。
逻辑表达式用于
if和
while等构造中,有助于控制程序的进度。
应该注意的是,在期望为
true或
false情况下,您可以使用语言自动将其视为真(真)或假(假)的其他值。
特别是,以下是错误值:
0 -0 NaN undefined null '' //
其余值为true。
输入空值
JavaScript具有一个特殊的
null值,该值指示不存在值。 其他语言也使用类似的含义。
类型未定义
写入某个变量的
undefined值表示该变量未初始化,并且没有任何值。
该值是从没有使用
return关键字显式返回结果的函数中自动返回的。 如果函数接受未指定的参数,则在调用该参数时未将其设置为
undefined 。
为了检查
undefined的值,可以使用以下构造。
typeof variable === 'undefined'
▍物件
所有不是基本值的值都具有对象类型。 我们在谈论函数,数组,所谓的“对象”以及许多其他实体。 所有这些数据类型都是基于
object类型的,尽管它们在很多方面都存在差异,但是它们有很多共同点。
表达方式
表达式是代码片段,可以根据执行的计算将特定值处理并获得。 JavaScript有几种类别的表达式。
算术表达式
计算结果为数字的表达式属于此类别。
1 / 2 i++ i -= 2 i * 2
字符串表达式
计算此类表达式的结果是字符串。
'A ' + 'string' 'A ' += 'string'
主要表达
文字,常量和对标识符的引用都属于此类。
2 0.02 'something' true false this // , undefined i // i
这还包括JavaScript的一些关键字和构造。
function class function* // yield // / yield* // async function* // await // /pattern/i // () //
数组和对象初始化表达式
[] // {} // [1,2,3] {a: 1, b: 2} {a: {b: 1}}
逻辑表达式
在逻辑表达式中,使用逻辑运算符,其计算结果为逻辑值。
a && b a || b !a
属性访问表达式
这些表达式使您可以访问对象的属性和方法。
object.property // ( ) object[property] object['property']
对象创建表达式
new object() new a(1) new MyRectangle('name', 2, {a: 4})
函数声明表达式
function() {} function(a, b) { return a * b } (a, b) => a * b a => a * 2 () => { return 2 }
呼叫表达
这样的表达式用于调用对象的函数或方法。
ax(2) window.resize()
处理对象
上面我们已经遇到对象,谈论对象文字,调用它们的方法,访问它们的属性。 在这里,我们更详细地讨论对象,尤其是考虑原型继承机制和
class关键字的使用。
▍原型继承
JavaScript在现代编程语言中脱颖而出,因为它支持原型继承。 大多数面向对象的语言都使用基于类的继承模型。
每个JavaScript对象都有一个特殊的属性(
__proto__ ),该属性指向其原型的另一个对象。 一个对象继承了原型的属性和方法。
假设我们有一个使用对象文字创建的对象。
const car = {}
或者我们使用
Object构造函数创建了一个对象。
const car = new Object()
在上述任何一种情况下,
car对象的原型都是
Object.prototype 。
如果创建也是对象的数组,则其原型为
Array.prototype对象。
const list = [] // const list = new Array()
您可以如下验证。
car.__proto__ == Object.prototype //true car.__proto__ == new Object().__proto__ //true list.__proto__ == Object.prototype //false list.__proto__ == Array.prototype //true list.__proto__ == new Array().__proto__ //true
在这里,我们使用了
__proto__属性,开发人员不必使用它,但是您通常可以访问它。 应该注意的是,获取对象原型的一种更可靠的方法是使用全局
Object的
getPrototypeOf()方法。
Object.getPrototypeOf(new Object())
具有该原型的对象可以访问该原型的所有属性和方法。 例如,在这里看起来像他们的数组列表。
数组提示所有对象的基本原型是
Object.prototype 。
Array.prototype.__proto__ == Object.prototype
Object.prototype原型。
我们上面看到的是原型链的示例。
尝试访问对象的属性或方法时,如果对象本身不具有此类属性或方法,则在其原型中搜索对象,然后在原型原型中进行搜索,依此类推,直到找到所需的对象或直到原型链不会结束。
除了使用
new运算符以及使用对象常量或数组常量创建对象之外,还可以使用
Object.create()方法创建对象的实例。 传递给此方法的第一个参数是一个对象,它将成为使用该方法创建的对象的原型。
const car = Object.create(Object.prototype)
您可以使用
isPrototypeOf()方法检查某个对象是否是另一个对象的原型链的一部分。
const list = [] Array.prototype.isPrototypeOf(list)
构造函数
上面,我们使用该语言中已经可用的构造函数创建了新对象(调用它们时,将使用
new关键字)。 . .
function Person(name) { this.name = name } Person.prototype.hello = function() { console.log(this.name) } let person = new Person('Flavio') person.hello() console.log(Person.prototype.isPrototypeOf(person))
-. ,
this .
name , . . - ,
name , .
,
name , . , , ,
hello() . ,
Person hello() ( ).
▍
ES6 JavaScript «».
JavaScript . , JS . , , , « » . , , , , , .
.
class Person { constructor(name) { this.name = name } hello() { return 'Hello, I am ' + this.name + '.' } }
,
new ClassIdentifier() .
constructor , .
.
hello() — , , .
Person .
const flavio = new Person('Flavio') flavio.hello()
,
. , , , , .
, ( ) , , -, .
class Programmer extends Person { hello() { return super.hello() + ' I am a programmer.' } } const flavio = new Programmer('Flavio') flavio.hello()
hello() Hello, I am Flavio. I am a programmer .
(), .
super .
, , , , , . (
static ) , .
JavaScript , (, ) . , , .
,
get set . — , , . -, — .
class Person { constructor(name) { this.userName = name } set name(value) { this.userName = value } get name() { return this.userName } }
总结
, , JavaScript. .
亲爱的读者们! JS, , class.
