JavaScript

基本语法

[0]. JavaScript原生提供的三个包装对象

  • Number
  • String
  • Boolean

Number与parseInt

parseInt:字符串转为整数,字符依次转换,遇到不能转为数字的字符,就不再进行下去,返回已经转好的部分
Number:将任意类型的值转化成数值,字符串整体转换,若不可以被解析为数值,返回NaN

1
2
3
4
/// parseInt/Number的返回值只有两种可能,一个十进制整数或NaN
parseInt('8.8a') //8  Number('8.8a')  //NaN
parseInt(''); //NaN   parseInt(null); //NaN  parseInt(undefined); //NaN  
Number('');   //0     Number(null);   //0    Number(undefined);   //NaN

Number要比parseInt严格很多。基本上只要有一个字符无法转成数值,整个字符串就会被转为NaN。

  • 第一步,调用对象自身的valueOf方法。如果返回原始类型的值,则直接对该值使用Number函数,不再进行后续步骤。
  • 第二步,如果valueOf方法返回的还是对象,则改为调用对象自身的toString方法。如果toString方法返回原始类型的值,则对该值使用Number函数,不再进行后续步骤。
  • 第三步,如果toString方法返回的是对象,就报错。

表示valueOf方法先于toString方法执行。
注:一元运算符(+)同Number()方法功能一样。

String

将任意类型的值转化成字符串。

1
2
3
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"

与Number方法基本相同,只是互换了valueOf方法和toString方法的执行顺序。

  • 先调用对象自身的toString方法。如果返回原始类型的值,则对该值使用String函数,不再进行以下步骤。
  • 如果toString方法返回的是对象,再调用原对象的valueOf方法。如果valueOf方法返回原始类型的值,则对该值使用String函数,不再进行以下步骤。
  • 如果valueOf方法返回的也是对象,就报错。

表示toString方法先于valueOf方法执行。

字符串方法总结

Boolean

将任意类型的值转为布尔值。

1
2
3
4
Boolean(false) // false
Boolean({}) // true
Boolean([]) // true
Boolean(new Boolean(false)) // true

[1]. JavaScript中三种方法确定值的类型:

  • typeof运算符
  • instanceof运算符
  • Object.prototype.toString方法
1
2
3
typeof(null) --> "object"
typeof(undefined) --> "undefined"
typeof(NaN) --> "Number"

非数值类型转换为数值类型

1
2
6 + null --> 6   // Number(null);
6 + undefined  --> NaN  // Number(undefined);

instanceof

表示对象是否为某个构造函数的实例。但,只能用于对象,不适用原始类型的值。

检查右边构造函数的原型对象(prototype),是否在左边对象的原型链上。

1
2
3
v instanceof V
// 等同于
V.prototype.isPrototypeOf(v)

利用该运算符,可以巧妙解决忘记new命令的问题

字节序

分为小端(little endian)和大端(big endian):

  • 大端字节序:高位字节在前,低位字节在后,这是人类读写数值的方法
  • 小端字节序:低位字节在前,高位字节在后

下面是判断计算机字节序的方法

1
2
3
4
5
6
// true:小端,false:大端
var littleEndian = (function() {
  var buffer = new ArrayBuffer(2);
  new DataView(buffer).setInt16(0, 256, true);  // 小端字节序写入
  return (new Int16Array(buffer))[0] === 256;
})();

通常个人PC都是小端字节序,因为计算机先处理低位字节,效率比较高。

以32位整数求值为例

1
2
3
4
/* 大端字节序 */
i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);
/* 小端字节序 */
i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

关于字节序,参见:理解字节序 - 阮一峰;  

[2]. Infinity  

Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN)
Infinity与NaN比较,总是返回false(任何值(包括NaN本身)与NaN比较,返回的都是false)

1
2
3
0 * Infinity // NaN
Infinity - Infinity // NaN
Infinity / Infinity // NaN

Infinity与null运算,等同于与0运算

Infinity与undefined运算,总是等于NaN

[3]. 布尔类型  

以下6个的布尔值为false,其余均为true 

空数组[]和空对象{}也为true。 

! 与 !!:强制转换为布尔型

  • !:类型判断,逻辑取反,可将null、undefined和空串取反为false
  • !!:类型判断,双重逻辑取反,判断变量 !!a 等效于 a!=null&&typeof(a)!=undefined&&a!=''&&a!="" 

[4]. 字符集

JavaScript使用Unicode字符集。
每个字符在JavaScript内部都是以16位(即2个字节)的UTF-16格式储存。
也就是说,JavaScript的单位字符长度固定为16位长度,即2个字节。
JavaScript无法识别四字节的字符,也就是说,JavaScript返回的字符串长度可能是不正确的。

判断一个字符由两个字节还是由四个字节组成的最简单方法:

1
2
3
function is4Bytes(c) {
  return c.codePointAt(0) > 0xFFFF;
}

[5]. Base64编码

  • 将文本中不可打印的特殊符号转成可打印的字符;
  • 以文本格式传递二进制数据;

非ASCII码字符转的Base64编码,需要转码环节

1
2
3
4
5
6
7
8
9
function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}
function b64Decode(str) {
  return decodeURIComponent(atob(str));
}
 
b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

借此,了解下 js中 encodeURIencodeURIComponent

  • 把字符串作为 URI 进行编码
  • 方法不会对 ASCII 字母和数字进行编码,也不会对这些 ASCII 标点符号进行编码: - _ . ! ~ * ' ( ) 。

主要的区别如下

  • encodeURI(URIstr): 对在 URI 中具有特殊含义的 ASCII 标点符号,不会进行转义的:;/?:@&=+$,#
  • encodeURIComponent(URIstr):对在 URI 中具有特殊含义的 ASCII 标点符号,也会进行转义的:;/?:@&=+$,#

[6]. isNaN() 与 isFinite()  

isNaN():判断一个值是否为NaN,利用NaN是唯一不等于自身的值,用于isNaN()判断
isFinite():表示某个值是否为正常的数值,Infinity、-Infinity、NaN和undefined返回false,其余均返回true

[7]. 数组

数组的length属性的值 = 最大的数字键 + 1
将数组的键分别设为字符串或小数(为数组添加属性),结果都不影响length属性。

  • push和pop:“后进先出”的栈结构(stack)  
  • push和shift:“先进先出”的队列结构(queue)

二进制数组

允许以二进制数组操作二进制数据,支持浏览器与显卡之间以二进制的形式进行通信。

  • ArrayBuffer对象:代表原始的二进制数据。表示内存之中的一段二进制数据,支持以数组的方法操作内存
  • TypedArray对象:代表确定类型的二进制数据。用来生成内存的视图
  • DataView对象:代表不确定类型的二进制数据。用来生成内存的视图,支持自定义格式和字节序

对ArrayBuffer的读写均需通过视图实现。

TypedArray视图和DataView视图,两者的区别主要是字节序,前者的数组成员都是同一个数据类型,后者的数组成员可以是不同的数据类型。

二进制数组应用

  • Ajax
  • Canvas
  • WebSocket
  • Fetch API
  • File API

[8]. 闭包

JavaScript语言特有的“链式作用域”结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。
也就是说,父对象的所有变量,对子对象都是可见的,反之则不成立。
闭包就是函数,能够读取其他函数内部变量的函数。
由于在JavaScript语言中,只有函数内部的子函数才能读取内部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。
闭包最大的特点:“记住”诞生的环境
闭包的最大用处有两个:

  • 可以读取函数内部的变量
  • 让变量始终保持在内存中,即闭包使诞生环境一直存在(闭包可以看作是函数内部作用域的一个接口)

本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁
实际中,常用于封装对象的私有属性和私有方法

[9]. eval命令

将字符串当作语句执行:

  • 直接使用:eval(expression),当前局部作用域
  • 间接调用:除eval(expression)外,全局作用域

该命令JavaScript引擎不优化,运行速度较慢。

通常情况下,eval最常见的场景是解析Json数据字符串。
最正确的做法应该是:使用浏览器提供的JSON.parse方法

[10.1]. 对象

对象转换成原始类型的值:obj.valueOf().toString()

  • 对象的valueOf方法总是返回对象自身
  • 对象的toString方法默认返回[object Object]

JavaScript语言的继承是通过“原型对象”(prototype),而不是“类”(class)。

至于原因,参见:Javascript继承机制的设计思想

注:在出现对象或函数的地方,可以用类替换,或许更容易理解。

new

C#/Java/C++中的new用法

1
类名/var obj = new 类名();

而JS中的new用法,略有不同,是其简化设计版

1
var obj = new 构造函数名();

使用new命令时,其后面的构造函数依次执行:

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

特别地,注意构造函数体中有return语句的情况。

new命令简化的内部流程:

toString()

Object.prototype.toString方法返回对象的类型字符串,可以判断一个值的类型:Object.prototype.toString.call(value)

1
2
3
4
var type = function (o){
  var s = Object.prototype.toString.call(o);
  return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};

这是比 typeof 运算符更准确的类型判断函数。

this

this是属性或方法“当前”所在的对象。但是,this的指向是动态的。

  • 全局环境:this指向顶层对象window(this === window;  //true)
  • 构造函数:指向实例对象
  • 对象的方法:指向方法运行时所在的对象
1
2
3
4
5
6
7
8
9
10
var obj ={
  foo: function () {
    console.log(this);
  }
};
 
// 表示调用foo方法,this指向对象obj
obj.foo()
// 表示属性foo对应的值,this指向顶层对象
obj.foo

直白理解,JS引擎内部,obj和obj.foo储存在两个内存地址:地址一和地址二。obj.foo()这样调用,是从地址一调用地址二,因此地址二的运行环境是地址一,this指向obj。但是,obj.foo表示直接取出地址二执行,因此运行环境就是全局环境,this指向全局环境。  

注意

  • 避免多层this
  • 避免在数组处理方法中使用this
  • 避免在回调函数中用this

对于多层this,可以将外层的this先赋值给临时变量tmp,内层函数调用this的地方用tmp替换。

this绑定

JS提供 callapplybind 三种方法,实现动态切换/固定this的指向。

(1)call

指定函数内部this的指向。默认参数为空,则指向全局对象。

1
func.call(thisValue, arg1, arg2, ...)

(2)apply

同call方法,唯一的区别就是,它接收一个数组作为函数执行时的参数

1
func.apply(thisValue, [arg1, arg2, ...])
  • 将数组的空元素变为undefined
  • 转换类数组对象为真正的数组
  • 绑定回调函数的对象 

call和apply方法绑定函数执行时所在的对象,还会立即执行函数。 

(3)bind

将函数体内的this绑定到某个对象,然后返回一个新函数,而且(每一次绑定均返回一个新的函数)

:涉及到this时(特别是有些库方法内部有this,不易察觉),在将函数赋值给其他变量时,务必注意this的绑定。

对this的详细理解,请参见:this关键字

prototype

JS规定

每一个构造函数都有一个prototype属性,该属性指向另一个特殊的对象。这个对象的所有属性和方法,都会被构造函数的实例继承。

JS继承机制的设计思想:原型对象的所有属性和方法都能被实例对象共享。也就是说,如果属性和方法定义在原型上,那么所有实例对象均可共享。

  • 数据共享,节省内存
  • 体现实例对象之间的联系

可以理解成接口或者是类的静态变量。实例对象可以视作是从原型对象衍生出来的子对象。

JavaScript规定:

  • 每个函数都有一个prototype属性,指向一个对象
  • 所有对象都有自己的原型对象prototype

原型链

prototype chain:对象到原型,再到原型的原型,直至null。

Object.prototype是所有对象的原型,而Object.prototype的原型是null

1
Object.getPrototypeOf(Object.prototype);  // null

prototype对象的constructor属性,默认指向prototype对象所在的构造函数 。

1
2
3
4
function F() {}
var f = new F();
f.constructor === F // true
f.constructor === f.prototype.constructor // true

利用该属性,可以判定某个实例对象,是哪个构造函数产生的。

1
f.constructor.name; // "F"

也可以由一个实例对象新建另一个实例,利用f.constructor间接调用构造函数

1
2
3
F.prototype.createCopy = function () {
  return new this.constructor();
};

constructor属性表示原型对象与构造函数之间的关联关系,若修改原型对象,需同时修改constructor属性的指向。

1
2
3
4
5
6
7
8
9
// 好的写法:将constructor属性重新指向原来的构造函数
F.prototype = {
  constructor: F,
  method1: function (...) { ... },
  // ...
};
 
// 更好的写法:只在原型对象上添加方法
F.prototype.method1 = function (...) { ... };

Object

获取原型对象的标准方法:Object.getPrototypeOf

1
2
3
4
5
6
7
8
9
// 实例对象f的原型是 F.prototype
Object.getPrototypeOf(f);  // F.prototype
// 空对象的原型是 Object.prototype
Object.getPrototypeOf({});  // Object.prototype
// Object.prototype 的原型是 null
Object.getPrototypeOf(Object.prototype);  // null
// 函数的原型是 Function.prototype
function f() {}
Object.getPrototypeOf(f);  // Function.prototype

实例对象的__proto__属性,返回该对象的原型,等同于getPrototypeOf方法。

生成实例对象的常用方法:Object.create

实质是新建一个空的构造函数F,然后让F.prototype属性指向参数对象obj,最后返回一个F的实例,从而实现让该实例继承obj的属性。

1
2
3
4
5
Object.create = function (obj) {
    function F() {}
    F.prototype = obj;
    return new F();
  };

创建一个空对象

1
2
3
var obj1 = Object.create({});
var obj2 = Object.create(Object.prototype);
var obj3 = new Object();

若想生成一个纯粹的空对象,即不继承任何属性

1
var obj = Object.create(null);

获取所有属性键名:Object.getOwnPropertyNames

只返回对象本身的,不包含继承的,而且不管是否可以遍历(与Object.keys的区别)。

对应的,hasOwnProperty方法用于判定是否存在于对象本身(与in的区别),该方法是JS中唯一一个处理对象属性时,不会遍历原型链的方法。

获得对象的所有属性(不管是自身的还是继承的,也不管是否可枚举)

1
2
3
4
5
6
7
8
9
10
function allPropertyNames(obj) {
  var props = {};
  while(obj) {
    Object.getOwnPropertyNames(obj).forEach(function(p) {
      props[p] = true;
    });
    obj = Object.getPrototypeOf(obj);
  }
  return Object.getOwnPropertyNames(props);
}

对象的拷贝

确保拷贝后的对象:

  • 与原对象具有同样的原型
  • 与原对象具有同样的实例属性

采用ES2017引入的标准的Object.getOwnPropertyDescriptors方法,简化为

1
2
3
4
5
6
function copyObject(orig) {
  return Object.create(
      Object.getPrototypeOf(orig),
      Object.getOwnPropertyDescriptors(orig)
  );
}

关于拷贝,可参见:Javascript面向对象编程(三):非构造函数的继承 中 深拷贝 部分,此处仅引用其代码

其实,此代码仅满足了上述的第2个条件。

属性描述对象

attributes object,JS提供的内部数据结构,用来描述对象的属性,控制对象的行为

  • value
  • writable
  • enumerable
  • configurable
  • get
  • set

如果一个属性的enumerable为false下面三个操作不会取到该属性

  • for..in循环
  • Object.keys方法
  • JSON.stringify方法

存取器:get 与 set ,有2种定义形式(第2种更常用)

拷贝:将一个对象的所有属性,拷贝到另一个对象

行为控制:控制读写状态,防止对象被改变

  • Object.preventExtensions:无法添加新属性
  • Object.seal:既无法添加新属性,也无法删除旧属性
  • Object.freeze:无法添加新属性、无法删除旧属性、也无法改变属性的值,近似常量

从上至下,控制性越强。Object.seal实质是把属性描述对象的configurable属性设为false。

若想彻底锁定对象,需要锁定对象的原型

1
2
3
4
var obj = new Object();
Object.preventExtensions(obj);
var proto = Object.getPrototypeOf(obj);
Object.preventExtensions(proto);

这样就避免通过改变原型对象,间接改变对象属性。

[10.2]. 继承

子构造函数(子类)继承父构造函数(父类)

  • 子类继承父类的实例:在子类的构造函数中,调用父类的构造函数
  • 子类继承父类原型:子类的原型指向父类的原型
1
2
3
4
5
6
function Son() {
  Father.call(this);
}
 
Son.prototype = Object.create(Father.prototype);
Son.prototype.constructor = Son;

关于继承的问题,参见:Javascript面向对象编程(二):构造函数的继承

另一种实现形式,异曲同工

1
2
3
4
5
6
7
8
9
10
function extend(Son,Father){
    var Tmp = function(){};
    Tmp.prototype = Father.prototype;
     
    var tmpObj = new Tmp( );
     
    Son.prototype = tmpObj;
    Son.prototype.constructor = Son;  //必写,否则孩子的构造函数指向不对
    Son.super = Father.prototype;  //可写,提供孩子访问父亲的方法
}

该方法也是 YUI 库实现继承的方法,图示原型链

特别是在:原型继承,对原型链的图示,有助于对prototype的理解。

JS不提供多重继承功能(不允许一个对象同时继承多个对象),但可以间接实现

该实现模式称为 Mixin(混入)。

封装私有变量

  • 普通构造函数形式
  • 立即执行函数(IIFE):不暴露私有成员
  • 模块的放大模式:支持模块拆分和继承
  • 宽放大模式:与放大模式相比,宽放大模式的“立即执行函数”的参数可以是空对象

在未出现class关键字前,可采用如下方式模拟类

参见:Javascript定义类(class)的三种方法

在ES6中,引入了class关键字,更接近Java/C#的用法,极大地简化了原型链代码。

[11]. == 与 ===

  • ==:相等运算符,比较两个值是否相等
  • ===:严格相等运算符,比较它们是否为“同一个值”

如果两个值不是同一类型,===直接返回false,而==会将它们转换成同一个类型,再用===进行比较。
对于两个对象的比较,===比较的是地址,而大于或小于运算符比较的是值。

1
2
3
4
5
// undefined和null与自身严格相等
undefined ===/== undefined  //true
null ===/== null            //true
NaN ===/== NaN              //false
undefined == null           //true

不要使用相等运算符(==),最好只使用严格相等运算符(===)。

[12]. 位运算

所有的位运算都只对整数有效。
位否运算:一个数与自身的取反值相加,等于-1。

位否运算遇到小数时,会将小数部分舍去,只保留整数部分。对一个小数连续进行两次二进制否运算,能达到取整效果。

1
~~ -1.9999 // -1

异或运算也可以实现取整运算

1
-8.9 ^ 0  //-8

但是使用二进制否运算取整,是所有取整方法中最快的一种。
位或运算:将任意数值转为32位带符号整数

1
2
3
4
5
function toInt32(x) {
  return x | 0;
}
toInt32(Math.pow(2, 32) + 1) // 1
toInt32(Math.pow(2, 32) - 1) // -1

[13]. switch…case

通常是 case...break 的形式

建议写成对象结构,避免代码冗长

[14]. JSON
stringify()与parse()

  • JSON.stringify:将一个值转为JSON字符串
  • JSON.parse:将JSON字符串转换成对应的值

toJSON()
若参数对象有自定义的toJSON方法,那么JSON.stringify会使用此方法的返回值作为参数,而忽略原对象的其他属性。

toJSON()的一个应用是,将正则对象自动转为字符串。
因为JSON.stringify默认不能转换正则对象,但设置了toJSON()后,就可以转换正则对象

[15]. 正则表达式

正则表达式中,需要反斜杠转义的一共有12个字符:^、.、[、$、(、)、|、*、+、?、{和\\。

  • [\S\s]:指代一切字符
  • \w:匹配任意的字母、数字和下划线,相当于[A-Za-z0-9_]

replace

如果不加g修饰符,仅替换第一个匹配成功的值,否则替换所有匹配成功的值。

1
2
3
'aaa'.replace('a', 'b') // "baa"
'aaa'.replace(/a/, 'b') // "baa"
'aaa'.replace(/a/g, 'b') // "bbb"

replace方法的一个应用:去除空格

1
2
3
4
5
// str不变
var str = '  #id div.class  ';
var ss = str.replace(/^\s+|\s+$/g, '');
var ss = str.trim();

量词符
用来设定某个模式出现的次数。

  • ?  问号表示某个模式出现0次或1次,等同于{0,1}
  • *  星号表示某个模式出现0次或多次,等同于{0,}
  • + 加号表示某个模式出现1次或多次,等同于{1,}

默认最大可能匹配:贪婪模式
若改为非贪婪模式,在 * 或 + 的后面加上 ? 即可。
修饰符

1
2
3
4
5
6
g 表示全局匹配(global),主要用于搜索和替换
i 表示忽略大小写(ignorecase)
m 表示多行模式(multiline),使^和$会识别换行符(\n)
s 使得.可以匹配任意单个字符,包括换行符\r或\n (dotAll模式)
y “粘连”(sticky)修饰符,g 的加强版
u 用于正确处理大于\uFFFF的 Unicode 字符(Unicode 模式)

断言

  • 先行断言:lookahead,/x(?=y)/
  • 先行否定断言:negative lookahead,/x(!=y)/
  • 后行断言:lookbehind,/(?<=y)x/
  • 后行否定断言:negative lookbehind,/(?<!y)x/

关于正则表达式,详情请见:http://javascript.ruanyifeng.com/stdlib/regexp.html

具名组匹配

利用exec提取()匹配的结果,同时为每一个结果预先指定名字。

  • 定义:?<name>
  • 使用:res.groups.name

也可以在其他地方引用:$<name>

若是在某个正则表达式内部引用:\k<name>

[16]. 计时方法

计时

获取某段代码的执行耗时

1
2
3
4
5
console.time('计时器名');
xxx...xxx
console.timeEnd('计时器名');
 
// 计时器名: xxx.xxxxms

定时器

  • setTimeout()
  • setInterval()

运行机制:将指定的代码移出本轮事件循环,等到下一轮事件循环,再检查是否到了指定时间

  • 如果不到,继续等待
  • 如果到了,且本轮事件循环的所有同步任务执行完,再执行对应的代码(回调函数)

为确保两次执行之间有固定的间隔,不建议用setInterval,而是每次执行结束后,使用setTimeout指定下一次执行的具体时间

1
2
3
4
var timer = setTimeout(function f() {
  // ...
  timer = setTimeout(f, 2000);
}, 2000);

上面代码可以确保,下一次执行总是在本次执行结束之后的2000毫秒开始。

有关setTimeout()的原理,请参见:https://www.jianshu.com/p/3e482748369d?from=groupmessage

防抖动:debounce()
假定两次Ajax通信的间隔不得小于2500毫秒,实际中应该

1
2
3
4
5
6
7
8
9
10
11
12
13
$('textarea').on('keydown', debounce(ajaxAction, 2500));
 
function debounce(fn, delay){
  var timer = null; // 声明计时器
  return function() {
    var context = this;
    var args = arguments;
    clearTimeout(timer);
    timer = setTimeout(function () {
      fn.apply(context, args);
    }, delay);
  };
}

若是如下格式,会存在连续点击触发keydown事件、频繁调用回调函数的问题。

1
$('textarea').on('keydown', ajaxAction);

setTimeout(fun, 0)
尽可能早地执行fun,但是并不能保证立刻就执行fun。

  • 调整任务执行顺序
  • 拆分计算量大耗时长的任务:代码块高亮、改变网页背景色  

关于定时操作,可参见:定时器 - 阮一峰

[17]. 异步操作

JS异步操作的几种模式

  • 回调函数:最基本
  • 事件监听:事件驱动
  • 发布/订阅:观察者模式

其中,发布订阅模式优于事件监听模式,具体参考:异步操作概述 - 阮一峰; 

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

  • 代理作用(proxy),充当异步操作与回调函数之间的中介桥梁
  • 使得异步流程可以写成同步流程

设计思想:所有异步任务都返回一个Promise实例。

  • 预加载图片
  • Ajax操作

Promise支持:串行执行异步任务 和 并行执行异步任务。

关于Promise,可参见:Promise对象 - 阮一峰Promise - 廖雪峰

[18]. 有限状态机

Finite-state machine

  • 状态(state)总数是有限的
  • 任一时刻,只处在一种状态之中
  • 某种条件下,会从一种状态转变(transition)到另一种状态

结合异步操作,与对象的状态改变挂钩,当异步操作结束时,发生相应的状态改变,由此再触发其他操作。

可以利用有限状态机的函数库:Javascript Finite State Machine

1
var fsm = StateMachine.create();
  • 允许为每个事件指定两个回调函数:onBeforeEventA,onAfterEventA
  • 允许为每个状态指定两个回调函数:onLeaveState1,onEnterState1

若事件EventA使得由状态State1变为State2,则调用顺序为

onBeforeEventA → onLeaveState1 → onEnterState2 → onAfterEventA

参见:JS与有限状态机Javascript State Machine

DOM模型

JS执行速度远高于DOM。

详情请参见:JS - DOM - sqh; 

Ajax

详情请参见:JS - Ajax - sqh;  

参考

JavaScript 标准参考教程(alpha)- 阮一峰ECMAScript 6  - 阮一峰

JavaScript教程 - 廖雪峰

posted @   万箭穿心,习惯就好。  阅读(544)  评论(1编辑  收藏  举报
编辑推荐:
· .NET开发智能桌面机器人:用.NET IoT库编写驱动控制两个屏幕
· 用纯.NET开发并制作一个智能桌面机器人:从.NET IoT入门开始
· 一个超经典 WinForm,WPF 卡死问题的终极反思
· ASP.NET Core - 日志记录系统(二)
· .NET 依赖注入中的 Captive Dependency
阅读排行:
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(二):用.NET IoT库
· 几个自学项目的通病,别因为它们浪费了时间!
· 在外漂泊的这几年总结和感悟,展望未来
· .NET 数据拷贝方案选择
· .net工作流elsa-书签
点击右上角即可分享
微信分享提示