js前端技术

时间:2024-07-26 11:35:56

一、前端技术

1、HTML

HTML(hypertext markup language)超文本标记语言,不同于编程语言。

超文本就是超出纯文本的范畴,描述文本的颜色、大小、字体。

HTML由一个个标签组成,标签各司其职,有的提供网页信息,有的负责图片,有的负责网页布局。

超文本需要显示,就得有软件呈现超文本定义的排版格式,,例如显示图片、表格、显示字体的大小,颜色,软件就是浏览器。

超文本的诞生是为了解决纯文本不能格式显示问题,是为了好看,但是只用通过网络分享超文本的内容,所以制定了HTTP协议。

2、浏览器

1)历史、1980年代,tim berners-Lee为cern设计基于超文本思想的enquire,以促进科研人员之间信息更新和共享。19899年其编写了《信息化管理;建议》一文,并构建基于Internet的hypertext系统,并在cern开发了world wide web项目。打造了世界上第一站。于1991年8月6日上线。

Tim berners-lee于1990年发明了第一个浏览器,还发明了HTTP协议。

1994年MIT创建了w3c。w3c万维网联盟,负责万维网持续发展,提出w3c的标准应该基于无专利权、无版税。

Marc Andreessen于1993年发明了mosaic浏览器,看到了技术前景,不久后成立自己的公司---网景公司Netscape,1994发不了Netscape navigator浏览器,席卷全球。

1995年微软发布IE。

1999年网景被aol收购,收购后,Netscape公开了浏览器代码。创建了Mozilla组织。Mozilla组织使用gecko引擎重写浏览器。。

2003网景被解散。

2008年google的Chrome浏览器待着v8引擎横空出世。

2)网景公司

HTTP cookie,解决HTTP无状态。

Javascript

Ssl协议:

Jar格式文件,将Java的class文件打包压缩,并加上签名。

2012年4月9日,微软购买800项美国在线的专利或专利授权。

3)浏览器技术

浏览器是特殊的客户端。

浏览器软件分为两个部分

         外壳:

外壳提供用户交互的界面。

内核(引擎engine)

提供HTML,css,图像的渲染引擎。提供DOM编程接口。

提供Javascript引擎。

排版(渲染)引擎

浏览器

说明

Gecko

Firefox

Trident

IE,AOL

Khtml

Presto

oPera

Webkit

Safari,Chrome

Blink

Chrome,Opera

Js引擎:

Jscript、tracemonkey(firefox)  v8等

使用jquery等框架来解决兼容性问题。

3、js

是一种动态的弱类型的脚本解释性语言。和HTML、css秉承三大web核心技术。

4、ES

ECMAscript:是ecma国际组织

JavaScript是商品名。

2009年 ES5发布

2015年ES6发布

5、v8引擎

谷歌推出的,使用的是bsd协议开源。

二、nodejs

1、nodejs简介

Nodejs是服务器端运行JavaScript的开源、跨平台运行环境。

作者是瑞安达尔(ryan dahl),2009年发布,使用了v8引擎,采用时间驱动,非阻塞,异步IO模型。

2012年,npm软件包管理器诞生,通过其,可以方便的发布,分享nodejs的库和源代码。

Nodejs4.0引入了ES6语言的特性。

2、安装

国内阿里云镜像

https://npm.taobao.org/mirrors/node

Linux:

https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.11.3-linux-x64.tar.xz

windows:

https://npm.taobao.org/mirrors/node/latest-v8.x/node-v8.11.3-x64.msi

默认路径安装:

3、开发

Visual studio code

https://code.visualstudio.com/Download

4、注释

和c、Java一样

//单行注释

/*comment*/ 
多行注释,在语句中间使用。

str = 'hello' + /*comment*/ 'student'

5、常量和变量

标识符

标识符必须是字母、下划线、美元符号和数字,但必须是字母、下划线、美元符号开头。,不能是数字开头。

标识符区分大小写。

声明

var 
a声明   a值为undefined   声明全局变量

let 
b 声明   let  块变量,局部变量。

const 
c常量声明时候必须赋值。后期不允许更改。明确知道一个标识符定以后不在膝盖,声明的时候使用const常量,减少被修改的风险。

能给常量就不用变量。

变量和常量声明和初始化的过程中是可以分开的。

var a

let b

console.log(a,b)

a = 1

b = 'a string'

console.log(a,b)

//const c   //不能定义,因为const定义时候必须赋值,之后不可以再次进行更改

const c = 100

console.log(c)

var y //只是复制,y的值为undefined

var x = 1 //规范的声明并初始化,声明全局或局部变量

function hello()

{

var a    //只是声明,a为undefined,作用域是在函数中

a = 100   //赋值

}

//console.log(2,a)   //抛出错误,变量a未定义

//a = 200   //不能提升作用域

//var a = 200;hello();   //var提升作用域

//console.log(3,a)

6、数据类型

序号

名称

说明

1

number

数值型

2

boolean

布尔型,true和False

3

String

字符串

4

Null

只有一个null值

5

Undefined

变量声明未赋值的

6

Symbol

Es6新引入的类型

7

object类型

以上基本类型的复合类型,容器

ES是动态弱语言,弱类型语言,虽然先声明了变量,但是变量可以重新赋值任何类型。

//string

console.log('----string-------')

console.log(a = 3+'abc',typeof(a))

console.log(a = null + 'abc',typeof(a))

console.log(a = undefined + 'abc',typeof(a))

console.log(a = true + 'abc',typeof(a))

//number

console.log('----number----')

console.log(a = null + 1,typeof(a))

console.log(a = undefined + 1,typeof(a))   //undefined没有办法转成对应的数字,只是显示男,not a number

console.log(a = true + 8,typeof(a))

console.log(a = false + 8,typeof(a))

//boolean

console.log('----bool----')

console.log(a = null + true,typeof(a))

console.log(a = null + false,typeof(a))

console.log(a = undefined + true,typeof(a))   //undefined没有办法转成对应的数字

console.log(a = undefined + false,typeof(a))  //undefined,不能转成对应的数字

console.log(a = null & true,typeof(a))

console.log(a = undefined & true,typeof(a))

//短路

console.log(a = null && true,typeof(a))

console.log(a = false && null,typeof(a))

console.log(a = false && 'abc',typeof(a))

console.log(a = true && 'abc',typeof(a))

console.log(a = true && '',typeof(a))

//null

console.log(a = null + undefined,typeof(a))

----string-------

3abc string

nullabc string

undefinedabc string

trueabc string

----number----

1 'number'

NaN 'number'

9 'number'

8 'number'

----bool----

1 'number'

0 'number'

NaN 'number'

NaN 'number'

0 'number'

0 'number'

null 'object'

false 'boolean'

false 'boolean'

abc string

string

NaN 'number'

类型运算:

String:与str相加全部转化为str类型。

Number:与number相加全部转化为number

Boolean类型:转为话number类型

弱类型,不需要强制类型转换,会隐士的类型转换。

总结:

遇到字符串,加号就是拼接字符串。

如果没有遇到字符串,加号就是把其他的所有的类型都当做数字处理。

Undefined特殊,因为他没有定义值,所以是一个特殊的数字nan.

如果运算符是逻辑运算符,短路符,返回的就是短路时候的类型,没有隐士转换,

尽量使用显示的转换。

7、字符串

将一个值利用单引号或者双引号引起来就是字符串。

Es6提供了反引号定义一个字符串,可以支持多行,还可以支持插值。

字符串:插值。使用反引号$符号进行插值,赋值即定义。

let a = 'abc'

let b = 'ced'

let c = `line1

line2

line3

`

console.log(c)

let name = 'tom',age = 19

console.log(`hi name is ${name},age${age}`)

line1

line2

line3

hi name is tom,age19

8、转义字符

名称

说明

\0

Null字节

\b

退格符

\f

换页符

\n

换行符

\r

回车符

\t

Tab制表符

\v

垂直制表符

\’

单引号

\”

双引号

\

反斜杠符(\)

\XXX

由从0到377最多三位八进制数XXX,例如\251是版权符号的八进制序列

\xXX

由从00和FF的两位十六进制数字XX表示的Latin-1字符。\ x A9是版权符号的十六进制序列

\uXXXX

由思维十六进制数字XXXX的Unicode字符,例如,\u 00A9是版权符号的Unicode序列。见Unicode escape sequences(Unicode转义字符)

\u{XXXXX}

Unicode代码点(code point)转义字符,例如\u{2F804}相当于Unicode转义字符\uD87E\uDc04的简写。

9、字符串操作方法

let a = 'abcdefgh'

console.log(a.charAt(2))    //索引查找字符串

console.log(a[2])        //索引查找字符串

console.log(a.toUpperCase())  // 大写

console.log(a.concat('.com'))  
//拼接字符串

console.log(a.slice(3))     
//  切片

console.log(a.slice(3,6))    //

console.log(a.slice(-2,-1))   //负索引切片

console.log(a.slice(-2))    //负索引切片

c

c

ABCDEFGH

abcdefgh.com

defgh

def

g

gh

let url = 'www.google.com'

console.log(url.split('.'))   //以什么进行切割

console.log(url.substr(7,2))   //
返回字符串从何处开始,取多长

console.log(url.substring(7,10)) 
// 返回子串,从何处开始,到什么为止

[ 'www', 'google', 'com' ]

gl

gle

let url1 = 'www.google.com'

console.log(url1.indexOf('com'))     
//   查找字符串所在的索引

console.log(url1.replace('.com','.cn'))   //替换

console.log(url1.indexOf('gle',3))   
//   向右偏移3

url2 = '\tmg edu \r\n'

console.log(url2.trim())       //去除两端的空白字符串

11

www.google.cn

7

mg edu

10、数值型number

在js中,数据均为双精度浮点型范围只能在- +(2^53-1)之间,整型不例外。

数字类型还有三种符号值:+infinity(正无穷)  -infinity(负无穷)和nan(not-a-number非数字)

二进制0b。

八进制0o

十六进制0x

指数表示1E3(1000),2e-2(0.02)

常量属性:

数字的方法;

方法

描述

Number.parseFloat()

把字符串参数解析成浮点数,和全局方法parseFloat()作用一致

Number.parseInt()

把字符串解析成特定基数对应的整型数字,和全局方法parseInt()作用一致

Number.isFinite()

判断传递的值是否为有限的数字

Number.isInteger()

判断传递的值是否为整数

Number.isNaN()

判断传递的值是否为NaN

内置数学对象:Math

有绝对值,对数、指数运算、三角函数运算、最大值、最小值、随机数、开方等运算函数。

console.log(Math.PI)    //3.14 PI值

console.log(Math.abs(-1))   //绝对值

console.log(Math.log2(16))   // 开方

console.log(Math.sqrt(2))    //平方根

console.log(Math.random())    //随机数

11、运算符

1)算数运算符

+ - * / %

console.log(1/2)   //0.5

console.log(1/0)  //Infinity

console.log(5%3)   //2

console.log(parseInt(1/2))     // 
0  向下取整

console.log(parseInt(3/2))     // 1  
向下取整

console.log(Math.floor(3/2))   // 1  
向下取整

console.log(Math.ceil(3/2))    // 2  
向下取整

console.log(Math.round(3/2))   // 
2  四舍五入

console.log(Math.round(1/2))   // 
1  四舍五入

++和—

单目运算符,表示变量自增,自减

I++ 先用i,用完之后在加1

++I i先自增,在使用i

let i = 0

let a = i++

console.log(a,i)   //0  
1

console.log(a,i++)   // 0  
1

a = ++ i

console.log(a,i)    // 3 
3

单目运算符是优先级高于双目运算符。

7

i = 0;

let a = ++i+i+++i+++i; //++i + i++ i++ +i

console.log(a);        //  1  
1   2    3  7

2)比较运算符

不做隐士的类型转换写的是===。

不做两个等等号。严格相等使用三个等号。

console.log(100  > '200') //  false

console.log(100 > 'a')   //false

console.log(300 == '300')  //true

console.log(300 === '300')  //false

3)逻辑运算符

&&,||,!  与或非

4)位运算

& | 
^ ~<< >>位与,位或,异或,取反,左移,右移。

5)三元运算符

条件表达式?真值:假值

console.log(('3' > 30)?'真':'假')

6)逗号操作符

Js运行多个表达式写在一起

let a = 4+5,b = true,c=a > 20?'t':'f'

console.log(a)   // 9

console.log(c)    // f

7)其他

名称

说明

Instanceof

判断是否属于指定类型

Typeof

判断类型字符串

Delete

Delete操作符,删除对象

In

判断指定的属性在对象内,则返回true

console.log('a' instanceof String) 
// false

console.log(1 instanceof Number)   
// false

a = new String('b')

console.log(a instanceof String) 
// true

console.log(new Number(1) instanceof Number) // true

console.log(a instanceof Object) // true

Instance必须明确使用的类型定义变量。没有 new方法的类型的都不是初始的类型。可以用于继承关系的判断。

Typeof就是返回对象的类型字符串。

Delete删除对象、属性、数组元素

8)运算符优先级

运算符由高到低。

var trees = new Array();

逗号运算符优先级最低,比赋值语句还低。

9)表达式(生产器)

function* inc()

{

let i = 0;

let j = 2;

while(true){

yield i++

if (!j--)return  100;

}

}

let gen = inc()

for (let i = 0 ;i<10;i++)

console.log(gen.next());

{ value: 0, done: false }

{ value: 1, done: false }

{ value: 2, done: false }

{ value: 100, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

{ value: undefined, done: true }

每次调用next()方法返回一个对象,这个对象包含两个属性:value和done,value属性表示本次yield表达式的返回值,done属性为布尔值,done是False表示后续还有yield语句执行,如果执行完成或者return后,done为true。

三、js语法

1、语句块

function hello(){

let a = 1;

var b = 2;

c =3

}

if (1)

{

let d = 4;

var e = 5;

f = 6

if (true){

console.log(d)

console.log(e)

console.log(f)

console.log('------')

g = 10

var h = 11

}

}

console.log(e)

console.log(f)

console.log(g)

console.log(h)

4

5

6

------

5

6

10

11

大括号中都是一个作用域。

Let定义的外部不能访问,只能是内部才能访问。Var块作用域,外部可以见到,普通定义外部也可见。

2、条件分支

if (cond1){

}

else if(cond2){

}

else if (cond3){

}

else{

}

条件False等效

False

Undefined

Null

0

NaN

空字符串(””)

3、switch..case分支语句

switch (expression){

case label_1

statements_1

[break;]

case label_2

statements_2

[break;]

default:

statements_def

[break;]

}

let x = 5

switch (x){

case 0:

console.log('zero')

break;

case 1:

console.log('one')

case 2:

console.log('two')

case 3:

console.log('three')

break;

case 4:

console.log('four')

default:

console.log('other')

break;

}

Switch…case语句都可以协程多分支结构。

4、for循环

//for ([initialExpression];[condition];[increamentExpression])

//{

//  statement

//}

for (let i=0;i<10;i++){

console.log(i)

}

console.log('---')

5、while循环和do….while循环

While (condition)

Statement

条件满足,进入循环,条件为真,继续循环

do

statement

while (condition);

先进入循环,然后判断,为真就继续循环。

let x = 10;

while(x--){

console.log(x);

}

do{

console.log(x);

}while(x++<10)

打印九九乘法表:

for (let x =
1;x<10;x++)

{

line = '';

for(let y = 1;y<=x;y++)

line += `${x}*${y}=${x*y}`;

console.log(line)

}

5、for…in 循环

对象操作语句for…in用来遍历对象的属性

for (variable in object){

statements}

let arr =[10,20,30,40 ]

console.log(arr[2])  
//30

for (let x in arr)

console.log(x)

for (let index in arr)

console.log(`${index}:${arr[index]}`);

for (let i=0;i<arr.length;i++)

console.log(arr[i]);

let obj = {

a:1,

b:'abc',

c:true

};

console.log(obj.a)

console.log(obj['b'])

console.log(obj.d)

console.log('++++++')

for (let x in obj)

console.log(x) 
//属性名

for (let key in obj) 
//返回数组的index

console.log(`${key}:${obj[key]}`);

30

0

1

2

3

0:10

1:20

2:30

3:40

10

20

30

40

1

abc

undefined

++++++

a

b

c

a:1

b:abc

c:true

for in 循环返回的是索引或者key,需要简介访问到值。

数组反正返回的是索引,c风格for循环操作简单。

6、for..of循环

Es6的新语法

let arr =
[1,2,3,4,5]

let obj = {

a;1,

b:'abc',

c:true

}

for (let i of
arr){  //返回数组的元素

console.log(i)

}

for (let i of
obj){  //异常,不可以迭代

console.log(i)

}

For….of不能是迭代对象。

原因是of后面必须是一个迭代器(typeerror)

break 、continue

break结束当前循环

continue中断当前煦暖,直接进入下一次循环。

7、for迭代的差别

function sum(arr){

for (let x in arr){

console.log(x,typeof(x),arr[x]);

}

for (let x of arr){

console.log(x,typeof(x));

}

for (let x =
0;x<arr.length;x++){

console.log(x,typeof(x),arr[x])

}

}

X退出的时候还是会加一或减一。

四、函数及作用域

1、函数表达式

function //函数名(参数列表){

//函数体;

return //返回值;

}

function add(x,y){

return x + y

}

console.log(add(3,5))

匿名函数表达式

const add = function(x,y){

return x + y;

};

console.log(add(4,5))

有名字的函数表达式

const add1 = function fn(x,y){

return x + y;

};

console.log(add1(3,4))

有名字的函数表达式,名字只能内部使用,外部不可见

const add2 = function _add(n){

if (n === 1) return n;

return n+ _add(--n)

};

console.log(add2(5))

函数、匿名函数、函数表达式的差异

函数和匿名函数,本质上是一样的,都是函数对象,不过函数都有自己的标识符,函数名,匿名函数需要的是借助其他的标识符而已。

区别在于,函数会声明提升,函数表达式不会。

console.log(add(3,4))

function add(x,y){     //声明提升

return x + y;

};

console.log(sub(4,5))   //会报出异常的,提示sub未定义

const sub = function(x,y){

return x + y;

};

定义函数的形式:function表达式。(有名字和匿名的),有名字的内部使用等。

声明先做,调用后做。

生成器:

const counter = (function *(){

count = 1

while(1)

yield count ++;

})();

console.log(counter.next())

2、高阶函数

高阶函数:函数作为参数或者返回一个函数。

const counter = function(){

let c = 0;

return function(){

return c++

};

};

const c = counter()

console.log(c())

console.log(c())

map函数的实现

const map = function(arr,fn){

newarr = []

for (i in arr){

newarr[i] = fn(arr[i])

}

return newarr

};

console.log(map([1,2,3,4],function(x){

return ++x

}));

3、箭头函数

const map1 = function(arr,fn){

newarr = []

for (i in arr){

newarr[i] = fn(arr[i])

}

return newarr

}

console.log(map([1,2,3,4],x =>++x))

// console.log(map1([1,2,3,4],x =>++x))

// console.log(map1([1,2,3,4],x=>{return ++x}))

console.log(map1([1,2,3,4],(x)=>{return ++x}))

箭头函数就是匿名函数定义。

去掉关键字function。

一个参数的时候可以省掉括号。无参和多参数的时候必须保留括号。多个参数使用逗号分隔。

有大括号的时候必须有return。

定义是定义的形式。调用必须加括号,因为有优先级的问题,所以调用前面的利用括号抱起来。

箭头函数的返回值:

如果函数体部分有多行,就需要使用{},如果有返回值使用关键字return。

如果只有一行语句,可以同时省略大括号和return。

只要有return语句,就不能省略大括号,有return必须有大括号。

只有一条非return语句,加上大括号,函数就是没有返回值了。

Map函数:

function map(arr,fn){

newarr1 = []

for (i in arr)

newarr1[i] = fn(arr[i])

return newarr1

};

console.log(map([1,2,3,4],function(x){

return ++x;

}));

4、参数

传参是按照位置对应的,没有关键字传参这个属性。写的像的话只是赋值语句。

传参的是只是表达式的值。

数组不解构的话当做一个来进行,解构利用…

缺省值可以进行定义的。位置传参的,缺省值往后写

//位置传参

const add = (x,y)=> x+y;

console.log(add(4,5));

//缺省值

const add1 = (x,y=6)=>x+y;

console.log(add1(4))

//非关键字传参,没有关键字传参,只是表达式

const add2 = (x,y)=>x+y;

console.log(add2(z=1,c=2))

//缺省值不能放在前,否则就是转换为3和undefined相加,加过为NaN

const add3 = (x=1,y)=>x+y;

console.log(add3(3))    //NaN

5、可变参数

(1)args

const sum = function(...args){

let resule = 0;

for (i in args){

resule += args[i]

};

return resule

};

console.log(sum(2,3,4))

可变参数使用…args.

(2)arguments对象

const sum = function(...args){

let resule = 0;

console.log(arguments)

for (i in args){

resule += args[i]

};

return resule

};

console.log(sum(2,3,4))

{ '0': 2, '1': 3, '2': 4 }

所有的参数会保存到一个k,v,键值对的字典里面。

(3)参数解构

const add = function (x,y){

return x+y

}

console.log(add(...[100,200,300,400,500]))   //参数解构,不需要参数一一对应的。

参数解构,不需要和需要的参数一一对应。

6、返回值

Return的返回值:返回的通常是几个参数,返回的是最后一个参数的值。逗号表达式的。

const add1 = (x,y)=>{return x,y}

console.log(add1(1,2))

表达式的值:

逗号表达式,最后一个的值。

返回 的都只是一个单值。

a = (x = 5,y=6,true);

console.log(a)

b = (x=1,y=4,'abc');

console.log(b)

function c() {

return x= 1,y=2,'abc',false;

}

console.log(c());

7、作用域

Function函数定义,是独立的作用域,内部定义的变量外部不可以见到。

//函数作用域

function c(){

a = 1

var b = 2

let c1 = 3

};

c();

console.log(a)

//console.log(b)   //  函数中var定义变量没有方法突破,外界见不到

//console.log(c1)  //   let定义的外界见不到

//块作用域

if (1){

d = 4

var e = 5

let f = 6

}

console.log(d)

console.log(e)       //var 块中定义的才会外界可以见到。

// console.log(f)      //let定义外界始终见不到

var b = 2可以提升声明,可以突破非函数的块作用域。

a = 1 隐士声明不能进行提升声明,

let a=3不能提升声明。

严格模式:使用”use strict”语句放到函数的首行,或者js脚本首行。

function show(i,args){

console.log(i,args)

};

x = 100;

function fn(){

let z = 200;

{

var a = 300;

show(1,x)

t = 'free'

let p = 400;

}

var y = 500

show(2,z)

show(3,x)

show(4,a)

show(5,t)

//show(5.5,p) //异常,let出不来上一个语句块

{

show(6,y);

show(7,a)

show(8,t)

{

show(9,a)

show(10,t)

show(11,z)

}

}

}

fn()

// show(12,y)   //异常,出不了函数的y

show(13,t)

// show(14,a)   //异常,a不能出函数的

show(15,z)  
//变量声明提升,声明了z,但是还没赋值

var z = 10;

五、js对象模型

基于原型的面向对象语言,而不是基于类的面向对象语言。

基于对象事件。

Js是基于原型的语言,只有原型对象的概念,原型对象就是一个模板,新的对象从这个对象模板构建从而获取最初的属性,任何对象在运行时候可以动态的增加属性。任何一个对象都可以作为另一个对象的原型,后者就可以共享前者的属性。

1、定义类

var obj = {

}

var obj1 = new Object();

var obj2 = new Object;

创建的时候必须使用new方法。

function定义的时候 大驼峰。

字面声明方式。

2、es6之前---构造器

function Point(x,y){

this.x = x

this.y = y

this.show = ()=>console.log(1,this,this.x,this.y)

};

console.log(Point)

p1 = new Point(4,5)

console.log(2,p1)

function Point3D(x,y,z){

Point.call(this,x,y);

this.z = z

console.log(3,'Point 3d')

};

console.log(4,Point3D)

p2 = new Point3D(3,4,5)

console.log(5,p2)

p2.show();

[Function: Point]

2 Point { x: 4, y: 5, show: [Function] }

4 [Function: Point3D]

3 'Point 3d'

5 Point3D { x: 3, y: 4, show: [Function], z: 5 }

1 Point3D { x: 3, y: 4, show: [Function], z: 5 } 3 4

(1)定义一个函数(构造器)对象,函数名首字母大写。

(2)This指代是当前实例的本身。定义属性。

(3)使用new和构造器创建一个通用对象。New操作符会将新的对象的this值传递给point3d构造器函数,函数为这个对象创建z属性。

如果不使用new方法,就是普通的函数调用,this不代表实例。

3、es6中的class

(1)class

Es6开始,提供了关键字class,创建对象更加简单、清晰。

(1)利用关键字class,创建的本质上还是一个函数,是特殊的函数。

(2)一个类只能拥有一个名为constructor的构造器方法,如果没有显示定义一个构造方法,,就会默认添加一个constructor方法。

(3)继承使用extends关键字

(4)一个构造器可以使用super关键字来调用父类的构造函数。

(5)类没有私有属性。

class Point{

constructor(x,y){

this.x = x

this.y = y

}

show(){

console.log(this,this.x,this.y)

}

}

let p1 = new Point(10,11)

p1.show()

class Point3D extends Point{

constructor(x,y,z){

super(x,y);

this.z = z

}

}

let p2 = new Point3D(4,5,6)

p2.show()

Point { x: 10, y: 11 } 10 11

Point3D { x: 4, y: 5, z: 6 } 4 5

重新写show方法;

class Point{

constructor(x,y){

this.x = x

this.y = y

}

show(){

console.log(this,this.x,this.y)

}

}

p1 = new Point(1,2)

console.log(p1)

class Point3D extends Point{

constructor(x,y,z){

super(x,y)

this.z= z

}

show(){

console.log(this ,this.x,this.y,this.z)

}

}

p2 = new Point3D(3,4,5)

console.log(p2)

子类中直接重写父类的方法即可,如果需要使用父类的方法,使用super.method()的方式调用。

使用箭头函数修改:

class Point{

constructor(x,y){

this.x = x

this.y = y

this.show = ()=>console.log('point')

}

}

//继承关系

class Point3D extends Point{

constructor (x,y,z){

super(x,y,z)

this.z = z

this.show=()=>console.log('point3d')

}

}

let p2 = new Point3D(3,4,5);

p2.show()

point3d

子类覆盖,最终显示的结果是point

class Point{

constructor(x,y){

this.x = x

this.y = y

this.show =()=>

console.log('point')

}

}

class Point3D extends Point{

constructor(x,y,z){

super(x,y)

this.z = z

//this.show=()=>console.log('Point3d')

}

show(){

console.log('point3d')

}

}

优先使用实例的方法,show方法,使用this的方法。

class Point{

constructor(x,y){

this.x = x

this.y = y

//this.show =()=>

//  console.log('point')

}

show(){

console.log(this,this.x,this.y)

}

}

class Point3D extends Point{

constructor(x,y,z){

super(x,y)

this.z = z

this.show=()=>console.log('Point3d')

}

//show(){

// console.log('point3d')

//}

}

let p1 = new Point3D(2,3,4)

console.log(p1)

p1.show()

属性优先,一定先用属性。优先使用子类的属性。

总结:如果子类和父类使用同一种方式进行定义,子类覆盖父类的。

如果父类使用的属性,子类使用的是方法,那么就是采用父类的属性。

如果子类使用的属性,父类是方法,那么优先使用的是子类的属性方法。。

最终总结,属性优先。。同一类定义的,子类优先

静态属性:

静态方法没有很好的支持的。

(2)静态方法:

在方法名前面加上static,就是静态方法了。

class Add{

constructor(x,y){

this.x = x

this.y = y

}

static show(){

console.log(this.x)  //this是Add   不是Add的实例

}

}

a = new Add(2,3)

console.log(a)

//a.show()    实例不能直接访问静态方法

a.constructor.show()  //实例可以通过constructor构造器方法访问静态方法。

静态方法总结:实例不能直接访问静态方法,实例必须通过constructor方法访问静态方法。

静态成员必须使用类来定义的。

实例是自己的。

4、this的坑

var shcool = {

name : 'abc',

getNameFunc: function(){

console.log(1,this.name)

console.log(2,this)

return function(){

console.log(3,this === global);

return this.name

}

}

};

console.log(4,shcool.getNameFunc()());

this是全局的global的,所以第三行是true。

第四行,This是global的,所哟下面的return this.name没有name属性。

函数调用的时候调用的方式不用,this的对象就是不同的。

函数执行的时候,会开启新的执行上下文环境executioncontext。

创建this属性。

(1)myfunction(1,2,3)普通的函数调用,this指向的是全局对象,全局对象是nodejs的global或者浏览器的window。

(2)myObject.myFunction(1,2,3),对象的方法调用方式,this指向包含该方法的对象。

(3)call和apply方法的调用,都要看第一个参数是谁。

解决this的问题。

1)显式传入

var shcool1 = {

name : 'cde',

getNameFunc1 : function(){

console.log(this.name)

console.log(this);

return function(that){

console.log(this === global);

return that.name;

}

}

}

console.log(shcool1.getNameFunc1()(shcool1))

cde

{ name: 'cde', getNameFunc1: [Function: getNameFunc1] }

true

cde

利用关键字that   传入对象。主动传入对象,避开了this的问题

2)引入call、apply方法。

var shcool2 = {

name : 'asd',

getNameFunc2:function(){

console.log(this.name)

console.log(this);

return function(){

console.log(this === global);

return this.name

}

}

}

console.log(shcool2.getNameFunc2().call(shcool2));

asd

{ name: 'asd', getNameFunc2: [Function: getNameFunc2] }

false

asd

call方法和apply都是函数对象的方法,第一参数都是传入对象引入的。

Apply传其他参数需要数组。

Call传其他参数需要使用可变参数收集。

3)bind方法

var school3 = {

name: 'asdd',

getNameFunc3:function(){

console.log(1,this.name)

console.log(2,this)

return function(){

console.log(3,this === global);

return this.name;

}

}

};

// console.log(school3.getNameFunc3().bind(school3));

var func = school3.getNameFunc3()

console.log(4,func)

var bindfunc = func.bind(school3)

console.log(5,bindfunc)

console.log(6,bindfunc())

1 'asdd'

2 { name: 'asdd', getNameFunc3: [Function: getNameFunc3] }

4 [Function]

5 [Function: bound ]

3 false

6 'asdd'

Apply、call方法,参数不同,调用时候传入this。

。bind方法是为函数绑定this,调用时候直接调用

4)es6引入的箭头函数定义

var school = {

name :'ass',

getNameFunc:function(){

console.log(this)

console.log(this.name)

return ()=>{

console.log(this === global);

return this.name

}

}

};

console.log(school.getNameFunc()())

{ name: 'ass', getNameFunc: [Function: getNameFunc] }

ass

false

ass

class school{

constructor(){

this.name = 'abcd';

}

getNameFunc(){

console.log(this.name)

console.log(this);

return ()=>{

console.log(this === global);

return this.name

}

}

};

console.log(new school().getNameFunc()())

abcd

school { name: 'abcd' }

false

abcd

绑定之后返回一个新的函数。

全局对象。

全局global,

浏览器中叫做window

解决this语法的利用bind。

5、高阶对象、高阶类、或称为Mixin模式

Mixin,混合模式,不用继承就可以复用的技术,主要还是为了解决多重继承的问题,多继承的路径是个大问题。

Js是基于对象的,类和对象都是对象模板。

混合Mixin,指的四将一个对象的全部或者部分拷贝到另一个对象上去,其实就是属性了。

可以将多个类或对象混合成一个类对象。

指的是将一个对象的全部或者部分拷贝到另一个对象上去。

返回的是定义的类。

class Serialization{

constructor(){

console.log('serialization construtor---');

if (typeof(this.stringify) !== 'function'){

throw new ReferenceError('should define stringify')

}

}

}

class Point extends Serialization{

constructor(x,y){

console.log('Point constructor');

super()

this.x = x

this.y = y

}

stringify(){

return 
`<point x=${this.x},y=${this.y}>`

}

}

class Point3d extends Point{

constructor(x,y,z){

super(x,y);

this.z = z

}

stringify(){

return `<point x=${this.x},y=${this.y},z=${this.z}>`

}

}

p = new Point(4,5)

console.log(p.stringify())

p3d = new Point3d(7,8,9)

console.log(p3d.stringify())

Point constructor

serialization construtor---

<point x=4,y=5>

Point constructor

serialization construtor---

<point x=7,y=8,z=9>

高阶对象实现,将类的继承构建成为箭头函数

//普通继承

class A extends Object{};

console.log(A)

//匿名类

const A1 = class{

constructor(x){

this.x = x;

}

}

console.log(A1)

console.log(new A1(100).x)

//匿名继承

const B = class extends Object{

constructor(){

super()

console.log('B constorse')

}

};

console.log(B)

b = new B()

console.log(b)

[Function: A]

[Function: A1]

100

[Function: B]

B constorse

B {}

Point3d调用父类serialization,此类然后调用继承point类。

尽量少的改变原有代码的方式增强注入函数的功能。Extends继承,就是Mixin类,混入的类型。

React框架大量使用了Mixin类。

const x = (Sup) =>{

return class extends Sup{

constructor(){

super();

console.log('c constructor')

}

}

};

const c = Sup =>class extends Sup{

constructor(){

super();

console.log('c constorce')

}

};

cls = c(A)

console.log(cls)

a = new cls();

console.log(a);

const Serialization = Sup => class extends Sup{

constructor(...args){

console.log('serialization constructor--')

super(...args);

if (typeof(this.stringify)!=='function'){

throw new ReferenceError('should define stringify')

}

}

}

class Point{

constructor(x,y){

console.log('point constrouct')

this.x =x

this.y =y

}

}

class Point3d extends Serialization(Point){

constructor(x,y,z){

super(x,y)

this.x = x

}

stringify(){

return `<point3d ${this.x}.${this.y}>`

}

}

let p3d = new Point3d(1,2,3)

console.log(p3d.stringify())

serialization constructor--

point constrouct

<point3d 1.2>

Serialization(point)实际上是匿名函数的调用,返回一个新的类型,point3d继承来自这个新的匿名函数类型,增强了功能。

React框架大量使用了Mixin技术。

六、异常

1、抛出异常

使用throw关键字抛出异常。

使用throw关键字可以抛出任意对象的异常

2、捕获

try…catch语句捕获异常

try….catch…finally ,语句捕获异常,finally保证最终一定执行。

try{

throw 1;

}catch (error){

console.log(error.constructor.name);

}finally{

console.log('end')

}

3、模块化

(1)简介

Js主要是在前端的浏览器中使用,js文件下载缓存到客户端,在浏览器中执行。

简单的表单的本地验证,漂浮广告。

服务器端使用ASP、JSP等动态网页技术,将东外生成数据嵌入一个HTML模板中,里面夹杂着js后使用<script>标签,返回给浏览器端。Js只是简单的函数和语句的组合。

2005年后,google大量使用ajax技术,可以一步请求服务器端数据,前端交互的巨大变化,

前端功能需要越来越多,代码多,js文件的增多。全局变量污染,函数名冲突,无法表达脚本之间的依赖关系,用脚本文件先后加载实现的,需要模块化的出现。

2008年v8引擎,2009年nodejs,支持服务器端JS编程,没有模块化是不可以的。

之后产生了commonjs规范,

Common规范,使用全局 require函数导入模块,使用exports导出变量。

AMD(asynchronous module
definition)异步模块定义:使用异步方式加载模块,模块的加载不影响他后面语句的执行,所有依赖此模块的语句,都需要定义在一个回调函数里面,回调函数中使用模块的变量和函数,模块加载完成后,回调函数才会执行,就可以安全的使用模块的资源,就是AMD/requires。AMD虽然是异步,但是会预先加载和执行。

CMD(common module definition),使用seajs,作者是淘宝前端玉伯,兼容并包解决了requirejs的问题。Cmd推崇as lazy as possible,尽可能的懒加载。

(2)ES6模块化

Import语句,导入另一个模块导出的绑定。

Export语句,从模块中导入函数、对象、值,供其他模块import导入引用。

(3)导出

建立模块的目录src,此目录下建立mode.js,  内容是导入和导入模块的代买

export default function a(){   //导出缺省的

console.log('a is t1')

};

a();

//导出函数

Export function foo(){

Console.log(‘foo function’);

}

//导出常量

Export const consta = ‘aaa’

(4)导入

import a from './t1-1'

a();

vs code可以很好的语法支持,但是运行环境和v8引擎,不能很好的支持模块化语法。

4、编译器

转译从一种语言代码转换到另一语言代码,当然也可以从高版本转译到低版本的支持语句。

由于js存在不同的版本,不同浏览器兼容问题,使用transpiler转译工具解决。

Babel

开发中比较新的es6的语法,通过转移器指定Wie特定的某些版本代码。

官网:http://babeljs.io/

function* inc()

{

let i = 0;

let j = 2;

while(true){

yield i++

if (!j--)return  100;

}

}

let gen = inc()

for (let i = 0 ;i<10;i++)

console.log(gen.next());

转化结果:

"use strict";

var _marked = /*#__PURE__*/regeneratorRuntime.mark(inc);

function inc() {

var i, j;

return regeneratorRuntime.wrap(function
inc$(_context) {

while (1) {

switch (_context.prev
= _context.next) {

case 0:

i = 0;

j = 2;

case 2:

if (!true) {

_context.next = 9;

break;

}

_context.next
= 5;

return i++;

case 5:

if (j--) {

_context.next = 7;

break;

}

return
_context.abrupt("return", 100);

case 7:

_context.next
= 2;

break;

case 9:

case
"end":

return _context.stop();

}

}

}, _marked, this);

}

var gen = inc();

for (var i = 0; i < 10; i++) {

console.log(gen.next());

}

缺省必须写在外头,函数和类。

5、预设

有presets,预设的一些

6、转义安装配置****

1)新建文件夹src 和lib

将导入和导出文件放入src文件中。

目录下打开shell  敲入命令npm init 生成package.json文件。

2)设置镜像

.npmrc文件

echo
"registry=https://registry.npm.taobao.org" > .npmrc

3)安装

项目根目录下。

$
npm install babel-core babel-cli 
--save-dev

安装完成后,会在项目根目录下出现node_moudles

4)修改package.json文件

"name": "trans",

"version": "1.0.0",

"description": "trans test",

"main": "index.js",

"directories": {

"lib": "lib"

},

"scripts": {

"build": "babel src -d lib"

},

"author": "",

"license": "ISC",

"devDependencies": {

"babel-cli": "^6.26.0",

"babel-core": "^6.26.3"

}

}

替换为这样的。

"build": "babel src -d
lib"   的意思是从src目录转义后输出到lib目录。

7、准备目录

项目根目录下创建src和lib目录。

Src是源码目录。

Lib是目标目录

8、配置babel和安装依赖

touch
.babelrc  创建此文件,内容如下 
.babelrc没有后缀

{

“presets”:["env"]

}

Env是当前环境自动选择。

安装依赖

npm
install babel-preset-env  -save-dev

9、准备js文件

export default function a(){

console.log('a is t1.a()')

};

export function b(){

console.log('t1.b()')

};

export 
let c = 100;

export 
var d = 200;

export const e = 300;

import a from './mod'

a();

在项目根目录下:

$
npm run build

>
trans@1.0.0 build C:\Users\WCL\Documents\trans    //

>
babel src -d lib                         
//

src\index.js
-> lib\index.js       //

src\mod.js
-> lib\mod.js           //

两个文件被转译。

运行文件:

$
node lib/index.js

a
is t1.a()

使用babel转译工具转译js非常流行。

可以提高开发效率,兼容性交给转移器处理。

lib
下的index转译后的文件格式:

'use
strict';

var
_mod = require('./mod');

var
_mod2 = _interopRequireDefault(_mod);

function
_interopRequireDefault(obj) { return obj && obj.__esModule ? obj : {
default: obj }; }

(0,
_mod2.default)();

Mod的文件;

'use
strict';

Object.defineProperty(exports,
"__esModule", {

value: true

});

exports.default
= a;

exports.b
= b;

//
function a(){

//     console.log('test')

//
}

//
export default

function
a() {

console.log('a is t1.a()');

};

function
b() {

console.log('t1.b()');

};

var
c = exports.c = 100;

var
d = exports.d = 200;

var
e = exports.e = 300;

10、导入导出

导出文件代码全部在src下的mod.js文件,导入文件都在index.js文件下

export default function a(){

console.log('a is t1')

};

//缺省导出,匿名函数

export default function(){

console.log('default export function')

}

a();

//缺省导入

import defaultFunc from './mod'

defaultFunc();

缺省导入的时候,可以自己重新命名,不需要和缺省导出 的时候一致。

缺省导入,不需要在import后使用花括号。

/**

* 导出举例

*/

//缺省导出类

export default class{

constructor(x){

this.x = x;

}

show(){

console.log(this.x)

}

}

//命名导出函数

export function foo(){

console.log('regular foo()')

}

//函数定义

function bar(){

console.log('regular bar()')

}

//变量常量定义

let x= 100;

var b = 200;

const z=300;

export {bar,x ,y,z};

/**

* 导入

*/

import defaluts,{foo,bar,x,y,z as CONST_c}from './mod'

foo();

bar();

console.log(x);

console.log(y);

console.log(CONST_c);

new defaluts(100).show();

导入所有的导出,会使用一个新的名词空间,使用名词空间可以避免冲突。

Import * as newmod from ‘./mod’;

Newmod.foo();

Newmod.bar();

New newmod.default(200).show();

七、解构

Js的参数解构参考文档;
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

1、列表解构

var a = [1,2,3,4,5,6]

var b = [...a,7,8,9,0]

console.log(b)

[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 ]

2、参数解构

//参数

function f(x,y,z){

console.log(x+y+z)

}

var args = [1,2,3,4]

f(...args);

结果为6,按照位置一一对应参数,多了的参数不用管,少的参数直接为undefined。

3、数组

解构的时候也是利用数组进行接数值。

//数组解构

const arr = [1,2,3]

let [x,y,z] = arr

console.log(x,y,z)

//丢弃元素

const [,b,] = arr

console.log(b)

//少于数组元素

const[c,d] = arr

console.log(c,d)

//多余数组元素

const[e,f,g,h] = arr

console.log(e,f,g,h)

//可变变量

const[i,...args] = arr

console.log(i)

console.log(args)    //可变的参数args收集多个,利用的数数组

//支持默认参数

const[k=20,l=34,,,p=222] = arr

console.log(k,l,p)       //没有的话默认使用默认参数,有的话优先使用数组的元素

数组,可变参数的收集就是数组。

可变参数不能给缺省值。

可以丢弃,参数可以多,可以少,少的全部使用undefined。

4、对象解构

const obj = {

a:100,

b:200,

c:300

};

//let {x,y,z} = obj;

//console.log(x,y,z) //undefined undefined undefined  名字要与之对应的。

let {a,b,c} = obj

console.log(a,b,c)    //名字是key的名字, 100,200,300

//let {a:x,b:y,c:z} = obj  //设置别名,

//console.log(a,b,c)

//console.log(x,y,z)    //利用别名打印出消息

//缺省值

let {a:x,b:y,c:z='abc'} = obj

console.log(x,y,z)

结构的时候,提供对象的属性名(key),可以根据属性名找到对应的值,
没有找到对应的值使用缺省值,没有缺省值的话就是undefined,也可以采用别名的方式,把key改成别名,通过别名进行访问属性的值。

别名:

Obj解构。

5、复杂结构

(1)嵌套的数组:

const arr = [1,[2,3],4]

const [a,[b,c],d] = arr

console.log(a,b,c,d)    //1 2 3 4

const [e,f] = arr

console.log(e,f)  //嵌套的可以接一个数组,作为外层的一个元素。

//1 [ 2, 3 ]

let [g,h,i,j=19] = arr

console.log(g,h,i,j)    //1 [ 2, 3 ] 4
19

var [k,...l] = arr

console.log(k,l)   //1 [ [ 2, 3 ],
4 ]

(2)对象

var atim = {

title:'secation',

tranliat:[

{

local:'def',

local_tart:[],

last_dict:'2222222',

url:'/def/ac/asd/ffff',

titile:'java'

}

],

url:'wwwww.xxxxxx.com'

}

// let {titile,tranliat,url} = atim

// console.log(titile,tranliat,url)

let{titile,tranliat:[{local}],url} = atim

console.log(local)

还是利用属性名(key)查询所对应的值。

6、数组的操作

方法

描述

Push(…items)

尾部增加多个元素

Pop()

移除最后一个元素,并返回

Map

引入处理函数中来处理数组中的每一个元素,返回新的数组

Filter

引入处理函数处理数组中的每一个元素,此处理函数返回true的元素保留,否则该元素被过滤掉了,保留的元素构成新的数组返回。

Foreach

迭代所有元素,无返回值

const arr = [1,2,3,4,5,6]

arr.push(6,7,8,9,0)

console.log(arr)

arr.pop()

console.log(arr)

const newarr = arr.map(x=>x*x)

console.log(newarr)

let newarr1 = arr.filter(x=>x%2==0)

console.log(newarr1)

let newarr2 = arr.forEach(x=>x+1)

console.log(newarr2)  //没有新的返回值

练习题:

s = Math.sqrt(10)

const arr = [1,2,3,4,5]

//console.log(arr.filter(x=>x%2==0 && x>3).map(x=>x*x))

//console.log(arr.filter(x=>x>s && x%2==0).map(x=>x*x))

let newarr = []

arr.forEach(x=>{

if (x>s && x%2==0) newarr.push(x*x)

})

console.log(newarr)

map返回每次都会返回一个新的值。

filter过滤解决,返回一个新的。

foreach迭代元素,没有任何返回值,返回新的结果是采用新的数组。

数据算数的问题:能过滤先过滤,先过滤在进行计算。

7、对象操作

Object静态方法

描述信息

Object.keys(obj)

Es5开始,返回所有的key

Object.values(obj)

返回所有值

Object.entries(obj)

返回所有值

Object.assign(target,…sources)

使用多个source对象,来填充target对象,返回target对象

const obj = {

a:100,

b:200,

c:300

};

console.log(Object.keys(obj));

console.log(Object.values(obj))

console.log(Object.entries(obj))  //二元数组

var atim = {

title:'secation',

tranliat:[

{

local:'def',

local_tart:[],

last_dict:'2222222',

url:'/def/ac/asd/ffff',

titile:'java'

}

],

url:'wwwww.xxxxxx.com'

}

var copy = Object.assign(

{},atim,{

name:'xxxxxx',url:'www.xxxx.com'

},{tranliat:null}

)

console.log(copy)

{ title: 'secation',

tranliat: null,

url: 'www.xxxx.com',

name: 'xxxxxx' }

属性和值的动态增加和替换等,返回新的。

八、promise

1、概念

Promise对象用于一个异步操作的最终完成(包括成功和失败,)即结果值的表示。

处理异步请求,之所以叫做promise,就是承诺,如果成功怎么处理,失败怎么处理。

语法格式:

new promise(

//executor函数

function(resolve,reject){….});

(1)executor

是一个带有resolve和reject两个参数的函数,

Executor函数在promise构造函数执行同步执行,被传递resolve和reject函数(execu函数在promise构造函数返回前被调用)

Executor内部通常会执行一些异步操作,一旦成功,可以调用resolve函数将promise状态改成fulfilled即完成,或者在发生错误的时候将其状态改为rejected失败

如果在executor函数中抛出一个错误,那么该promise状态为rejected,executo函数的返回值被忽略。

Executor中,resolve或者reject函数只能执行一个。

(2)promise状态

Pending初始状态,不是成功和失败的状态

Fulfilled意味成功

Rejected,意味着失败了。

(3)promise.then(onfulfilled,Onrejected)

参数是两个函数,根据promise的状态来调节不同的函数,fulfilled走的是onfulfiled,reject走的Onrejected。Then得返回值是一个新的promise对象,调用任何一个参数后,其返回值会被新的promise对象来resolve向后传递,

var myPromise = new Promise((resolve,reject)=>{

resolve('ok')

console.log('======')

reject('no') 
//不会执行到

})

console.log(myPromise);

myPromise.then(

(value)=>console.log(1,myPromise,value),

(reason)=>console.log(2,myPromise,reason)

)

======

Promise { 'ok' }

1 Promise { 'ok' } 'ok'

(4)catch(onrejected)

为当前promise对象添加一个拒绝回调,返回一个新的promise对象,onrejected函数调用其返回值会被新的promise对象用来resolve。

var myPromise = new Promise((resolve,reject)=>{

resolve('ok')

console.log('======')

reject('no')

})

console.log(myPromise);

//链式处理

myPromise.then(

/**

成功就会显示结果

*/

(value)=>console.log(1,myPromise,value),

/**

* 失败就显示原因

*/

(reason)=>console.log(2,myPromise,reason)

).then(

function(v){

console.log(2.5,v);

return Promise.reject(v+'++++++')

}

).catch(reason=>{

console.log(3,reason)

return Promise.resolve(reason)

})

(5)异步调用实例

function runAsync(){

return new Promise(function(resolve,reject){

setTimeout(function(){

console.log('do sth...')

resolve('ok...')

},3000);

})

}

runAsync().then(value=>{

console.log(value)

return Promise.reject(value+'*')

}).catch(reason=>{

console.log(reason)

return Promise.resolve(reason+'*')

}).then(value=>{

console.log(value)

console.log('end')

})

console.log('----fin-----')

----fin-----

do sth...

ok...

ok...*

ok...**

end

不会阻塞执行,按照顺序执行,顺序执行后按照要求进行调度处理。

严格模式:定义常量时候必须使用var这些等。