JavaScript
JavaScript(JS)是一种具有函数优先特性的轻量级、解释型或者说即时编译型的编程语言。虽然作为 Web 页面中的脚本语言被人所熟知,但是它也被用到了很多非浏览器环境中,例如 Node.js、Apache CouchDB、Adobe Acrobat 等。进一步说,JavaScript 是一种基于原型、多范式、单线程的动态语言,并且支持面向对象、命令式和声明式(如函数式编程)风格。
JavaScript 内置了一些对象的标准库,比如数组(Array),日期(Date),数学(Math)和一套核心语句,包括运算符、流程控制符以及声明方式等。JavaScript 的核心部分可以通过添加对象来扩展语言以适应不同用途;例如:
- 客户端的 JavaScript 通过提供对象,控制浏览器及其文档对象模型(DOM),来扩展语言核心。例如:客户端的拓展代码允许应用程序将元素放在某个 HTML 表单中,并且支持响应用户事件,比如鼠标点击、表单提交和页面导航。
- 服务端的 JavaScript 则通过提供有关在服务器上运行 JavaScript 的对象来可扩展语言核心。例如:服务端版本直接支持应用和数据库通信,提供应用不同调用间的信息连续性,或者在服务器上执行文件操作。
这意味着,在浏览器中,JavaScript 可以改变网页(DOM)的外观与样式。同样地,在服务器上,Node.js 中的 JavaScript 可以对浏览器上编写的代码发出的客户端请求做出响应。
基本概念
程序
JavaScript 程序是 JavaScript 语言中用户编写的代码。
- JavaScript 程序是单个语句的集合。
- JavaScript 程序是单个变量的集合。
语句
JavaScript 程序是由一条条的语句组成的,每条语句就是一个命令。
- JavaScript 语句是 JavaScript 解释器对代码的文本。
- JavaScript 语句可以是单个语句也可以是多行语句。
注释
JavaScript 注释用于解释 JavaScript 代码,提高代码的可读性。
- 单行注释以两个正斜杠开头:// 这是单行注释。
- 多行注释以/_ 开头,以_/结束。
// 单行注释
/* 这是一个更长的,
多行注释
*/
/* 然而,你不能,/* 嵌套注释 */ 语法错误 */数据类型
最新的 ECMAScript 标准定义了 8 种数据类型:
- 七种基本数据类型:
- 布尔值(Boolean),有 2 个值分别是:true 和 false。
- null,一个表明 null 值的特殊关键字。JavaScript 是大小写敏感的,因此 null 与 Null、NULL 或变体完全不同。
- undefined,和 null 一样是一个特殊的关键字,undefined 表示变量未赋值时的属性。
- 数字(Number),整数或浮点数,例如: 42 或者 3.14159。
- 任意精度的整数(BigInt),可以安全地存储和操作大整数,甚至可以超过数字的安全整数限制。
- 字符串(String),字符串是一串表示文本值的字符序列,例如:"Howdy"。
- 代表(Symbol,在 ECMAScript 6 中新添加的类型)。一种实例是唯一且不可改变的数据类型。
- 以及对象(Object)。
虽然这些数据类型相对来说比较少,但是通过他们你可以在程序中开发有用的功能。对象和函数是这门语言的另外两个基本元素。你可以把对象当作存放值的一个命名容器,然后将函数当作你的程序能够执行的步骤。
变量
在应用程序中,使用变量来作为值的符号名。变量的名字又叫做标识符,其需要遵守一定的规则。
一个 JavaScript 标识符必须以字母、下划线(_)或者美元符号($)开头;后续的字符也可以是数字(0-9)。因为 JavaScript 语言是区分大小写的,所以字母可以是从“A”到“Z”的大写字母和从“a”到“z”的小写字母。
合法的标识符示例:Number_hits、temp99、$credit 和 _name。
不合法的标识符示例:99balloons、-name 和 100steaks。
声明变量
你可以用以下三种方式声明变量:
- 使用关键词 var 。例如 var x = 42。这个语法可以用来声明局部变量和全局变量。
- 直接赋值。例如 x = 42。在函数外使用这种形式赋值,会产生一个全局变量。在严格模式下会产生错误。因此你不应该使用这种方式来声明变量。
- 使用关键词 let、const。例如 let y = 13。这个语法可以用来声明块作用域的局部变量。
声明函数
一个函数定义(也称为函数声明,或函数语句)由 function 关键字,并跟随以下部分组成:
- 函数名称。
- 函数参数列表,包围在括号中并由逗号分隔。
- 定义函数的 JavaScript 语句,用大括号括起来,{ /_ … _/ }。
function myFunction(a, b) {
return a * b;
}对象
JavaScript 的设计是一个简单的基于对象的范式。一个对象就是一系列属性的集合,一个属性包含一个名和一个值。一个属性的值可以是函数,这种情况下属性也被称为方法。除了浏览器里面预定义的那些对象之外,你也可以定义你自己的对象。
运算符
JavaScript 运算符用于执行数据运算,例如:加、减、乘、除等。
- 算术运算符:+ - * / % ++ --
- 比较运算符:> < >= <= == === != !==
- 逻辑运算符:&& || !
- 位运算符:& | ^ ~ << >> >>>
- 赋值运算符:= += -= *= /= %= <<= >>= >>>=
- 字符串运算符:+
- 条件运算符:? :
- 逗号运算符:,
字面量
在 JavaScript 中,你可以使用各种字面量。这些字面量是脚本中按字面意思给出的固定的值,而不是变量。JS 有多种类型的字面量:
- 数组字面量:数组字面值是一个封闭在方括号对 ([]) 中的包含有零个或多个表达式的列表,其中每个表达式代表数组的一个元素。当你使用数组字面值创建一个数组时,该数组将会以指定的值作为其元素进行初始化,而其长度被设定为元素的个数。若在顶层(全局)脚本里用字面值创建数组,JavaScript 语言将会在每次对包含该数组字面值的表达式求值时解释该数组。另一方面,在函数中使用的数组,将在每次调用函数时都会被创建一次。
- 布尔字面量:布尔类型有两种字面量:true 和 false。不要混淆作为布尔对象的真和假与布尔类型的原始值 true 和 false。布尔对象是原始布尔数据类型的一个包装器。
- 数字字面量:JavaScript 数字字面量包括多种基数的整数字面量和以 10 为基数的浮点数字面量。值得一提的是,语言标准要求数字字面量必须是无符号的。但是像-123.4 这样的代码片段还是没有问题的,会被解释为一元操作符-应用于数字字面量 123.4
- 对象字面量:对象字面值是封闭在花括号对({})中的一个对象的零个或多个“属性名—值”对的(元素)列表。对象属性名字可以是任意字符串,包括空串。如果对象属性名字不是合法的 javascript 标识符,它必须用引号包裹。属性的名字不合法,那么便不能用点(.)访问属性值。
- RegExp 字面量:一个正则表达式是字符被斜线(译注:正斜杠“/”)围成的表达式。
- 字符串字面量:字符串字面量是由双引号(")对或单引号(')括起来的零个或多个字符。字符串被限定在同种引号之间;也即,必须是成对单引号或成对双引号。
流程控制
JavaScript 流程控制语句用于控制程序的执行路径。
- if 语句:根据条件是否为真来决定是否执行代码块。
- switch 语句:根据多个分支选择一个执行。
- for 循环:重复执行一段代码直到条件不满足为止。
- while 循环:只要条件为真就执行一段代码。
- do...while 循环:先执行一次,然后判断条件是否为真。
- break 语句:跳出循环。
- continue 语句:跳出当前循环,继续执行下一次循环。
错误处理
JavaScript 错误处理机制包括:
- try...catch 语句:用于捕获异常,并执行错误处理代码。
- throw 语句:抛出异常,允许你创建自定义的错误。
- finally 语句:无论是否发生异常,finally 语句都会执行。
函数
函数是 JavaScript 中的基本组件之一。JavaScript 中的函数类似于过程——一组执行任务或计算值的语句。但要成为函数,这个过程应该接受输入并返回与输入存在某些明显关系的输出。要使用一个函数,你必须将其定义在你希望调用它的作用域内。
函数表达式
函数表达式(function expression)非常类似于函数声明(function statement)(详情查看函数声明),并且两者拥有几乎相同的语法。函数表达式与函数声明的最主要区别是函数名称(function name),在函数表达式中可省略它,从而创建匿名函数(anonymous functions)。一个函数表达式可以被用作一个 IIFE(Immediately Invoked Function Expression,即时调用的函数表达式),它一旦定义就运行。
let function_expression = function [name]([param1[, param2[, ..., paramN]]]) {
statements
};调用函数
定义的函数并不会自动执行它。定义了函数仅仅是赋予函数以名称并明确函数被调用时该做些什么。
调用函数才会以给定的参数真正执行这些动作。
函数一定要处于调用它们的作用域中,但是函数的声明可以被提升(出现在调用语句之后)。函数声明的范围是声明它的函数(或者,如果它是在顶层声明的,则为整个程序)之内。
参数
参数本质上是按值传递给函数的——因此,即使函数体的代码为传递给函数的参数赋了新值,这个改变也不会反映到全局或调用该函数的代码中。
函数作用域
函数作用域是指函数内声明的变量和函数的可见性范围。JavaScript 中的函数作用域是词法作用域,即函数的作用域由函数定义时确定,而不是执行时确定。
基本特性
闭包
闭包是一个函数及其相关引用环境组合而成的实体。闭包使得函数可以访问到其外部作用域的变量。
原型
在 JavaScript 中,每个对象都有一个原型(prototype)对象。对象原型对象和构造函数(constructor)属性指向另一个对象。该对象称为原型对象。
原型链
每个对象(object)都有一个私有属性指向另一个名为原型(prototype)的对象。原型对象也有一个自己的原型,层层向上直到一个对象的原型为 null。根据定义,null 没有原型,并作为这个原型链(prototype chain)中的最后一个环节。可以改变原型链中的任何成员,甚至可以在运行时换出原型,因此 JavaScript 中不存在静态分派的概念。
JavaScript 对象是动态的属性(指其自有属性)“包”。JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。
继承
JavaScript 的继承是一种对象基于其他对象的属性和方法来构建新对象的机制。继承主要通过原型链(prototype chain)来实现。
属性的可枚举性和所有权
JavaScript 对象的属性分为两种:自有属性和继承属性。自有属性是直接在对象上定义的属性,而继承属性则是通过原型链从其他对象继承而来的属性。
可枚举属性是指那些内部“可枚举”标志设置为 true 的属性,对于通过直接的赋值和属性初始化的属性,该标识值默认为即为 true,对于通过 Object.defineProperty 等定义的属性,该标识值默认为 false。可枚举的属性可以通过 for...in 循环进行遍历(除非该属性名是一个 Symbol)。属性的所有权是通过判断该属性是否直接属于某个对象决定的,而不是通过原型链继承的。一个对象的所有的属性可以一次性的获取到。
属性特性
JavaScript 属性有四个特性:可配置性(Configurability)、可枚举性和可写性(Enumerable and Writable)和值(Value)。
JavaScript 类型化数组
JavaScript 类型化数组是一种类似数组的对象,并提供了一种用于在内存缓冲中访问原始二进制数据的机制。类型化数组由以下几种形式组成:
- Int8Array
- Uint8Array
- Uint8ClampedArray
- Int16Array
- Uint16Array
- Int32Array
- Uint32Array
- Float32Array
- Float64Array
迭代器
在 JavaScript 中,迭代器是一个对象,它定义一个序列,并在终止时可能附带一个返回值。
更具体地说,迭代器是通过使用 next() 方法实现了迭代器协议的任何一个对象,该方法返回具有两个属性的对象:
value 迭代序列的下一个值。
done 如果已经迭代到序列中的最后一个值,则它为 true。如果 value 和 done 一起出现,则它就是迭代器的返回值。
一旦创建,迭代器对象可以通过重复调用 next() 显式地迭代。迭代一个迭代器被称为消耗了这个迭代器,因为它通常只能执行一次:在产生终值后,对 next() 的额外调用应该继续返回 {done:true}。
异步编程
JavaScript 是一种单线程的编程语言,但它可以异步执行任务。异步编程是 JavaScript 的一个重要特性,它允许在等待外部事件时继续执行代码。
事件循环
JavaScript 的事件循环机制使得异步操作得以实现。事件循环是一个程序执行模型,它将任务分为不同的阶段,并按照顺序依次执行这些任务。
优缺点
优点:
- 跨平台性:JavaScript 可以在多种平台和环境中运行,如浏览器和 Node.js。
- 灵活性:作为一种多范式语言,JavaScript 支持多种编程风格。
- 庞大的生态系统:拥有大量的库和框架,以及丰富的开发工具。
- 事件驱动和非阻塞 I/O:适合开发高并发的网络应用。
- 统一的开发语言:前端和后端(Node.js)可以使用同一种语言开发。
缺点:
- 单线程限制:在浏览器中,JavaScript 的单线程模型可能导致长时间运行的操作阻塞用户界面。
- 类型系统:动态类型系统可能导致运行时错误难以发现。
- 性能问题:对于计算密集型任务,JavaScript 的性能可能不如编译型语言。
- 安全性问题:在 Web 页面中执行 JavaScript 代码可能带来安全风险,如跨站脚本攻击(XSS)。
- 内存泄漏:不当的内存管理可能导致内存泄漏。
总结
JavaScript 是一种广泛使用的编程语言,它具有跨平台、灵活性和庞大的生态系统等优点。但是,也存在单线程限制、类型系统问题、性能问题和安全性等问题。在选择使用 JavaScript 进行开发时,需要权衡其优缺点并做出明智的选择。