现在通常所说的JavaScript是制定于2009年的ES5,而经常被提及的ES6/ES2015则泛指5.1之后发布的新一代JavaScript标准。
JavaScript基础
基本语法
语句
- 语句(statement)是为了完成某任务进行的操作
- 表达式(expression)是为了得到返回值的计算式, 表达式不需要分号结尾.
变量
- 变量名区分大小写,只声明不赋值默认为undefined
- 动态类型语言,变量可以改变值类型
关键字:
- var
数据类型
- 基本数据类型:
- nubmer: 64位浮点数
- string:
- boolean: 空数组[] 和空对象{} 对应布尔true
- 合成类型、
- 对象(Object):
- Array
- function
数值
- 特殊数值: NaN(Not a Number)
- parseInt()
字符串
- 转义反斜杠\ ;
- length属性;
- Base64转换: btoa()/atob()/encodeURIComponent() 非ASCII码转换
注:约定JavaScript字符串只使用单引号,HTML属性值使用双引号
对象
键名必须是字符串,每个键名也叫属性(property),属性可以动态创建(后绑定)
对象有两种读取成员的方法:点结构(object.key)和方括号结构(object[key])
检查对象是否包含属性:
- in
- hasOwnProperty: 排除继承属性
// 如果要解释为对象,最好在大括号前加上圆括号。
// 因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象
({ foo: 123 })
注:
- 对象使用引用,基本类型值使用值拷贝
- 建议不要使用with语句,改用临时变量
函数
把函数看成一个可以执行的值.
三种函数声明方式:
- function 命令
- 函数表达式:将匿名函数/具名函数赋值给变量(结尾要加分号;)。好处:
- 可以在函数体内部调用自身
- 方便调用栈除错
- Function 构造函数:几乎不使用。最后一个参数是函数体
函数作用域: 全局变量/局部变量(即函数作用域)
参数:
- 函数体内部可以使用arguments读取/修改参数
- arguments很像数组,但它是一个对象
// arguments与数组转换
var args = Array.prototype.slice.call(arguments);
// 或者
var args = [];
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
注:
-
- JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部。
-
- 函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。
-
- 对于复合类型的函数参数,如果函数内部修改的,不是参数对象的某个属性,而是替换掉整个参数,这时不会影响到原始值。因为重新赋值后,变量会指向另一个地址。
数组
- 本质上,数组属于一种特殊的对象。
- 数组的特殊性体现在,它的键名是按次序排列的一组整数(0,1,2…)。 (JavaScript 语言规定,对象的键名一律为字符串,所以,数组的键名其实也是字符串)
- length属性不过滤空位(hole)
- 生成新数组建议直接使用数组字面量
如果一个对象的所有键名都是正整数或零,并且有length属性,那么这个对象就很像数组,语法上称为“类似数组的对象”(array-like object).
典型的“类似数组的对象”是函数的arguments对象,以及大多数 DOM 元素集,还有字符串。
// 清空数组的一个有效方法,就是将length属性设为0
var arr = [ 'a', 'b', 'c' ];
arr.length = 0;
// for...in不仅会遍历数组所有的数字键,还会遍历非数字键。不推荐使用for...in遍历数组。
// 数组的遍历可以考虑使用for循环或while循环
// 数组的forEach方法,也可以用来遍历数组
// 方式一: 数组的slice方法可以将“类似数组的对象”变成真正的数组
var arr = Array.prototype.slice.call(arrayLike);
// 方式二: 通过call()把数组的方法放到对象上面,较方式一速度更慢
Array.prototype.forEach.call(arrayLike, print);
JSON对象
约定:
- 字符串必须使用双引号表示,不能使用单引号
- 对象的键名必须放在双引号里面
- 数组或对象最后一个成员的后面,不能加逗号
静态方法:
- stringify(): 将一个值转为 JSON 字符串
- 注:对于原始类型的字符串,转换结果会带双引号
- parse():
运算符
- 非相等运算符:非字符串的比较
- 都是原始类型的值,则是先转成数值再比较
- 对象,会转为原始类型的值,再进行比较
- 严格相等运算符===: 比较它们是否为“同一个值”
- 布尔运算符
- 三元运算符:?:
var x = [2];
x > '11' // true
// 等同于 [2].valueOf().toString() > '11'
// 即 '2' > '11'
常用风格
- 行末不要省略分号,不用添加分号仅适用下列情况:
- for 和 while循环(do while有分号)
- 分支: if, switch, try
- 函数声明语句
- 避免使用全局变量
- 变量声明应放在代码块的头部
- 不要使用with语句
- 建议只使用严格相等运算符 ===
高级
待整理: Promise / async function / arrow function / module / Symbol / Class / dynamic import
'use strict'; // 开启严格模式
闭包
闭包即能够读取其他函数内部变量的函数;或者定义在一个函数内部的函数。
用处:
- 可以读取函数内部的变量
- 让这些变量始终保持在内存中。可使得内部变量记住上一次调用时的运算结果。
- 是封装对象的私有属性和私有方法
“链式作用域"结构(chain scope):子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。
注:外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大。因此不能滥用闭包,否则会造成网页的性能问题。
// 通常情况下,只对匿名函数使用这种“立即执行的函数表达式”/IIFE (Immediately-Invoked Function Expression)
// 它的目的有两个:一是不必为函数命名,避免了污染全局变量;二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
(function () {
var tmp = newData;
processData(tmp);
storeData(tmp);
}());
// 加()会被当作表达式处理,因为 JavaScript 引擎规定,如果function关键字出现在行首,一律解释成语句。
eval
eval的本质是在当前作用域之中,注入代码。由于安全风险和不利于 JavaScript 引擎优化执行速度,所以一般不推荐使用。
通常情况下,eval最常见的场合是解析 JSON 数据的字符串,不过正确的做法应该是使用原生的JSON.parse方法。
事件
推荐使用EventTarget.addEventListener的方式增加监听函数,监听函数内部的this指向触发事件的那个元素节点.
另一种方便使用的是GlobalEventHandlers的onxxxEvent事件(缺点是只能为每个事件指定一个回调函数,并且无法指定事件触发的阶段)
事件的传播阶段:
-
第一阶段:从window传导到目标节点,捕获阶段(capture phase)
-
第二阶段:目标节点上触发,目标阶段(target phase)
-
第三阶段:从目标节点传导会window对象,冒泡阶段(bubbling phase)
-
preventDefault(): 取消事件,比如表单提交
Module
- ES Modules: import
- mocha 需要高版本支持: Node.js v12.11+/v13.2+
- CommonJS: required
import {add} from './add.mjs';
import assert from 'assert';
// 使用.mjs 扩展
// 或在package.json 添加 "type": "module"
Promise
使得异步流程可以写成同步流程
DOM
DOM/Document Object Model:文档对象模型,是操作网页的接口规范.
所有DOM节点对象都继承了Node接口.
常用节点类型:
- document: 代表整个文档, window.document属性就指向这个对象.
- element: 各种网页标签/元素节点.
- attr: 网页元素的属性/键值对 name-value
浏览器模型
XHR/AJAX
XMLHttpRequest
注: AJAX 只能向同源网址(协议、域名、端口都相同)发出 HTTP 请求,如果发出跨域请求,就会报错
同源限制:实际上,同一个网域的不同端口,是可以互相读取 Cookie 的。
CORS/Cross-Origin Resource Sharing/跨源资源分享: W3C 标准,属于跨源 AJAX 请求的根本解决方法。只要服务器实现了 CORS 接口,就可以跨域通信。
Node.JS
Reference
- Arrow functions: Lambda表达式: ES6标准, (paramN) => {statements}
- Promise