尽管 JavaScript 的名称如此,但它与 Java 的关联仅在于两者共享一些语法相似之处。JavaScript 的语法在最初开发时受到了 Java 语法的粗略启发,并且在 1995 年首次在 Netscape Navigator 的 Beta 版本中发布时,它被称为“LiveScript”,这既是为了与 Netscape 的其他命名产品保持一致,也是为了致敬它在浏览器中“实时”运行这一事实。Microsoft 随后在 Internet Explorer 3.0 中发布了他们自己对 JavaScript 的实现,“JScript”。
Netscape 将这项早期工作提交给了 Ecma International(一个制定和发布技术标准的组织),以正式确定和详细说明其他浏览器应如何理解这种脚本语言。1997 年,Ecma International 发布了 ECMA-262,对名为 ECMAScript 的脚本语言的第一个版本进行了标准化。ECMAScript 是一个标准,它为创建更具体的脚本语言提供了依据,例如,Microsoft 后来在现已废弃的 JScript、Adobe 的 ActionScript 以及 JavaScript 本身方面的工作。
在讨论 JavaScript 的具体方面和功能时,这种区别非常重要。“ES5”指的是 ECMAScript 标准在 2009 年的第一个主要“版本化”版本,在此之前经历了多年的零星开发。“ES6”(或“ES2015”)是 ECMAScript 第六版(于 2015 年发布)制定的标准的简写。在 ES6 之后,ECMAScript 标准的新版本每年都会发布,每个版本的更改和新增内容都按年份引用,如“ES2016”或“ES2017”。
基本规则
与编译型语言不同,JavaScript 不是将人编写的代码翻译成浏览器可以理解的形式。脚本与标记、图像和样式表等资源一起发送到浏览器,浏览器以编写脚本的相同方式解释脚本:作为人类可读的 Unicode 字符序列,从左到右、从上到下解析。
当 JavaScript 解释器接收到脚本时,它首先执行词法分析,解析构成脚本的长字符串字符,并将其转换为以下离散的输入元素
- 令牌
- 格式控制字符
- 行终止符
- 注释
- 空格(几乎总是指制表符和空格)。
脚本的结果在重新加载页面或离开当前页面后不会持久存在,除非您在脚本中包含明确的指令以执行其他操作。
从高层次来看,JavaScript 应用程序由语句和表达式组成。
语句
语句是由一行或多行代码组成的指令单元,表示一个操作。例如,您可以使用以下语句为名为 myVariable
的变量赋值
let myVariable = 4;
myVariable;
> 4
为了得到正确解释,语句必须以分号结尾。但是,在编写 JavaScript 时,这些分号并非总是必需的。一种称为自动分号插入的功能允许将完整语句后的换行符视为分号,前提是缺少分号会导致错误。
ASI 是一种错误纠正,而不是 JavaScript 本身的一种宽松方面。由于过度依赖这种错误纠正可能会导致歧义,从而破坏您的代码,因此您仍然应该手动以分号结束每个语句。
块语句
块语句将任意数量的语句和声明分组在一对花括号 ({}
) 内。它允许您在 JavaScript 仅期望一个语句的地方组合语句。
您最常在 控制流 语句(例如 if
)旁边看到块语句
if ( x === 2 ) {
//some behavior;
}
表达式
表达式是一个代码单元,它产生一个值,因此可以在期望值的地方使用。2 + 2
是一个表达式,它产生值 4
2 + 2;
> 4
“分组运算符”(一对匹配的闭合括号)用于对表达式的各部分进行分组,以确保表达式的一部分被评估为一个单元。例如,您可以使用分组运算符来覆盖数学运算顺序,或提高代码的可读性
2 + 2 * 4;
> 10
( 2 + 2 ) * 4;
> 16
let myVariable = ( 2 + 2 );
myVariable;
> 4
弱类型
JavaScript 是一种弱类型语言,这意味着数据值不需要显式标记为特定的数据类型。与强类型语言不同,JavaScript 可以从值的上下文中推断出预期类型,并将值转换为该类型。此过程称为类型强制转换。
例如,如果您在强类型语言(如 Python)中将数字添加到字符串值,则结果会出错
>>> "1" + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
JavaScript 不会返回错误,而是将数字值强制转换为字符串并将两个值连接起来,这是将任何值添加到字符串时最有可能的预期行为
"1" + 1;
> "11"
数据类型也可以显式强制转换。以下示例使用 JavaScript 的内置 toString
方法将数值 100
强制转换为字符串值 "100"
let myVariable = 100;
typeof myVariable;
> "number"
myVariable = myVariable.toString();
> "100"
typeof myVariable;
> "string"
区分大小写
与 HTML 和大多数 CSS 不同,JavaScript 本身完全区分大小写。这意味着您必须始终保持所有内容的大小写一致,从语言内置的属性和方法到您自己定义的标识符。
console.log( "Log this." );
> Log this.
console.Log( "Log this too." );
> Uncaught TypeError: console.Log is not a function
const myVariable = 2;
myvariable;
> Uncaught ReferenceError: myvariable is not defined
myVariable;
> 2
空格
JavaScript 对空格不敏感。这意味着解释器会忽略使用的空格量和类型(制表符或空格)。
console.log( "Log this" );console.log("Log this too");
> "Log this."
> "Log this too."
但是,空格的存在作为词法标记之间的分隔符可能很重要
let x;
[令牌: [let]
[x]
]
letx;
> Uncaught ReferenceError: letx is not defined
[令牌: [letx]
]
在空格用于分隔有意义的词法标记的地方,解析器会忽略空格的数量和类型
let x = 2;
[令牌: [let]
[x]
[=]
[2]
]
行中断也是如此,尽管在某些情况下,行中断可能会因过早结束语句而导致问题)
let x
=
2;
[令牌: [let]
[x]
[=]
[2]
]
从文体上讲,某些类型的语句经常占用单行
let x = 1;
let y = 2;
而某些语句通常使用多行
if ( x == 2 ) {
//some behavior;
}
但是,这些约定严格来说是为了提高可读性。JavaScript 以与以下示例相同的方式解释之前的示例
let x=1;let y=2;
if(x==2){}
因此,从脚本文件中删除不必要的空格以减小传输大小的自动化过程,是为生产环境准备 JavaScript 的常见步骤,同时还进行许多其他优化。
在 JavaScript 中使用空格字符在很大程度上取决于作者和维护者的偏好。有多个开发人员贡献代码的 JavaScript 项目通常会建议或强制执行某些空格约定,以确保代码格式一致,例如,使用制表符或空格来缩进嵌套语句
let myVariable = 10;
if ( typeof myVariable === "number" ) {
console.log( "This variable is a number." );
if( myVariable > 5 ) {
console.log( "This variable is greater than five." );
}
}
> "This variable is a number."
> "This variable is greater than five."
检查您的理解情况
什么是表达式?
JavaScript 区分大小写。