• JavaScript

    • 初识

      • 计算机语言
      • 翻译器
      • 标识符、关键字、保留字
      • 计算机基础
    • JavaScript(ECMAScript)

      • 变量(variable)与常量(constant)
      • 注释
      • JS输入输出语句
      • 数据类型

        • 堆和栈
        • 原始数据类型
        • 对象类型(Object)
        • Symbol
        • Set
        • Map
        • 字面量
      • 运算符

        • 算数运算符
        • 递增和递减运算符
        • 比较运算符
        • 逻辑运算符
        • 赋值运算符
        • 扩展运算符
        • 解构赋值

          • 运算符和优先级
      • 语句

        • 流程控制

          • 分支流程控制

            • if
            • 三元表达式
            • switch
          • 循环流程控制

            • for
            • 双重for
            • while
            • do while
            • for in
            • for of
        • 函数(function)

          • arguments的使用
          • 构造函数
          • 箭头函数
        • 作用域

          • 块级作用域
        • Class类

          • 类的继承
      • 异步编程

        • 迭代器(Iterator)
        • 生成器(Generator)
        • Promise(承诺)对象
        • Async
      • 相关功能

        • 函数(function)
        • 方法(method)
      • 案例

        • 变量值交换
        • 数组遍历
        • 算法:冒泡排序

JavaScript

  • JavaScript

    • JavaScript语法(ECMAScript)
    • 页面文档对象模型(DOM)
    • 浏览器对象模型(BOM)

ECMAScriptJavaScript,前者是后者的标准,后者是前者的实现

Test
Test

初识

计算机语言

计算机语言指用于人与计算机之间通讯的语言
三大类:机器语言汇编语言高级语言
机器语言:0和1组成的二进制树,二进制是计算机语言的基础
编程语言(Programming Language):可以通过类似于人类语言的“语言”来控制计算机
编程语言两种通用形式:汇编语言高级语言
汇编语言:实质和机器语言相同,都是直接对硬件操作,只不过指令采用了英文缩写的标识符
高级语言:相对于低级语言,并不特指一门语言,而是一个统称,常用的:C++、C、Java、C#、Python、PHP、JavaScript、Go、TypeScript、Swift、Lua、

翻译器

计算机不能直接理解任何除机器语言以外的语言,因此编程语言运行时需要翻译成机器语言,负责翻译的工具称为翻译器
翻译器方式的不同划分出了两种类型的语言
编译型语言:代码执行之前进行翻译,生成中间代码文件(二进制文件,如exe可执行程序、dll动态链接库),如:Java
解释型语言:运行时进行及时解释,并立即执行,如:JavaScript

标识符、关键字、保留字

标识符:指开发人员为彬良、互相、函数、参数取的名字
关键字:是编程语言本身已经使用了的字,不能用它们充当变量名、方法名,JS关键字包括:break、case、catch、continue、default、delete、do、else、finally、for、function、if、in、instanceof、new、return、switch、this、throw、try、typeof、var、void、while、with等
保留字:预留的关键词,即现在用不上但以后可能成为关键词,同样不能用它们充当变量名、方法名,JS保留字包括:boolean、byte、char、class、const、debugger、double、enum、export、extends、fimal、float、goto、implements、import、int、interface、long、mative、package、private、protected、public、short、static、super、synchronized、throws、transient、volatile等

计算机基础

  • 计算机

    • 硬件

      • 输入设备

        • 鼠标、键盘、手写板、摄像头等
      • 输出设备

        • 显示器、打印机、投影仪等
      • CPU(中央处理器):负责处理数据与运算
      • 硬盘:存储数据,永久存储
      • 内存:存储数据,暂时存储
    • 软件

      • 系统软件

        • Windows、MacOS、Linux
      • 应用软件

        • 浏览器、VSCode、Word、QQ

JavaScript语法(ECMAScript)

变量(variable)与常量(constant)

变量(variable)

//变量声明
var variableName;
//变量赋值
var variableName2 = "str";
//声明多个变量
var variableName3 = 1,
    variableName4 = "str";

//使用let声明
let value = 123;
//let类似于var,为ES6中新增的语法,不同之处主要体现于用在函数和方法里面,不会污染全局变量,没有变量提升,更好用

建议:大多数时候用const声明常量,在声明的量的值需要改变时使用let,var废弃
资源释放

let val = 233;
val = null;

变量提升
即预解析中的变量预解析,同样的还有函数预解析

//正常情况
var a = 'hi';
console.log(a);
//输出'hi'
//非正常情况
console.log(a)
var a = 'hi';
//输出undefined
//使用let声明
console.log(a)
let a = 'hi';
//报错,因为a在此之前未被声明而不是像var一样将所有变量提前var a =undefined
var arr = [1, 2, 3];
for (var i = 0; i < arr.length; i++) {
    console.log(arr[i]);
}
console.log(i)
//在使用for循环结束之后,定义的初始化变量i并没有被销魂仍然可以被输出,导致了变量泄露,使用let即可解决此问题
var a = 1;
var a = 2;
//var可以被重复声明造成不便
let b = 1;
let b = 2;
//报错

函数提升

fn();
function fn() {
    console.log('hi');
}
//即使在函数声明前调用命名函数也可以正常使用,这便是函数预解析(函数提升)

fn2();
var fn2 = function() {
    console.log('hello');
}
//报错,因为匿名函数是一个变量,var声明的变量会有变量提升但仅仅只是在代码执行前声明了变量而未给值(undefined)
//但对于变量本身而言,变量提升本就不应该

常量(constant)

const constant = 123;
//constant的值无法被改变
//对象结构
const constant2 = {
    value: 'steve'
}
constant2.value = 'alex';
//但是对象结构的常量里面的值可以被修改
constant2 = {
    value: 'alex'
};
//不可以

注释

与java、c、php注释方法一致

//单行注释
/*多行
*注释
*/

JS输入输出语句

*归属于浏览器,由浏览器提供的API

方法说明
alert(msg)浏览器弹出警示框
console.log(msg, mgs2, ...msgN)浏览器控制台打印输出信息
prompt(info)浏览器弹出输入框,用户可以输入

数据类型

ECMAScript 标准定义了原始数据类型)和引用数据类型,共七种内置类型:

  • 原始数据类型(简单数据类型):按值访问,可以操作保存在变量中实际的值,存储时存储的是值本身,因此得名

    • 空值(null)
    • 未定义(undefined)
    • 布尔值(boolean)
    • 数字(number)
    • 字符串(string)
    • 符号(symbol)
  • 引用类型(复杂数据类型):引用类型的值是保存在内存中的对象,存储时存储的仅仅是地址(引用),因此得名

    • 对象
      (Object)

      • 布尔对象(Boolean)
      • 数字对象(Number)
      • 字符串对象(String)
      • 函数对象(Function)
      • 数组对象(Array)
      • 日期对象(Date)
      • 正则对象(RegExp)
      • 错误对象(Error)

堆和栈

前者由操作系统自动分配释放存放函数的参数值、局部变量的值等;简单数据类型放到栈里
后者存储复杂类型(对象),由程序员分配释放,若不释放,由垃圾回收机制回收;复杂数据类型放到堆里
引用类型变量里存放的是地址在栈空间内,真正的对象实例在堆空间里,地址指向堆

原始数据类型

数字型(Number)
包含整数值和浮点型值,如1、1.0,默认值:0
布尔值类型(Boolean)
如true、false,等价于1和0,默认值:false(=>0)
字符串类型(String)
带引号,默认值:""
模板字符串(ES6)

let age = 18,
    name = "2233ya";

let result = `信息:
年龄:${age}
名字:${name}
`
console.log(result);

Undefined与Null
var a;声明了变量但未给值,默认值:undfined
var a = null;声明了变量并给了一个空值,默认值:null

对象类型(Object)

var obj = {
    name: '糊狸',
    age: 18,
    say: function() {
        console.log("???");
    }
}
//对象取值 方法1
var age = obj.name;
//方法2
var age = obj['name'];
//ES6中简写
const name = '糊狸',
    age = 18;
const obj = {
    name,//等于与name: name
    age,
    getName(){//等价于getName: function () {...}
        console.log(this.name)
    }
}

对象下的子变量称之为该对象obj的属性,对象内,以键: 值的形式存在,即key: value
对象下的函数称之为方法(method)

数组类型

//数组创建
//使用new创建
var arr = new Array(); //创建了要给空的数组
//使用数字字面量创建
var arr = [];

//数组访问
var arr2 = [1, "str", true];
console.log(arr2[0])
//输出1,[]内的数字表示该数组内的第n - 1个元素(以0开头)

Symbol

ES6新增,原始数据类型,声明的值表示是独一无二的,用于定义私有变量

const val = Symbol('str');
const val2 = Symbol('str');
//即使两者的值都一致,但内存地址不同,严格等于===将返回false

//对象内
let obj = {
    [val]: '???' //键或值为Symbol类型时必须加中括号[]
}
console.log(obj[val]); //取值访问仅能用类似于数组的方式访问,不允许obj.val

//私有变量访问
let arr = Object.getOwnPropertySymbol(obj);//获取对象类的所有私有变量Symbol的键Key,返回数组
console.log(arr[0]);
//Symbol(val)
let arr2 = Reflect.ownkeys(obj);//同上
//[Symbol(val)]

Set

集合:表示无重复值的无序列表,本质为构造函数,使用new关键词创建

let set = new Set();
console.log(set)//{}

//添加元素
set.add(1);
set.add(2);
set.add(2);
console.log(set)//{1, 2},第二个add(2)被忽略
//删除元素与元素检测
set.delete(2);
console.log(set.has(3));//false

//关于资源释放
let val = {a: 1};
set.add(val);
val = null;
console.log(set) //{1, {a: 1}},资源释放后不受影响

let set2 = new WeakSet(),val2 = {a: 1};
set2.add(val2);
val2 = null
console.log(set) //{},WeakSet受影响,有局限性

Map

是键值对无重复的有序列表,键和值是任意类型

let map = new Map();
map.set('name', '糊狸');//添加键值对
map.set('age', 18);
console.log(map) //Map(2) {"name" => "糊狸", "age" => 18}
console.log(map.get('name')) //"糊狸",map.get(value)获取map中的元素(键对应的值)
map.has('name');//true,检测元素(键值对)是否存在
map.delete('name');//删除键值对
map.clear();//清空map中的所有元素

字面量

字面量表示如何表达这个值
数字字面量:8,9,10
字符串字面量:'字符串',"str"
布尔字面量:true,false
数组字面量:[a, b, c]
对象字面量:{}
Symbol字面量

运算符

又称操作符

  • 运算符

    • 算数运算符
    • 递增和递减运算符
    • 比较运算符
    • 逻辑运算符
    • 赋值运算符

算数运算符

运算符描述实例
+10 + 20 = 30
-10 - 20 = -10
*10 * 20 = 200
/10 / 20 = 0.5
%取余数(取模)9 % 2 = 1(返回除法的余数)

+可用于字符串类型拼接

递增和递减运算符

等同于num = num + 1,num = num - 1
前置:++num,--num
后置:num++,num--
单独使用时无区别,带入到运算里面时,前置的表达式最终返回值为自加或自减后的结果,后置的表达式的返回值则是先返回num原本的值然后再做自加或自减运算
例子:

var num = 1;
var num2 = 1;
console.log(++num + 1)
console.log(num)
//输出3,++num自加后为 2 + 1 = 3 
//输出2
console.log(num2++ + 1)
console.log(num2)
//输出2,num++返回原值1 + 1 = 2 
//输出2,再次输出则是自加后的结果

比较运算符

运算符描述案例结果
<小于1 < 2true
>大于1 > 2false
>=大于或等于2 >= 2true
<=小于或等于3 <= 2false
==判等号37 == 37true
!=不等号37 != 37false
=== !==全等 要求值和数据类型都一致37 === '37'false

逻辑运算符

运算符描述案例结果
&&"逻辑与", 简称"与" andtrue && falsefalse
\\ "逻辑或", 简称"或" ortrue && falsetrue
!"逻辑非", 简称"非" not!truefalse

赋值运算符

运算名称简写的操作符分解含义符号
赋值x = yx = y=
加法赋值x += yx = x + y+=
减法赋值x -= yx = x - y-=
乘法赋值x *= yx = x * y*=
除法赋值x /= yx = x / y/=
求余赋值x %= yx = x % y%=
求幂赋值x ** yx = x ** y**
左移位赋值x <<= yx = x << y<<=
右移位赋值x >>= yx = x >> y>>=
无符号右移位赋值x >>>= yx = x >>> y>>>=
按位与赋值x & yx = x & y&
按位异赋值x ^= yx = x ^ y^=
按位或赋值`x= y``x = xy``y`

+=可用于字符串类型拼接,a = a + 233等价于a += 233

扩展运算符

又名rest参数,形式为...variableName
应用1:剩余参数
使用arguments关键词可以获取函数调用时传过来的所有参数,在遍历除去前N个实参后剩余的全部实参需要在for循环定义初始化变量的数值,有时在不知道是前几个实参后需要遍历时就会很麻烦,而扩展运算符便解决了这一问题

function fn(num1, ...nums) {
    //形参内,扩展运算符后的变量名随意
    let result = 0;
    for (let i = 0; i < nums.length; i++) {
        //nums是一个真正的不数字,而不是arguments那样的伪数组
        result += nums[i];
    }
    console.log('第一个数是', a, '剩余数的和', result)
}
//应用2:拆散数组用于实参
//在函数外,扩展运算符也可以用于拆散数组带入到实参里或其它场景里
let arr = [2, 3, 4, 5, 6, 7, 8, 9];
fn(233, ..arr);
//一般的,扩展运算符后方允许有正常参数,但前方也必须要有,若前方没有,后方的正常参数应提到扩展运算符参数之前

解构赋值

ES6新增,可以将值从数组属性从对象提取到多个变量里赋值

let val = [233, 2233, 2333];
let {a, b, c} = val;
//a=233,b=2233,c=2333

//解构失败:变量返回undefined
let val2 = [];
let {d, e} = val2;

//不完全解构
let {x, y} = {1, 2, 3};
//x=1,y=2
let { , , z} = {1, 2, 3};
//z=3

运算符优先级

优先级运算类型关联性运算符示例
20分组表达式N/A(foo)
19属性访问器从左到右foo.bar
属性访问器从左到右foo[bar]
实例化对象(带参数列表)N/Anew Foo(bar)
函数调用从左到右foo()
18实例化对象(无参数列表)从左到右new Foo
17更新表达式(后置递增)N/Afoo++
更新表达式(后置递减)N/Afoo--
16逻辑运算符(逻辑非)从右到左!foo
按位非 ~foo
一元加法 +foo
一元减法 -foo
更新表达式(前置递增) ++foo
更新表达式(前置递减) --foo
typeof typeof foo
void void foo
delete delete foo
await await foo
15算术运算符(幂)从右到左foo ** bar
14算术运算符(乘法)从左到右foo * bar
算术运算符(除法) foo / bar
算术运算符(取模) foo % bar
13算术运算符(加法)从左到右foo + bar
算术运算符(减法) foo - bar
12按位左移从左到右foo << bar
按位右移 foo >> bar
无符号右移 ... >>> bar
11小于从左到右foo < bar
小于等于 foo <= bar
大于 foo > bar
大于等于 foo >= bar
in foo in bar
instanceof foo instance bar
10等号从左到右foo == bar
非等号 foo !== bar
全等号 foo === bar
非全等号 foo !== bar
9按位与从左到右foo & bar
8按位异或从左到右foo ^ bar
7按位或从左到右`foobar`
6逻辑运算符(逻辑与)从左到右foo && bar
5逻辑运算符(逻辑或)从左到右`foo bar`
4条件运算符从右到左foo ? foo : bar
3赋值运算符从右到左foo = bar
赋值运算符 foo += bar
赋值运算符 foo -= bar
赋值运算符 foo *= bar
赋值运算符 foo /= bar
赋值运算符 foo %= bar
赋值运算符 foo <<= bar
赋值运算符 foo >>= bar
赋值运算符 foo >>>= bar
赋值运算符 foo &= bar
赋值运算符 foo ^= bar
赋值运算符 `foo= bar`
2yield从右到左yield foo
yield* yield* foo
1扩展运算符N/A...foo
0逗号运算符从左到右foo, bar
表达式和返回值

表达式:由数字、运算符、变量等以能求得树脂的友谊排列方法所得的组合
简单理解:是由数字、运算符、变量等组成的式子
返回值:即结果

语句

流程控制

控制代码按照什么样的结构顺序来执行
三种主要结构:顺序结构、分支结构、循环结构

分支流程控制
if
if (条件表达式) {
    // 执行语句
}
// if else if 多分支语句
if (条件表达式) {
    // 执行语句
} else if (条件表达式2) {

} else {

}
三元表达式
// 条件表达式 ? 表达式1 : 表达式2,如:
var result;
2 > 1 ? result = "正确的" : result = "错误的";
//等价于if else
if (2 > 1) {
    result = "正确的";
} else {
    result = "错误的";
}
switch
switch (表达式) {
    case "值1":
        //执行语句1
        break;
    case "值2":
        //执行语句2;
        break;
    //...
    default:
        //执行语句最后;        
}

break:用于跳出语句,一定情况下,switch语句内也可以不跳出

循环流程控制
for
for (初始化变量; 条件表达式; 操作表达式) {
    //循环体(执行语句)
}
双重for
while
while (条件表达式) {
    //循环体(执行语句)
}
do while
do {
    //循环体(执行语句)
    //continue;
    //break;
} while (条件表达式);

区别于whiledo while无论条件表达式是否满足都会先执行一次循环体然后再看条件表达式是否满足
continue:跳出本次循环,继续执行剩余循环次数
break:退出当前所有循环

for in

用于更方便的遍历数组或对象,但多用于遍历对象而不是数组

for (初始化变量 in 对象或数组) {
    //初始化变量将作为键key
}
for of

ES6新增,for...of 语句在可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句

for (初始化变量 in 对象或数组) {
    //初始化变量将作为键key
}
//在迭代Map时,初始化变量仅有一个变量赋值时,变量值则是[key, value]形式,解构赋值形式{key, value}可分别赋值键与值,如:
let val = new Map(["a", 1], ["b", 2], ["c", 3])"
for (let {key, value} of ) {
    console.log(value);
}
//1, 2, 3

函数(function)

//1.声明函数(方法1:命名函数)
function funName() {
    //函数体(执行语句)
}
//2.调用函数,不调用函数就不会主动执行    
funName();

//参数(parameter)
function funName2(pa1, pa2, pa3) {
    var result = pa1 + pa2 + pa3;
    return result;
}
var var3 = 3;
console.log(funName2(1, 2, var3));
//输出结果6,(1 + 2 + 3)

//声明函数方法2:函数表达式(匿名函数)
var funName3 = function() {
    console.log("这是一个匿名函数");
}
funName3();
//funName3是变量名不是函数名,与之不同的是,函数表达式的变量存储的是函数而不是值
//匿名函数也可以传参

return:在函数内,用于返回值以及停止函数执行,仅能返回一个值;

arguments的使用
function fn() {
    console.log(arguments);
    console.log(arguments.length);
    console.log(arguments[2]);
}
fn(1, 2, 3);

argument内存储了所有传递过来的实参
伪数组,拥有length属性,但不能使用真正数组的一些方法 pop() push()

全局变量与局部变量

var num = 1;
function fn() {
    console.log(num);
}
//num变量在全局内声明的,因此是全局变量

function fn2() {
    var num2 = 2;
}
//num2变量在函数内声明的,因此是局部变量
fn();
fn2();

函数默认值

//ES5写法:需要在函数内部使用if或三元表达式或逻辑或||判断
function fn(a, b) {
    //1. if(b == null) {var b = 233};
    //2. b == null ? b = 233 : b;
    b = b || 233;
    return b += a; 
}
//ES6写法:方便且在阅读时判断参数是否必要或确定默认值更快捷
function fn2(a,  b=233) {
    return b += a;
}
console.log(fn2(1, 2));//3
console.log(fn2(null, 2));//null为,2
console.log(fn2());//形参a为undefined,NaN
console.log(fn2(1))//234
构造函数
function Fn(name, age, sex) {//构造函数名开头必须大写
    this.name = name;
    this.age = +age;
    //+variable用于字符串转数字,等价于number(variable)
    this.sex = sex;
    //this指向上下文里使用构造函数的对象

//不需要return返回
}

let a = new Fn('糊狸', 18, '男')
//构造函数必须使用new关键词创建,上文的this便指向了a
console.log(a.name)
//输出糊狸
箭头函数

ES6新增

var val = function () {
    //...
}

//等价于
let val2 = () => {
    //...
}
//带多个参数时
let val3 = (a, b) => {
    return a + b;
}
//带一个参数时
let val4 = a => {
    return a;
}
//带参数,仅需返回结果时
let val5 = a => (a + 5);
//仅需返回结果时
let val6 = ()=> 'hello';

此外,箭头函数没有this指向,代码在寻找this时将采用作用域链的方法查找(参考下文),=,在作用上等价于fun.bing()

作用域

作用域代表变量、函数等名字的可用范围,防止名字冲突导致的异常情况
在ES6之前,JS仅有全局作用域与局部作用域

var a = 1;
//全局作用域

function fn() {
    var b = 2;
    //局部作用域
}

作用域链

var num = 1;
function fn() {//外部函数
    var num = 2;
    
    function fn2() {//内部函数
        console.log(num);
        //输出2
    }
}

内部函数访问外部函数的变量,采取链式查找的方式来决定取哪个值(可理解为就近原则),这种结构称之为作用域链

块级作用域

ES6新增,块级作用域内letconst定义的变量与常量不会外泄,块级作用域由一对{}界定

let a = 1;
const b = 3;
{
    let a = 2;
    const b = 4;
}
console.log(a);
console.log(b);
//输出1和3

Class类

ES6里提供了class类语法糖

//ES5造类:使用new与构造函数
function Abc (name, age) {
    this.name = name;
    this.age = age;
    this.getName = function () {
        return this.name;
    }
}
//不懂的还以为是个函数(尽管它本质确实是构造函数)
var p = new Abc('糊狸', 18);

//ES6造类
class Abc {
    //constructor关键词下的内容会在类实例化时立即调用
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    getName() {
        return this.name;
    }
}
let p = new Abc("糊狸", 18);
console.log(p);
console.log(p.getName())//方法使用
类的继承
class Animal {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    getName() {
        return this.name;
    }
}
//使用extends关键词继承父类Animal
class Dog extends Animal {
    constructor(name, age, color) {
        super(name, age)
        //name与age在父类里已经定义过,可使用super(...属性)关键词在子类里直接引用
        //不必再在子类里this.name = name,除非需要重写父类
        this.color = color;
        //color为父类里没有定义过的属性,所以子类里则需要定义
    }
    //子类自己的方法
    getColor() {
        return `它的颜色是${this.color}`;
    }
    //重写父类的方法
    getName() {
        return `它的名字是${this.name}`;
    }
}

let MyDog = new Dog('Cat', 2, 'black');
console.log(MyDog.getName(), MyDog.getColor());

异步编程

迭代器(Iterator)

是一个接口,能快捷的访问数据,通过Symbol.iterator来创建迭代器;用于遍历数据结构的指针(数据库的游标)

const items = ['1' , '2'];
//创建迭代器
const ite = items[Symbol.iterator]();
console.log(ite.next());//{value: "1", done:"false"} done为true表示遍历完毕
console.log(ite.next());//{value: "2", done:"false"} done为true表示遍历完毕
console.log(ite.next());//{value: undefined, done:"true"} done为true表示遍历完毕

生成器(Generator)

generator函数可通过yield关键词挂起,返回遍历器对象,跟普通函数不同,需要在函数名之前加*

function* fn() {//function *fn() {...}均可
    console.log("test");//函数调用时,不会执行该代码,因为有下面的yield,
    yield 2;
    yield 3;
}
//返回一个迭代器对象 可以调用next()
let fun = fn();
console.log(fn.netxt())//{value: 2, done: false}
console.log(fn.netxt())//{value: 3, done: false}
console.log(fn.netxt())//{value: undefined, done: true}
//总结:yield语句是暂停执行,next()是恢复执行

Generator的应用

//期望:加载页面... => 1s之后:加载完毕...(异步操作) => 关闭加载页面
function loadUI() {
    console.log("加载页面...");
    //...
}
function showData() {
    setTimeout(() => {
        console.log('加载完毕')
        //...
    }, 1000)//延时器 单线程
}
function closeUI() {
    console.log("关闭加载页面")
    //...
}
loadUI();
showData();
closeUI()

//实际:加载页面... => 关闭加载页面 => 1s之后:加载完毕
//使用generator
function* load() {
    loadUI();
    yield showData();//yield关键词使执行showData()时暂停执行后面代码
    hideUI();
}
let itLoad = load()//创建迭代器
itLoad.next();//第一次使用next()

function loadUI() {
    console.log("加载页面...");
    //...
}
function showData() {
    //模拟异步操作 
    setTimeout(() => {
        console.log('加载完毕')
        //...
        itLoad.next();//加载完毕,再次使用next()方法放行
    }, 1000)//延时器
}
function closeUI() {
    console.log("关闭加载页面")
    //...
}

Promise(承诺)对象

相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果

但现在执行异步操作更多的是使用async await语句,而非底层的promise

特点
1.对象的状态不受外接影响(也是名字的由来) 处理异步操作三个状态,Pending(进行)、Resolved(成功)、Rejected(失败)
2.一旦状态改变,就不会再变,任何时候都可以得到这个结果

let pro = new Promise(function(resolved, rejected) {//此处resolved和rejected也为函数,因此外层的整个函数称之为高阶函数
    //执行异步操作...为空时
})
console.log(pro);//Promise {<pending>},进行
pro.then((val) => {
    console.log(val);
});
let pro = new Promise(function(resolved, rejected) {
    //执行异步操作
    let res = {//模拟来自后端返回的数据...
        code: 200,
        data: {
            name: '糊狸'
        },
        error: '失败了 '
    }
    setTimeout(() => {
        if(res.code === 200) {
            resolved(res.data);//code = 200操作成功,返回数据
        } else {
            rejected(res.error)//否则失败,返回错误
        }
    }, 1000)
})
console.log(pro);//返回数据或错误
pro.then((val) => {//val接收成功回调后的结果
    console.log(val);
},(err) => {//错误发生时,将执行此处的回调函数,而不是前者
    console.log(err);
});
//封装异步操作(上面的代码无法传参)
function timeOut(ms) {
    return new Promise((resolved, rejected) => {
        setTimeout(() => {
            resolved('Promise succesd!!!')
        })
    }, ms)    //1.外层里声明一个函数,返回promise异步操作
}
timeOut(2000).then((val) => {//2.通过promise链式调用
    console.log(val);
})

Promise的应用

//应用:封装ajax,获取get请求URL返回JSON的方法
const getJSON = function(url) {
    return new Promise((resolved, rejected) => {
        const xhr = new XMLHttpRequest()//XMLHttpRequest()以以下内容来自ajax
        xhr.open('GET', url);//打开xhr
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.send();//发送
        function handler() {
            console.log(this);
            
            if (this.readyState === 4) {
                if (this.state === 200) {
                    resolve(this.response);
                } else {
                    reject(new Error(this.statusText))
                }
            }
        }
    })
}
getJSON('https://iamlolicon.work/api/seimg?r18=true')
    .then(data) => {
        console.log(data)
    }, (error) => {
        console.log(error)
    };

Async

使得异步操作更加简单,是generator的一个语法糖,async会返回要给Promise对象 thencatch

async function f() {
    //return await 'hello';'hello'是一个字符串,但因为await返回的是promise对象
    let s = await 'hello';
    let data = await s.split('');//需等待(await)上面的let s执行完毕才会执行
    return data;//['h', 'e', 'l', 'l', 'o']
}
//async函数如果有多个await,那么then函数会等待所有await指令 运行完的结果 才去执行then的回调函数
f().then(v => {
    console.log(v);
}).catch(e => console.log(e));

async function f2() {
    //throw new Error('出错了');出错时抛出错误
    await Promise.reject('出错了');//await指令下,有一个reject失败操作就不会继续执行下去
    await Promise.resolve('hello');
}

f2().then(v => console.log(v)).catch(e => console.log(e));

//改进版:使用try catch语句
async function f3() {
    try {
        await Promise.reject('出错了');
    } catch (error) {
        
    }
    return await Promise.resolve('hello');
}

f3().then(v => console.log(v)).catch(e => console.log(e));

Async应用

const getJSON = function(url) {
    return new Promise((resolved, rejected) => {
        const xhr = new XMLHttpRequest()//XMLHttpRequest()以以下内容来自ajax
        xhr.open('GET', url);//打开xhr
        xhr.onreadystatechange = handler;
        xhr.responseType = 'json';
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.send();//发送
        function handler() {
            console.log(this);
            
            if (this.readyState === 4) {
                if (this.state === 500) {
                    resolve(this.response);
                } else {
                    reject(new Error(this.statusText))
                }
            }
        }
    })
}

async function getSeimg(url) {
//发送ajax
    let res = await getJson(url);
    console.log(res);
}
getSeimg('https://iamlolicon.work/api/seimg?r18=true')
    .then(back => {
        console.log(now)
    })

相关功能

函数(function)

isNaN(value)
是数字返回false,否则返回true

typeof(value)
返回值的类型:number、string、boolean、undefined、object

String(value)
转成字符串

concat(str1...)
拼接多个字符串,等价于str1 + str...

parseInt(value)
String转成整数数值型

paraseFloat(value)
String转成浮点数数值型

Number(value)
String转换成数值型

Boolean(value)
其它类型转成布尔值
""、0、NaN、null、undefined转成false
其余所有值转成true

Math.PI()
返回圆周率

Math.max(int...)
返回一堆数字中最大的一个

Math.min(int...)
返回一堆数字中最小的一个

Math.abs(int)
返回绝对值

Math.floor(int)
向上取整,返回数字

Math.ceil(int)
向下取整,返回数组

Math.round(int)
就近取整,四舍五入版,注意:-3.5 => -3,返回数字

Math.random()
返回一个0 <= int && int < 1的伪随机浮点数

Date()
日期对象是一个构造函数,必须使用new关键词创建

var arr = new Array();//创建一个数组对象
var obj = new Object();//创建了一个对象实例
var date = new Date();//如果没参数,返回当前系统时间

var date1 = new Date(2019, 10, 01)//数字型写法
var date2 = new Date(2019-10-1 00:00:00)//字符串型写法
console.log(date2);

Date.now()
H5新增,低版本浏览器不可用,返回当前时间戳

var date = +new Date()//使用加号+可直接返回时间戳
console.log(Date.now())//同上

Array.from(value)
ES6新增,将伪数组转换成真正的数组

Array.of(value...)
ES6新增,将一堆数值转换成

Object.keys(obj)
获取对象类的所有键,返回数组

Object.is(value1, value2)
ES6新增,比较两个值是否严格相等,等价于===,返回truefalse

Object.assign(target, obj1, obj2...)
ES6新增,合并对象,返回合并后的对象

let newObj = Object.assign({}, {a: 1}, {b: 2});

Reflect.ownkeys(obj)
ES6新增,同上

Object.getOwnPropertySymbol(obj)
ES6新增,获取对象类的私有变量Symbol,返回数组

setTimeout(func, time)
延时一段时间执行函数,func回调函数,time推迟时间(毫秒),返回任务ID(int)

setInterval(func, time)
设置周期执行函数,fucn回调函数,time间隔周期(毫秒),返回任务ID(int)

clearInterval(int)
取消延时或周期执行项,int为任务ID

Promise.resolve(value)
ES6新增,能将现有的任何对象转换成promise对象

//方法1: let p = Promise.resolve('foo')
let p = new Promise(resolve => resolve('foo'));//方法2
p.then((data) => {
    console.log(data);//返回'foo'
})

Promise.reject(value)
ES6新增,同上

Promise.all([pro1...])
ES6新增

let promise1 = new Promise((resolve, reject) => {})
let promise2 = new Promise((resolve, reject) => {})
let promise3 = new Promise((resolve, reject) => {})

let p4 = Promise.all([promise1, promise2, promise3])

p4.then(() => {
    //三个都成功 才成功
}).catch(err => {
    //一个失败 则失败
})

Promise.race([fun])`
ES6新增,某个异步请求设置超时时间,并在超时后执行相应的操作

Promise.don()
ES6新增

Promise.finally()
ES6新增

function requestImg(ImgScr) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('图片请求超时');
        }, 3000);
    })
}
Promise.race([requestImg('images/1.png'), timeout()]).then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
}).finally()

方法(method)

str.length
返回字符串str的长度

str.toString()
转成字符串,转换数组时,用逗号分隔每一项,返回字符串

str.join(value)
数组转成字符串,与上面的基本一致,但可自定义分隔符value

str.substr(start, length)
从start位置开始(索引号) ,取length个数,返回字符串

str.slice(start, end)
从start位置开始,截取到end位置(end不取),返回字符串

str.substring
与slice一致,但不接受负值

str.split(value)
使用value字符分割str字符串,返回分割后的数组

let str = '2333.png';
let type = str.split('.');
console.log(type)//['2333', 'png']
console.log('图片类型:', type[0])//图片类型: , png

str.trim()
去掉字符串两侧的空格,返回字符串

arr.length
返回数组arr的长度

arr.push(value...)
向数组arr内添加多个元素value(从后添加),返回新数组

arr.pop()
删除数组arr内最后一个元素,返回删除的元素的值

arr.unshift(value...)
像向数组arr内添加多个元素value(从头添加),返回新数组

arr.shift()
删除数组的第一个元素,数组长度减1无参数、修改原数组,返回删除元素的值

arr.reverse()
颠倒数组中的元素的顺序,该方法会改变原数组。返回新数组

arr.sort()
对数组的元素的进行排序(冒泡排序,从小到大数字),该方法会改变原数组。返回新数组

arr.indexOf(value)
查找数组内的元素是否包含给定的值value,包含返回符合条件的第一个元素的索引,不包含返回-1

arr.lastindexOf(value)
查找数组内的元素是否包含给定的值value,包含返回符合条件的最后一个元素的索引,不包含返回-1

arr.copywithin(int1, int2)
ES6新增,数组内将指定位置的元素复制到其它的位置,返回新数组

console.log([1, 2, 3, 4, 5, 6](0, 3))
//[3, 4, 5, 3, 4, 5]

arr.find(value => 表达式)
ES6新增,找出第一个符合条件的数组成员,返回数组元素的值

arr.findIndex(value => 表达式)
ES6新增,找出第一个符合条件的数组成员的索引,返回数组的索引

let num = [1, 2, 3, -1].find(val => val < 0);
//num = -1
let numIndex = [1, 2, 3, -1].findIndex(val => val < 0);
//numIndex = 3 

arr.keys()
ES6新增,返回一个遍历器,为键key,可使用for...of循环遍历

arr.values()
ES6新增,返回一个遍历器,为值value,可使用for...of循环遍历

arr.entries()
ES6新增,返回一个遍历器,为键值对,可使用for...of循环遍历

for (let index of ['a', 'b'].keys()) {
    console.log(index);
}
//0 1
for (let index of ['a', 'b'].values()) {
    console.log(index);
}
//'a' 'b'
for (let [key, value] of ['a', 'b'].values()) {
    console.log(key, value);
}
//0 'a' 1 'b'

arr.next()
ES6新增,逐级返回键值对

let arr = ['a', 'b'];
console.log(arr.next().value);//[0, 'a']
console.log(arr.next().value);//[1, 'b']
console.log(arr.next().value);//undefined,因为该数组已经遍历完毕

arr.includes(value)
ES6新增,返回一个布尔值,判断数组内是否包含给定的值

date.getFullyear()
data为Data日期对象,返回当前日期年份,均为数字型

date.getMonth()
返回当前日期月份

date.getDate()
返回当前日期号数

date.getDay()
返回当前日期星期(星期日为0,星期一为1...星期六为6)

date.getHours()
返回当前时间时

date.getMinutes()
返回当前时间分

date.getSeconds()
返回当前时间秒

data.valueOf()
默认返回当前时间戳,时间戳即总的毫秒数,距离1970.1.1所过去的毫秒数

data.getTime()
同上

set.add(value)
ES6新增,为set数据类型添加元素

set.delete(value)
ES6新增,为set数据类型删除元素

set.has(value)
ES6新增,检测set数据类型下是否有指定元素

set.forEach((val, key)=>{})
ES6新增,遍历set数据类型

map.set(key, value)
ES6新增,为map数据类型添加元素

map.delete(key)
ES6新增,为map数据类型删除元素(键值对)

map.has(key)
ES6新增,检测map数据类型下是否有指定元素(键对应的值)

map.clear()
ES6新增,清空map中的所有元素

func.bing()
取消该函数的this指向

pro.then(resolve [,reject])
ES6新增,两个都为回调函数,返回一个新的promise实例,可继续.then(),可采用链式编程,常与pro.catchpro.finally搭配使用

案例

变量值交换

var a = 1;
var b = 2;
var temp;
a = temp;
a = b;
b = temp;

数组遍历

var arr = ['str', 'str2', 'str3', 'str4'];
for (var i = 0;i < arr.length; i++) {
    console.log(arr[i]);
}

算法:冒泡排序

将数组内的各元素(数字型)从小到大依次排列

var arr = [5, 4, 3, 2, 1];
for (var i = 0; i < arr.length; i++) {//外层循环,总计循环次数
    for (var a = 0; a < arr.length - i; a++) {//内层循环,每次循环需要比较两个元素的次数
        if (arr[a] > arr[a + 1]) {
            var temp = arr[a];
            arr[a] = arr[a + 1];
            arr[a + 1] = temp;
            //如果前一个元素大于后一个元素,则交换两个元素在数组中的位置
        }
    }
}