网道JavaScript教程 笔记

377 阅读17分钟

文档地址:wangdoc.com/javascript/…

JavaScript 的核心语法包括两部分:

  • 基本的语法构造(比如操作符、控制结构、语句)
  • 标准库(就是一系列具有各种功能的对象比如ArrayDateMath等) 除此之外,各种宿主环境提供额外的 API(即只能在该环境使用的接口),以便 JavaScript 调用。
    以浏览器为例,它提供的额外 API 可以分成三大类:
  • 浏览器控制类:操作浏览器
  • DOM 类:操作网页的各种元素
  • Web 类:实现互联网的各种功能

JavaScript 的性能优势:灵活的语法,表达力强;支持编译运行;采用事件驱动(event-driven)和非阻塞式(non-blocking)设计。

发展史

ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现。在日常场合,这两个词是可以互换的。ECMAScript 只用来标准化 JavaScript 这种语言的基本语法结构。
2009年,Node.js 项目诞生,创始人为 Ryan Dahl,它标志着 JavaScript 可以用于服务器端编程,从此网站的前端和后端可以使用同一种语言开发。并且,Node.js 可以承受很大的并发流量,使得开发某些互联网大规模的实时应用变得容易。
2010年,三个重要的项目诞生,分别是 NPM、BackboneJS 和 RequireJS,标志着 JavaScript 进入模块化开发的时代。
2012年,微软发布 TypeScript 语言。该语言被设计成 JavaScript 的超集,这意味着所有 JavaScript 程序,都可以不经修改地在 TypeScript 中运行。同时,TypeScript 添加了很多新的语法特性,主要目的是为了开发大型程序,然后还可以被编译成 JavaScript 运行。
2015年5月,Node 模块管理器 NPM 超越 CPAN,标志着 JavaScript 成为世界上软件模块最多的语言。
2016年6月,《ECMAScript 2016 标准》发布。与前一年发布的版本相比,它只增加了两个较小的特性。
2017年6月,《ECMAScript 2017 标准》发布,正式引入了 async 函数,使得异步操作的写法出现了根本的变化 2017年11月,所有主流浏览器全部支持 WebAssembly,这意味着任何语言都可以编译成 JavaScript,在浏览器运行。

基本语法

变量提升

JavaScript 引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,这就叫做变量提升(hoisting)。

标签(label)

JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置。标签通常与break语句和continue语句配合使用,跳出特定的循环。标签也可以用于跳出代码块。

数据类型概述

JavaScript 的数据类型,共有六种。(ES6 又新增了第七种 Symbol 类型的值,本教程不涉及。)

  • 数值(number)
  • 字符串(string)
  • 布尔值(boolean)
  • undefined
  • null
  • 对象(object) 数值、字符串、布尔值这三种类型,合称为原始类型(primitive type)的值。对象则称为合成类型(complex type)的值。

对象是最复杂的数据类型,又可以分成三个子类型。

  • 狭义的对象(object)
  • 数组(array)
  • 函数(function)

JavaScript 有三种方法,可以确定一个值到底是什么类型。

  • typeof运算符,返回一个值的数据类型,数值、字符串、布尔值分别返回numberstringboolean
  • instanceof运算符,可以区分数组和对象
  • Object.prototype.toString方法

null 和 undefined

区别:null是一个表示“空”的对象,转为数值时为0undefined是一个表示"此处无定义"的原始值,转为数值时为NaN

布尔值

布尔值代表“真”和“假”两个状态。“真”用关键字true表示,“假”用关键字false表示。 除了下面六个值被转为false,其他值都视为true。注意,空数组([])和空对象({})对应的布尔值,都是true

  • undefined
  • null
  • false
  • 0
  • NaN
  • ""''(空字符串) 布尔值往往用于程序流程的控制。

数值

整数和浮点数

JavaScript 内部,所有数字都是以64位浮点数形式储存,即使整数也是如此。所以,11.0是相同的,是同一个数。某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算。

数值精度

精度最多只能到53个二进制位,即-2^53到2^53,9007199254740996

数值范围

2^1024到2^-1023(开区间)

NaN是 JavaScript 的特殊值,表示“非数字”(Not a Number)。NaN不等于任何值,包括它本身。
Infinity表示“无穷”,用来表示两种场景。一种是一个正的数值太大,或一个负的数值太小,无法表示;另一种是非0数值除以0,得到InfinityInfinity有正负之分,Infinity表示正的无穷,-Infinity表示负的无穷。Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)。

与数值相关的全局方法

parseInt方法用于将字符串转为整数。返回一个十进制整数,或者是NaN
parseFloat方法用于将一个字符串转为浮点数
isNaN方法可以用来判断一个值是否为NaN
isFinite方法返回一个布尔值,表示某个值是否为正常的数值。

字符串

字符串就是零个或多个排在一起的字符,放在单引号或双引号之中。 反斜杠(\),用来表示一些特殊字符,所以又称为转义符。

  • \n :换行符(\u000A
  • \r :回车键(\u000D

字符集

JavaScript 使用 Unicode 字符集。JavaScript 引擎内部,所有字符都用 Unicode 表示。 解析代码的时候,JavaScript 会自动识别一个字符是字面形式表示,还是 Unicode 形式表示。输出给用户的时候,所有字符都会转成字面形式。每个字符在 JavaScript 内部都是以16位(即2个字节)的 UTF-16 格式储存。JavaScript 的单位字符长度固定为16位长度,即2个字节。,由于历史原因,只支持两字节的字符,不支持四字节的字符。也就是说,JavaScript 返回的字符串长度可能是不正确的。

Base64 转码

Base64 就是一种编码方法,可以将任意值转成 0~9、A~Z、a-z、+/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。
JavaScript 原生提供两个 Base64 相关的方法。

  • btoa():任意值转为 Base64 编码
  • atob():Base64 编码转为原来的值 要将非 ASCII 码字符转为 Base64 编码,必须中间插入一个转码环节(encodeURIComponent),再使用这两个方法。

对象

对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。如果属性的值还是一个对象,就形成了链式引用。

对象的引用

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。

表达式还是语句

{}解释为代码块,()解释为对象。,圆括号的里面,只能是表达式。

属性的操作

属性读取或赋值:有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。
查看属性:查看一个对象本身的所有属性,可以使用Object.keys方法。
删除属性:delete命令用于删除对象的属性,删除成功后返回true。属性存在,且不得删除时,delete命令会返回false。只能删除对象本身的属性,无法删除继承的属性。
属性是否存在:in,hasOwnProperty
遍历属性:for...in循环用来遍历\

函数

JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。函数参数如果是原始类型的值(数值、字符串、布尔值),传递方式是传值传递(passes by value)。如果函数参数是复合类型的值(数组、对象、其他函数),传递方式是传址传递(pass by reference)。也就是说,传入函数的原始值的地址,因此在函数内部修改参数,将会影响到原始值。

闭包

能够读取其他函数内部变量的函数。简单理解成“定义在一个函数内部的函数”。在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
闭包的最大用处有两个,一个是可以读取外层函数内部的变量,另一个就是让这些变量始终保持在内存中,即闭包可以使得它诞生环境一直存在。

function createIncrementor(start) {
  return function () {
    return start++;
  };
}

var inc = createIncrementor(5);

inc() // 5
inc() // 6
inc() // 7

为什么闭包能够返回外层函数的内部变量?原因是闭包(上例的inc)用到了外层变量(start),导致外层函数(createIncrementor)不能从内存释放。只要闭包没有被垃圾回收机制清除,外层函数提供的运行环境也不会被清除,它的内部变量就始终保存着当前值,供闭包读取。
闭包的另一个用处,是封装对象的私有属性和私有方法。

立即调用的函数表达式

圆括号()跟在函数名之后,表示调用该函数。

(function(){ /* code */ }());
// 或者
(function(){ /* code */ })();

通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

eval 命令

接受一个字符串作为参数,并将这个字符串当作语句执行。

数组

本质上,数组属于一种特殊的对象。typeof运算符会返回数组的类型是object。数组的length属性,返回数组的成员数量。JavaScript 使用一个32位整数,保存数组的元素个数,数组成员最多只有 4294967295 个(232 - 1)个,length属性的最大值就是 4294967295。 清空数组的一个有效方法,就是将length属性设为0。

in 运算符

检查某个键名是否存在的运算符in,适用于对象,也适用于数组

for...in 循环和数组的遍历

for...in不仅会遍历数组所有的数字键,还会遍历非数字键。数组的forEach方法,也可以用来遍历数组

数组的空位

使用delete命令删除一个数组成员,会形成空位,并且不会影响length属性。

类似数组的对象

数组的slice方法可以将“类似数组的对象”变成真正的数组。通过call()把数组的方法放到对象上面。

运算符

JavaScript 共提供10个算术运算符,用来完成基本的算术运算。

  • 加法运算符x + y
  • 减法运算符: x - y
  • 乘法运算符: x * y
  • 除法运算符x / y
  • 指数运算符x ** y
  • 余数运算符x % y
  • 自增运算符++x 或者 x++
  • 自减运算符--x 或者 x--
  • 数值运算符: +x
  • 负数值运算符-x JavaScript 一共提供了8个比较运算符。
  • > 大于运算符
  • < 小于运算符
  • <= 小于或等于运算符
  • >= 大于或等于运算符
  • == 相等运算符
  • === 严格相等运算符
  • != 不相等运算符
  • !== 严格不相等运算符 布尔运算符用于将表达式转为布尔值,一共包含四个运算符。
  • 取反运算符:!
  • 且运算符:&&
  • 或运算符:||
  • 三元运算符:?: 二进制位运算符用于直接对二进制位进行计算,一共有7个。
  • 二进制或运算符(or):符号为|,表示若两个二进制位都为0,则结果为0,否则为1
  • 二进制与运算符(and):符号为&,表示若两个二进制位都为1,则结果为1,否则为0。
  • 二进制否运算符(not):符号为~,表示对一个二进制位取反。
  • 异或运算符(xor):符号为^,表示若两个二进制位不相同,则结果为1,否则为0。
  • 左移运算符(left shift):符号为<<,详见下文解释。
  • 右移运算符(right shift):符号为>>,详见下文解释。
  • 头部补零的右移运算符(zero filled right shift):符号为>>>,详见下文解释。

其他运算符,运算顺序

void运算符的作用是执行一个表达式,然后不返回任何值,或者说返回undefined。 逗号运算符用于对两个表达式求值,并返回后一个表达式的值。逗号运算符的一个用途是,在返回一个值之前,进行一些辅助操作。

运算顺序:
优先级:圆括号(())可以用来提高运算的优先级.JavaScript 语言的大多数运算符是“左结合”

语法专题

数据类型的转换

强制转换主要指使用Number()String()Boolean()三个函数,手动将各种类型的值,分别转换成数字、字符串或者布尔值。

错误处理机制

Error 实例对象

JavaScript 原生提供Error构造函数,所有抛出的错误都是这个构造函数的实例。

  • message:错误提示信息
  • name:错误名称(非标准属性)
  • stack:错误的堆栈(非标准属性)

原生错误类型

SyntaxError对象是解析代码时发生的语法错误。
ReferenceError对象是引用一个不存在的变量时发生的错误。
RangeError对象是一个值超出有效范围时发生的错误。主要有几种情况,一是数组长度为负数,二是Number对象的方法参数超出范围,以及函数堆栈超过最大值。
TypeError对象是变量或参数不是预期类型时发生的错误。
eval函数没有被正确执行时,会抛出EvalError错误。该错误类型已经不再使用了,只是为了保证与以前代码兼容,才继续保留。

throw语句的作用是手动中断程序执行,抛出一个错误。throw也可以抛出自定义错误。对于 JavaScript 引擎来说,遇到throw语句,程序就中止了。引擎会接收到throw抛出的信息,可能是一个错误实例,也可能是其他类型的值。

try...catch 结构

一旦发生错误,程序就中止执行了。JavaScript 提供了try...catch结构,允许对错误进行处理,选择是否往下执行。catch代码块捕获错误之后,程序不会中断,会按照正常流程继续执行下去。为了捕捉不同类型的错误,catch代码块之中可以加入判断语句。try...catch结构允许在最后添加一个finally代码块,表示不管是否出现错误,都必需在最后运行的语句。

编程风格

JavaScript 有两个表示相等的运算符:“相等”(==)和“严格相等”(===)。相等运算符会自动转换变量类型,造成很多意想不到的情况。因此,建议不要使用相等运算符(==),只使用严格相等运算符(===)。
建议switch...case结构可以用对象结构代替。

console 对象与控制台

console的常见用途有两个。

  • 调试程序,显示网页代码运行时的错误信息。
  • 提供了一个命令行接口,用来与网页代码互动。

console.infoconsole.log方法的别名,用法完全一样。只不过console.info方法会在输出信息的前面,加上一个蓝色图标。
console.debug方法与console.log方法类似,会在控制台输出调试信息。但是,默认情况下,console.debug输出的信息不会显示,只有在打开显示级别在verbose的情况下,才会显示。
console.warn方法输出信息时,在最前面加一个黄色三角,表示警告。
console.error方法输出信息时,在最前面加一个红色的叉,表示出错。log方法是写入标准输出(stdout),warn方法和error方法是写入标准错误(stderr)。
console.table方法可以将某些复合类型的数据转为表格显示。
console.count方法用于计数,输出它被调用了多少次。
console.dir方法用来对一个对象进行检查(inspect),并以易于阅读和打印的格式显示。
console.dirxml方法主要用于以目录树的形式,显示 DOM 节点。如果参数不是 DOM 节点,而是普通的 JavaScript 对象,console.dirxml等同于console.dir
console.assert方法主要用于程序运行过程中,进行条件判断,如果不满足条件,就显示一个错误,但不会中断程序执行。
console.time方法表示计时开始,console.timeEnd方法表示计时结束。用于计时,可以算出一个操作所花费的准确时间。它们的参数是计时器的名称。调用timeEnd方法之后,控制台会显示“计时器名称: 所耗费的时间”。
console.groupconsole.groupEnd这两个方法用于将显示的信息分组。它只在输出大量信息时有用,分在一组的信息,可以用鼠标折叠/展开。
console.groupCollapsed方法与console.group方法很类似,唯一的区别是该组的内容,在第一次显示时是收起的(collapsed),而不是展开的。 console.trace方法显示当前执行的代码在堆栈中的调用路径。
console.clear方法用于清除当前控制台的所有输出,将光标回置到第一行。如果用户选中了控制台的“Preserve log”选项,console.clear方法将不起作用。

控制台命令行 API

浏览器控制台中,除了使用console对象,还可以使用一些控制台自带的命令行方法。

debugger 语句

debugger语句主要用于除错,作用是设置断点。如果有正在运行的除错工具,程序运行到debugger语句时会自动停下。如果没有除错工具,debugger语句不会产生任何结果,

标准库

面向对象编程

对象是单个实物的抽象。对象是一个容器,封装了属性(property)和方法(method

构造函数的特点有两个。

  • 函数体内部使用了this关键字,代表了所要生成的对象实例。
  • 生成对象的时候,必须使用new命令。 new命令的作用,就是执行构造函数,返回一个实例对象。

new 命令的原理

使用new命令时,它后面的函数依次执行下面的步骤。

  1. 创建一个空对象,作为将要返回的对象实例。
  2. 将这个空对象的原型,指向构造函数的prototype属性。
  3. 将这个空对象赋值给函数内部的this关键字。
  4. 开始执行构造函数内部的代码。

异步操作

Promise 对象

Promise 对象是 JavaScript 的异步操作解决方案,为异步操作提供统一接口。