JavaScript

JavaScript(通常缩写为JS)是一种高级的、解释型的编程语言。它支持面向对象编程,命令式编程,以及函数式编程。JavaScript 是一种脚本,一门编程语言,它可以在网页上实现复杂的功能,网页展现给你的不再是简单的静态信息,而是实时的内容更新,交互式的地图,2D/3D 动画,滚动播放的视频等等。虽然它是作为开发Web 页面的脚本语言而出名的,但是它也被用到了很多非浏览器环境中,例如 Node.js、 Apache CouchDB 和 Adobe Acrobat。

JavaScript 的标准是ECMA国际组织发布的 ECMAScript 。截至 2012 年,所有的现代浏览器都完整的支持 ECMAScript 5.1。

不要将 JavaScript 与 Java 混淆。虽然“Java”和“JavaScript”都是 Oracle 公司在美国和其他国家注册(或未注册)的商标,但是这两门语言在语法、语义与用途方面有很大不同。

简介

不同于服务器端脚本语言,例如PHPASP,JavaScript主要被作为客户端脚本语言在用户的浏览器上运行,不需要服务器的支持。所以在早期程序员比较青睐于JavaScript以减少对服务器的负担,而与此同时也带来另一个问题:安全性。而随着服务器变得强大,现在的程序员更喜欢运行于服务端的脚本以保证安全,但JavaScript仍然以其跨平台、容易上手等优势大行其道。同时,有些特殊功能(如AJAX)必须依赖JavaScript在客户端进行支持。随着引擎如V8和框架如Node.js的发展,及其事件驱动及异步IO等特性,JavaScript逐渐被用来编写服务器端程序。且在近几年中,Node.js的出世,让JavaScript也具有了一定的服务器功能。

时间轴

  • 1995年,网景招募了布兰登·艾克,目标是把Scheme语言嵌入到Netscape Navigator浏览器当中。但更早之前,网景已经跟昇阳合作在Netscape Navigator中支持Java,这时网景内部产生激烈的争论。
  • 1995年5月,艾克仅花了十天时间就把原型设计出来了。最初命名为Mocha
  • 1995年9月,在Netscape Navigator 2.0的Beta版中改名为LiveScript
  • 1995年12月,Netscape Navigator 2.0 Beta 3中部署时被重命名为JavaScript,当时网景公司与昇阳电脑公司组成的开发联盟为了让这门语言搭上Java这个编程语言“热词”,因此将其临时改名为JavaScript,日后这成为大众对这门语言有诸多误解的原因之一。
  • 1996年11月,网景正式向ECMA(欧洲计算机制造商协会)提交语言标准。
  • 1997年6月,ECMA以JavaScript语言为基础制定了ECMAScript标准规范ECMA-262。JavaScript成为了ECMAScript最著名的实现之一。
  • 2012 年,所有的现代浏览器都完整的支持 ECMAScript 5.1,旧版本的浏览器至少支持 ECMAScript 3 标准。
  • 2015年6月17日,ECMA国际组织发布了 ECMAScript 的第六版 ,该版本正式名称为 ECMAScript 2015,但通常被称为 ECMAScript 6 或者 ES6。自此,ECMAScript 每年发布一次新标准。
  • 2018年6月,发布ECMAScript 2018 (ECMAScript 9)。
  • 2019年6月,发布ECMAScript 2019 (ECMAScript 10)。
  • 2020年6月,发布ECMAScript 2020 (ECMAScript 11)。

了解更多 >> 维基百科:JavaScript - 历史 维基百科:ECMAScript - 版本


提前了解

学习JavaScript 知识,应当提前了解:

  • HTML,一种用于创建网页的标准标记语言。
  • CSS,用来为结构化文档(如HTML文档或XML应用)添加样式(字体、间距和颜色等)。

基础

了解更多 >> MDN文档:JavaScript 第一步


基本语法

JavaScript 借鉴了 Java 的大部分语法,但同时也受到 Awk,PerlPython的影响。

了解更多 >> MDN文档:JavaScript 指南 - 语法和数据类型 MDN文档:JavaScript 参考 - 词法文法


区分大小写

JavaScript 是区分大小写的,并使用 Unicode 字符集。例如你可以使用中文用作变量名:

var 早 = "foobar";

语句与语句块

在 JavaScript 中,指令被称为语句 (Statement),并用分号 ; 进行分隔。如果一条语句独占一行的话,那么分号是可以省略的。虽然不是必需的,但是在一条语句的末尾加上分号是一个很好的习惯。这个习惯可以大大减少代码中产生 bug 的可能性。如果一行中有多条语句,那么这些语句必须以分号分开。

最基本的语句块由一对大括号界定,包含多个或零个语句,如:

{
  statement_1; 
  statement_2;
  statement_n;
}


Javascript 源码从左往右被扫描并转换成一系列由 token 、控制字符、行终止符、注释和空白字符组成的输入元素。空白字符指的是空格、制表符和换行符等。

注释

注释用来在源码中增加提示、笔记、建议、警告等信息,可以帮助阅读和理解源码。在调试时,可以用来将一段代码屏蔽掉,防止其运行。

Javascript 注释的语法和 C++ 或许多其他语言类似:

// 单行注释

/* 多行
   注释
*/


声明

JavaScript有三种声明方式。

  • var 声明一个变量,可选初始化一个值。
  • let 声明一个块作用域的局部变量,可选初始化一个值。
  • const 声明一个块作用域的只读常量。

数据类型的转换

JavaScript是一种动态类型语言(dynamically typed language)。这意味着你在声明变量时可以不必指定数据类型,而数据类型会在代码执行时会根据需要自动转换。

变量与常量

了解更多 >> MDN文档:JavaScript 指南 - 语法和数据类型 MDN文档:JavaScript 第一步 - 变量


变量名

变量用于存储值,通过变量名引用。变量名又叫做标识符,在JavaScript中,标识符只能包含字母数字或下划线_或美元符号$,且不能以数字开头。

合法的标识符示例:Number_hits,temp99,$credit 和 _name。

声明变量

声明变量也叫创建变量,使用关键词 var 和 let 。其中 var 可以用来声明局部变量和全局变量,let 用来声明一个块作用域的局部变量。可以在声明变量时就为变量赋值。

var x=42;

let y;
y=13;

变量如果没有赋初始值,则其值为 undefined 。如果访问一个未声明的变量会导致抛出一个引用错误(ReferenceError)异常

变量的作用域

在函数之外声明的变量,叫做全局变量,因为它可被当前文档中的任何其他代码所访问。在函数内部声明的变量,叫做局部变量,因为它只能在当前函数的内部访问。

在ECMAScript 6标准之前,Javascript没有块作用域。在一个块中引入的变量的作用域是包含函数或脚本,并且设置它们的效果会延续到块之外。换句话说,块语句不定义范围。从 ECMAScript 6开始,使用 let 变量和const 常量是块作用域的。

常量

你可以用关键字 const 创建一个只读的常量。常量标识符的命名规则和变量相同:只能包含字母数字或下划线_或美元符号$,且不能以数字开头。

const PI = 3.14;

常量不可以通过重新赋值改变其值,也不可以在代码运行时重新声明。它必须被初始化为某个值。然而,对象属性被赋值为常量是不受保护的,同样的,数组的被定义为常量也是不受保护的

数据类型

ECMAScript 标准定义了8种数据类型:

类型 中文名称 描述 示例
Boolean 布尔型 有2个值分别是:true 和 false true
Number 数字 整数或浮点数 42
3.14159
BigInt 任意精度的整数,安全地存储和操作大整数
String 字符串 文本型的数据,可以使用单引号或双引号创建,也可以使用字符串对象String创建 'foo'
"bar"
null
undefined 未定义
Symbol 代表 一种实例是唯一且不可改变的数据类型。 ( 在 ECMAScript 6 中新添加的类型)
Object 对象

了解更多 >> MDN文档:JavaScript 指南 - 数据结构与类型


流程控制

JavaScript 提供一套灵活的语句集,特别是控制流语句,你可以用它在你的应用程序中实现大量的交互性功能。

了解更多 >> MDN文档:JavaScript 指南 - 流程控制与错误处理 MDN文档:JavaScript 指南 - 循环与迭代


if...else 条件判断

条件判断语句指的是根据指定的条件所返回的结果(真或假或其它预定义的),来执行特定的语句。当一个逻辑条件为真,用if语句执行一个语句。当这个条件为假,使用可选择的 else 从句来执行这个语句。其中语句else是可选。if 语句如下所示:

if (条件) {
  当条件为真的时候,执行的语句;
} else {
  当条件为假的时候,执行的语句;
}

你也可以组合语句通过使用 else if 来测试连续多种条件判断。按顺序来执行条件判断,当某个条件为真执行该部分语句或者执行else语句就退出该if语句。就像下面一样:

if (条件1) {
  当条件1为真的时候,执行的语句;
}else if (条件2) {
  当条件1为真的时候,执行的语句;
}else if (条件n) {
  当条件1为真的时候,执行的语句;
}else {
  上述条件都为假时,执行的语句;
}

下面这些值在条件中将被计算出假(false) :

  • false
  • undefined
  • null
  • 0
  • NaN
  • 空字符串("")

当传递给条件语句所有其他的值,包括所有对象会被计算为真 。


switch 条件判断

switch 语句允许一个程序求一个表达式的值并且尝试去匹配表达式的值到一个 case 标签。如果匹配成功,这个程序执行相关的语句。如果都匹配不到,则执行default语句。default 语句通常出现在switch语句里的最后面,当然这不是必须的。 switch 语句如下所示:

switch (表达式的值) {
   case 值1:
      表达式的值与值1相等时,执行的语句;
      break;
   case 值2:
      表达式的值与值2相等时,执行的语句;
      break;
   case 值n:
      表达式的值与值n相等时,执行的语句;
      break;
   default:
      表达式的值与上述值都不相等时,执行的语句;
      break;
}

break 语句是可选的,与每个 case 语句相关联,用于在匹配的语句被执行后程序可以跳出 switch 语句。 如果break不添加,则程序将继续执行switch语句中的下一条语句。

for 循环

for 循环会一直重复执行,直到指定的循环条件为 false。 JavaScript 的 for 循环,和 Java、C 的 for 循环,是很相似的。一个 for 语句是这个样子的:

for ([initialExpression]; [condition]; [incrementExpression])
  statement

当一个 for 循环执行的时候,会发生以下过程:

  1. 如果有初始化表达式 initialExpression,它将被执行。这个表达式通常会初始化一个或多个循环计数器,但语法上是允许一个任意复杂度的表达式的。这个表达式也可以声明变量。
  2. 计算 condition 表达式的值。如果 condition 的值是 true,循环中的语句会被执行。如果 condition 的值是 false,for 循环终止。如果 condition 表达式整个都被省略掉了,condition的值会被认为是true。
  3. 循环中的 statement 被执行。如果需要执行多条语句,可以使用块{ ... }来包裹这些语句。
  4. 如果有更新表达式 incrementExpression,执行更新表达式。
  5. 回到步骤 2。

一个for循环例子如下

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

for..in 循环

for...in 语句循环一个指定的变量来循环一个对象所有可枚举的属性。JavaScript 会为每一个不同的属性执行指定的语句。

for (variable in object) {
  statements
}

示例:

let arr = [3, 5, 7];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // 输出 "0", "1", "2", "foo"
}

虽然可以使用 for...in 来迭代数组,但是它返回的东西除了数字索引外,还有可能是你自定义的属性名字。因此还是用带有数字索引的传统的 for 循环来迭代一个数组比较好,因为,如果你想改变数组对象,比如添加属性或者方法,for...in 语句迭代的是自定义的属性,而不是数组的元素。

for..of 循环

for...of 语句在可迭代对象(包括Array、Map、Set、arguments 等等)上创建了一个循环,对值的每一个独特属性调用一次迭代。

for (variable in object) {
  statements
}

示例:

let arr = [3, 5, 7];
arr.foo = "hello";

for (let i of arr) {
   console.log(i); // 输出 "3", "5", "7"
}

while 循环

while 语句只要指定的条件的值为真(true)就会一直执行它的语句块。while语句先判断条件真假,当条件为真执行一次需要重复执行的语句,再继续循环执行判断,当条件为假时,退出wile语句。一个 while 语句看起来像这样:

while (条件){
  需要重复执行的语句;
}

do...while 循环

do...while 语句一直重复直到指定的条件的值为假(false)。do...while语句是先执行一次需要重复执行的语句,再判断条件,当为真则继续循环执行判断,单条件为假时,退出do...while 语句。 一个 do...while语句看起来像这样:

do {
  需要重复执行的语句;
} while (条件);

label 标识符

label 语句提供了一个让你在程序中其他位置引用它的标识符。例如,你可以用 label 标识一个循环, 然后使用 break 或者 continue 来指出程序是否该停止循环还是继续循环。一个 label 语句看起来像这样:

label:
   标识的语句(块);

label可以是任何的非JavaScript的保留字,后面紧跟的一个语句(块)就是标识的语句(块)。

break 和 continue

break 语句用来终止循环,switch语句, 或者是链接到的 label 语句。break 语句的语法看起来像这样:

break [label];

label标识符可以选的:

  • 当不带label标识符时,表示终止当前的循环或switch语句。
  • 带label标识符时,表示终止该标识符标识的语句(块)。

示例如:

var num = 0;
outPoint:
for (var i = 0 ; i < 10 ; i++){
  for (var j = 0 ; j < 10 ; j++){
    if( i == 5 && j == 5 ){
      break outPoint; // 在 i = 5,j = 5 时,跳出所有循环,
                      // 接下来会执行alert(num);语句
    }
    num++;
  }
}

alert(num); // 输出 55

continue 语句用来用来继续执行(跳过代码块的剩余部分并进入下一轮)循环,switch语句, 或者是链接到的 label 语句。continue 语句的语法看起来像这样:

continue [label];

label标识符可以选的:

  • 当不带label标识符时,表示继续执行(跳过代码块的剩余部分并进入下一轮)循环或switch语句。
  • 带label标识符时,表示续执行(跳过代码块的剩余部分并进入下一轮)该标识符标识的语句(块)。



错误处理

了解更多 >> MDN文档:JavaScript 指南 - 流程控制与错误处理


异常类型

抛出异常 throw

异常处理 try...catch

Error 对象

函数

一般来说,一个函数是可以通过外部代码调用的一个“子程序”(或在递归的情况下由内部函数调用)。像程序本身一样,一个函数由称为函数体的一系列语句组成。值可以传递给一个函数,函数将返回一个值。

在 JavaScript中,函数是头等(first-class)对象,因为它们可以像任何其他对象一样具有属性和方法。它们与其他对象的区别在于函数可以被调用。简而言之,它们是Function对象。

了解更多 >> MDN文档:JavaScript 指南 - 函数 MDN文档:JavaScript 参考 - 函数


定义函数

定义函数有多种方法:

函数语句

可以使用函数语句来定义一个函数,

function name([param,[, param,[..., param]]]) {
   [statements]
}

例如,以下的代码定义了一个简单的square函数:

function square(number) {
  return number * number;
}

函数表达式

函数表达式和函数声明非常相似,它们甚至有相同的语法。一个函数表达式可能是一个更大的表达式的一部分。可以定义函数“名字”(例如可以在调用堆栈时使用)或者使用“匿名”函数。函数表达式不会提升,所以不能在定义之前调用。

let function_expression = function [name]([param1[, param2[, ..., paramN]]]) {
   statements
};

下面是匿名函数的一个例子(函数没有名字):

var myFunction = function() {
    // statements
}

了解更多 >> MDN文档:JavaScript 参考 - 函数表达式


函数生成器语句

function* 这种声明方式(function关键字后跟一个星号)会定义一个生成器函数 (generator function),它返回一个 Generator 对象。

function* name([param,[, param,[..., param]]]) {
   [statements]
}

示例:

function* gen(i) {
  yield i;
  yield i + 10;
}

了解更多 >> MDN文档:JavaScript 参考 - function*


函数生成器表达式

箭头函数表达式

箭头函数表达式的语法比函数表达式更简洁,并且没有自己的this,arguments,super或new.target。箭头函数表达式更适用于那些本来需要匿名函数的地方,并且它不能用作构造函数。

(param1, param2, …, paramN) => { statements } 
(param1, param2, …, paramN) => expression  //相当于:(param1, param2, …, paramN) =>{ return expression; }

// 当只有一个参数时,圆括号是可选的:
(singleParam) => { statements }
singleParam => { statements }

// 没有参数的函数应该写成一对圆括号。
() => { statements }

了解更多 >> MDN文档:JavaScript 参考 - 箭头函数


函数参数

调用函数

函数作用域

闭包

对象

在 JavaScript 中,大多数事物都是对象, 从作为核心功能的字符串和数组,到建立在 JavaScript 之上的浏览器 API 。对象是一个包含相关数据和方法的集合(通常由一些变量和函数组成,我们称之为对象里面的属性和方法)。

了解更多 >> MDN文档:JavaScript 对象


资源

官网

相关网站

参考文献