已更新目前所学内容
let 注:
es6没有对es5有任何修改,全部新增
在es5中定义变量:var
function
允许先使用再定义
1 2 console .log(a) var a = 10
let的特点
使用let定义的变量只在块级中有效
1 2 3 4 { let a = 10 console .log(a) }
不存在变量的提升(先定义,在使用)
let定义的变量不允许重复定义
变量的作用域 es5中,变量有两种:全局变量,局部变量
es6 全局变量,局部变量,块级变量
1 2 3 4 5 6 7 8 9 for (var i=0 ;i<5 ;i++){ console .log(5 ) } console .log(i)for (let j = 0 ; j < 5 ; j++) { console .log(j) }
闭包问题 1 2 3 4 5 6 7 8 9 10 11 12 var lis = document .querySelectorAll('li' )for (let i =0 ;i<lis.length;i++){ lis[i].onclick = function ( ) { alert(i) } }
1 2 注意:变量是let声明的,当前的i只在本轮循环有效,所以每一次循环的其实都是一个新的变量。你可能会问,如果每一轮循环的变量i都是重新声明的,那它怎么知道上一轮循环的值,从而计算出本轮循环的值?这是因为JavaScript引擎内部会记住上一轮循环的值,初始化本轮的变量i时,就在上一轮循环的基础上进行计算。 另外,for循环还有一个特别之处,就是设置循环变量的哪部分是一个父作用域,而循环体内部是一个单独的子作用域
暂时性死区 1 2 3 4 5 6 7 8 9 if (true ){ console .log(typeof a) var a = 1 } if (true ){ console .log(typeof a) let a = 1 }
let访问不到a
!!!变量一定要定义再使用
循环中的块级绑定 1 2 3 4 5 for (var i= 0 ;i<10 ;i++){ process[item[i]] } console .log(i)
1 2 3 4 5 6 for (let j=0 ;j<10 ;j++){ progress[item[j]]; }
let定义变量好处(总结)
不存在变量提升
let定义的变量不会成为window对象的属性
let不允许重复定义变量
let例子 闭包解决:
1 2 3 4 5 6 7 8 9 10 11 var arr = []for (var i = 0 ; i < 5 ; i++) { arr.push((function (j ) { return function ( ) { console .log(j) } })(i)) } console .log(arr[4 ]())
let定义:
1 2 3 4 5 6 7 arr0 = [] for (let j=0 ;j<5 ;j++){ arr0.push(function ( ) { console .log(j) }) } console .log(arr0[4 ]())
const 基本用法
声明一个只读的常量(不能被修改的量)
其他用法与let一致
注意:为了与一般的变量进行区分,常量的名称一般为大写 const定义的常量必须在定义的时候初始化(赋值)
1 2 3 4 const arr = [100 ,200 ,300 ]arr[0 ]='hello' console .log(arr)
1 2 3 4 5 6 7 8 9 const arr = [1 ,2 ,3 ,4 ]const arr0 = Object .freeze([2 ,3 ,4 ,5 ]) console .log(arr0)arr0[0 ]='hello world' console .log(arr0)
上图针对于对象也适用
总结 顶层对象,在浏览器环境指的是window对象,在Node指的是global对象。ES6之中,顶层对象的属性与全局变量是等价的。
顶层对象的属性与全局变量挂钩,被认为是JavaScript语言最大的设计败笔之一。这样的几个很大的问题,首先是没法在编译时报出变量未声明的错误,只有运行时才能知道(因为全局变量坑能是顶层对象的属性造成的,而属性的创造是动态的,其次,程序员很不容易不知不觉地就创造除了全局变量),最后,顶层对象的属性是可以到处读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合法的。
ES6巍峨改变这一观点,一方面规定,为了保证兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性,另一方面规定,let命令,const命令,class命令声明的全局变量,不属于顶层对象的属性。也就是说,从ES6开始,全局变量将逐步与顶层对象的属性脱钩。
数组的解构 结构——–模式匹配
对数组的解构: 1 2 let arr = [10 ,20 ,30 ]let [a,b,c]=arr
完全结构: 1 2 let [[a,b],c] = [[10 ,20 ],30 ]let [a1,a2]= [[10 ,20 ],30 ]
不完全结构: 1 2 let [a,b]=[100 ]let [c,d,e] = [1 ,2 ,34 ,5 ,56 ,6 ]
等号左右两边模式不一致
如果等号的右边的不是数组(或者可以严格地说,不是可遍历的结构),那么将会报错。
默认值 1 2 3 4 5 6 7 8 let [a,b=0 ]=[10 ]let [foo = true ] = []foo let [x,y='b' ] = ['a' ]
对象和字符串解构 字符串:
1 2 let arr = ['hello' ,'world' ,'yes' ,'ok' ]let [a,b,c,d]= arr
对象:对象的解构要保证:变量名称与属性名称一致
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必学与属性名相同
完全结构:
1 2 3 4 5 6 7 8 let obj ={ name:'xiaowu' , age:22 , addr:'大学城' } let {a,b} = obj let {name,age,addr}= obj
不完全解构:
1 2 3 4 5 let {color,age} ={ name: 'xiaowu' , age: 22 color: 'skyblue' }
简化对象的属性名称:
1 2 3 4 5 6 7 8 9 10 11 12 let data = { url: 'http://www.vchamps.cn' , myProductName;'整理笔记太难了' , price: '$22' , sale: '2222' } let {myProductName} = datalet {myProductName :mName} = dataconsole .log(mName)console .log(myProductName)
字符串解构赋值 完全解构
1 2 3 let str = 'hello' let [a,b,c,d,e]=strconsole .log(a,b,c,d,e)
函数的参数解构 1 2 3 4 5 function add ([x,y] ) { console .log(x+y) } add([10 ,20 ])
1 2 3 4 5 6 7 8 9 10 function fn ({name,age}={} ) { console .log(name.age) } fn({ name: 'jack' , age:20 , addr: '大学城' })
1 2 3 4 function add ([x=0 ,y=0 ] = [] ) { console .log(x+y) } add()
用途 1.交换变量的值
1 2 3 4 5 6 7 let a =3 ,b =5 a = a+b b = a-b a = a-b
2.从函数返回多个值
1 2 3 4 5 6 function fn ( ) { return [3 ,5 ,7 ] } let [a,b,c]= fn()
3.函数参数的定义
1 2 3 4 5 function add ([x=0 ,y=0 ] = [] ) { console .log(x+y) } add([10 ,30 ])
4.提取json数据
1 2 3 4 5 6 7 let jsonData = { id:42 , status: 'OK' , data: [867 ,5360 ] } let {id,status,data :number} = jsonDataconsole .log(id,status,number)
函数的扩展 函数参数默认值 基本语法:
在es5中,不能为函数的参数指定默认值
1 2 3 4 5 6 7 8 9 10 function add (x,y ) { if (y == undefined && x ! = undefined ){ y=0 }else if (x == undefined ){ x = y =0 } } add(10 ,20 ) add(10 ) add()
在ES6中支持为函数的参数设定默认值
1 2 3 function add (x=0 ,y=0 ) { console .log(x+y) }
rest参数 es5中:实现求和(没有rest参数)有arguments
1 2 3 4 5 6 7 8 9 10 11 function getSum ( ) { var sum = 0 console .log(arguments ) for (var i=0 ;i<arguments .length;i++){ sum += arguments [i] } console .log(sum) } getSum()
es6中:rest参数
ES6引入rest参数(形式为.....变量名),用于获取函数多余的参数,这样就不需要使用arguments对象了,rest参数搭配的变量是一个数组,该变量将多余的参数放入数组中
1 2 3 4 5 6 7 8 9 10 function getSum (...params ) { var sum = 0 ; params.forEach(function (item ) { sum += item }) console .log(sum) } getSum(20 ,30 ,40 )
!! rest参数注意点
rest参数必须为函数参数的最后一个参数
1 2 3 4 5 6 7 8 9 function sum (num,..rest ) { console .log(rest) console .log(num) }
函数复习 1 2 3 4 let fn = function (x ) { console .log('java or c?' ) return x }
箭头函数 在ES6中针对含税, =>代表函数
1 2 3 4 5 6 var fn = function (a ) { return a } let fn = a => a
箭头函数使用规则
若函数没有参数,则不能省略()
①若函数体只有一句代码,则可以省略{},
若不是return语句,但是需要注意在语句前添加void;
若是return语句,则直接省略return即可
②若函数体有多条语句组成,咋不能省略{ }
有参数函数
①有一个参数,可以省略() 其余和以上类似
②多个参数,不能省略( )
③若函数体只有一句return语句,且返回值为对象,则使用()包裹,若返回值为数组则不需要处理
1.无参函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 let fn1 = function ( ) { console .log('hello world' ) } let fn1 = () => void console .log('hello world' ) let fn2 = function ( ) { return 'hello world' } let fn2 = () => 'hello world' let fn3 = function ( ) { conssole.log('hello' ) conssole.log('javascript' ) conssole.log('python' ) } let fn3 = () => { conssole.log('hello' ) conssole.log('javascript' ) conssole.log('python' ) }
有参函数
1 2 3 4 5 6 7 8 9 10 let fn4 = function (x ) { console .log('hello' ) } let fn4 = x => void console .log('hello' )let fn4 = x => 'hello' let fn4 = x => { console .log('hello' ) return 'hello' }
1 2 3 4 5 6 7 8 9 let fn5 = function (x,y ) { console .log(x) console .log(x+y) } let fn5 = (x,y )=> { console .log(x) console .log(x+y) }
示例:
1 2 3 4 5 6 7 8 9 10 let fn = function (name,age ) { return { name: name, age: age } } let fn = (name,age )=> ({name :name,age :age})
特殊情况:
1 2 3 4 5 6 let fn = function (x ) { name:x } let fn = x => {name :x} console .log(fn('小黑' ))
被定义为此种函数,返回值无
1 2 3 4 5 6 7 8 9 10 11 12 13 tag:for (let i =0 ;i<3 ;i++){ for (let j=0 ;j<4 ;j++){ console .log('i=' +i+"j=" +j) if (i==1 ){ break } if (p==1 ){ break tag } } }
箭头函数和解构 数组解构:
1 2 3 4 5 6 7 let fn = function ([a,b,c] ) { console .log(a+b+c) } let fn = ([a,b,c] )=> { console .log(a+b+c) } fn([10 ,20 ,30 ])
1 2 3 4 5 6 7 let fn = function ({name,age} ) { console .log(name,age) } let fn = ({name,age} )=> void console .log(name,age)fn({name :'小黑' ,age :22 })
举例:
1 2 3 4 let fn = r => Math .PI*r*rlet fn1 = (w,h ) => w*h
箭头函数注意事项 1 2 3 4 5 6 箭头函数使用有几个注意事项 (1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象 (2)不可以当做构造函数,也就是说,不可以使用new命令,否则就会抛出一个错误 (3)不可以使用arguments对象,该对象在函数体内不存在,如果要使用,可以使用rest参数代替 (4)不可以使用yield命令,因此箭头函数不能用作generator函数 上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的
(1)this的问题:
在普通函数中,this指向调用者
在肩头函数内,this指向声明时的对象
构造函数不能使用箭头函数
原型中也不能使用箭头函数
在箭头函数内部不能使用arguments
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let obj = { name:'小黑' , aga:22 , say: function ( ) { console .log(this ) }, sayHello:function ( ) { setTimeout(() => { conssole.log(this ) },1000 ) } }
箭头函数与回调函数 1 2 3 4 5 6 7 8 const arr = [100 ,200 ,300 ,10 ]arr.forEach(function (item ) { console ,log(item) }) arr.forEach(item => { console .log(item) })
1 2 3 4 5 6 let arr0 = arr.map(function (item ) { return item*2 }) let arro = arr.map(item => item*2 )
字符串的扩展 字符串的遍历器接口 es5遍历:
1 2 3 4 5 6 7 8 9 let var = 'hello' for (var i=0 ;i<str.length;i++){ console .log(i,str[i]) } for (var i in str){ console .log(i,str[i]) }
使用for ….of遍历字符串:
1 2 3 4 for (let i of str){ console .log(i) }
字符串中新增的方法
includes() 判断是否包含指定字符串 布尔类型
startsWith 是否以指定字符串开头 布尔类型
endwith 是否以指定字符串结尾 布尔类型
repeat 返回一个新字符串,表示该字符串重复n次
padStart(),padEnd() es2017引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart用于头部补全,padEnd用于尾部补全 padEnd 在末尾追加内容 —-到指定的长度,padStart 在开头追加内容 —–到指定长度
es5:
1 2 3 4 5 6 7 8 let str = '你好。非常好,very good' let src = 'images/xxx1.jpg' if (str.indexOf('李时珍' )== -1 ) { alert('没有这个字符串' ) }else { alert('有这个' ) }
1 2 3 4 5 6 7 if (src.indexOf('1.jpg' ) != -1 ) { alert('包含' ) } if (src.includes('1.jpg' )){ alert('包含' ) }
1 2 3 4 5 6 7 8 9 10 let str = 'hello world' if (str.startsWith('hell' )){ str += '.你好' } if (str.endsWith('你好' )){ str += '你长得真丑' }
padstart(),padend()例子:
1 2 3 4 5 6 7 8 9 10 11 12 let addZero = num => { if (num < 10 ) { return '0' + num } return num } let addZero1 = num => num.padStart(2 ,'0' )addZero1('1' )
模板字符串: es5字符串拼接:
1 2 3 4 5 6 let obj = { name: '小黑' , age: 20 , addr: '大学城' } let str = '姓名:' +obj.name + ',年龄:' +obj.age+',地址为:' +obj.addr
ES6中的字符串模板语法:
模板字符串< template string)是增强版的字符串,用反引号(“)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。模板字符串中嵌入变量,需要将变量名写在${ }之中。
1 2 3 4 let fn = x => xlet x = 90 let str = `输入变量x,输出结果为:${fn(x)} ` console .log(str)
对象扩展 如何定义对象:
ES5中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var obj = new Object ()obj.name = '小黑' obj.age = 22 obj.say = function ( ) { console .log('你好 小黑!!!' ) } var obj1 = { name: '小黑' , age: 22 , say:function ( ) { console .log('你好 小黑!!!' ) } }
注:字面量的形式,一次性只能创建一个对象
ES6中,针对这种方案(属性名与值对应的变量名是一致的,可以省略变量名)
1 2 3 4 5 6 7 let obj1 = { name, age, say:function ( ) { console .log('dawdaw' ) } }
使用前提,已经定义过当前属性名的变量值
在对象内部可以简写函数
1 2 3 4 5 6 7 8 var name = '小黑' ,age = 22 let obj1 = { name, age, say(){ console .log('dad' ) } }
举例:
1 2 3 4 5 6 7 8 let fn = (x,y ) => { return { x:x, y:y } }
class 类 1 2 3 4 5 6 7 8 9 10 11 function Person (name,age ) { this .name = name, this .age = age } Person.prototype.say = function ( ) { console .log(`${this .name} 在说话00` ) } let p = new Person('小黑' ,22 )p.say()
ES6提供了更接近传统语言的写法,引入了Class (类)这个概念,作为对象的模板。通过class关键字,可以定义类。 基本上,ES6的class可以看作只是一一个语法糖,它的绝大部分功能, ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Perso { constructor (name,age){ this .name = name, this .age = age console .log('执行了' ) } say(){ console .log(this .name+"dadad" ) } } let p = Perso('小黑' ,22 )
基本语法 constructor 1 2 3 4 5 6 7 8 9 constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor 方法,如 果没有显式定义,-个空的constructor方法会被默认添加。 Class Point {} /等同于 class Point { constructor() {} } constructor方法默认返回实例对象(即this) , 完全可以指定返回另外一个对象。 类必须使用new调用,否则会报错。这是它跟普通构造函数的一-个主要区别,后者不用new也可以执行。
class表达式 1 2 3 4 5 6 7 与函数一样,类也可以使用表达式的形式定义。 const MyClass = class Me { getClassName() { return Me .name } }; 上面代码使用表达式定义了一个类。需要注意的是,这个类的名字是MyClass而不是Me, Me只在Class的内部代码可用,指代当前类。.
class注意事项 *ES5中,构造函数可以有变量提升
ES6 中,类不存在变量提升,先定义在使用**
class的静态方法 1 2 3 4 类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会 被实例继承,而是直接通过类来调用,这就称为“静态方法”。 如果静态方法包含this关键字,这个this指的是类,而不是实例。 父类的静态方法,可以被子类继承。.
静态方法只能对象自身调用,不能实例化调用
例子:
1 2 3 4 5 6 7 8 class Tool { static config(){ return { host: '127.0.0.1' , port: '27017' , } } }
set和get访问器 1 2 3 4 5 6 7 8 9 10 11 与ES5一样,在“类”的内部可以使用get和set关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。 Class MyClass { constructor() { } get prop() { return” getter' ; } set prop(value) { console.log('setter: ' +value); }} let inst = new MyClass();
setter访问器 :弱对属性进行了设置,则会执行getter访问器
getter访问器:若取出当前属性的值,则会执行setter访问器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Person { constructor (id,name,age){ this .id =id, this .name = name, this .age = age } set age(myAge){ console .log('执行了set' ) this ._age = myAge } get age(){ console .log('执行了 get' ) return this ._age } } let p = new Person(132123 ,'小黑' ,22 )p.age = 80 console .log(p.age)
继承 ES5完成继承:
1 2 3 4 5 6 7 8 for (var i in Person. prototype){ Student. prototype[i ]=Person. prototype[i]; } Student.prototype = new Person()
ES6中继承:
继承是单向的,父类只有一个,子类可以有很多个
父类:基类
子类:派生类
1 2 3 4 5 6 Class Point {} Class ColorPoint extends Point {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Person { constructor (name,age){ this .name = name, this .age = age } } class Student extends Person { constructor (name,age) { super (name,age) this .no = no } }
JS异常处理 1 2 3 4 5 6 7 8 9 10 11 12 JavaScript try-catch语句(错误处理) 错误处理在处理程序设计中的重要性是毋庸置疑的,任何有影响力的veb应用程序都需要-套完善的错误处理机制。当然, 大多数佼佼者确实做到了这一-点,但通常只有服务器端应用程序才能做到如此。实际上,服务器端团队往往会在错误处理机制 上投入较大精力,通常要考虑按照类型、频率,或者其他重要的标准对错误进行分类。这样一来,开发人员就能够理解用户在 使用简单数据库查询或者报告生成脚本时,应用程序可能会出现的问题。 虽然客户端应用程序的错误处理也同样重要,但真正受到重视,还是最近几年的事。实际上,我们要面对这样-一个不争的 事实:使用web的绝大多数人都不是技术高手,其中甚至很多人根本就不明白浏览器到底是什么,更不用说让他们说喜欢哪一 个了。每个浏览器在发生JavaScript错误时的行为都或多或少有一些差异。 有的会显示小图标,有的则什么动静都没有,浏览 器对JavaScript错误的这些默认行为对最终用户而言,毫无规律可循。最理想的情况下,用户遇到错误搞不清为什么,他们会 再试着重做一次,最糟糕的情况下,用户会恼羞成怒,-去不复返了。良好的错误处理机制可以让用户及时得到提醒,知道到 底发生了什么事,因而不会惊慌失措。为此,作为开发人员,我们必须理解在处理JavaScript错误的时候,都有哪些手段和工 具可以利用。
try…..catch
1 2 3 4 5 6 7 8 try { console .log('try 语句' ) fn() console .log('fn()执行了' ) } catch (error) { console .log(error) }
finally子句:
虽然在try-catch语句中是可选的,但finally子句- -经使用,其代码无论如何都会执行。换句话说,try 语句块中的代码全部正常执行,finally 子句会执行;如果因为出错而执行了catch语句块,finally 子句照样还会执行。只要代码中包含finally 子句,则无论try或catch语句块中包含什么样的代码–甚 至returm语句,都不会阻止finally子句的执行。来看下面这个函 数:
1 2 3 4 5 6 7 8 9 10 try { let arr = [13 ,13 ,123 ,123 ,12 ,31 ,23 ] arr.forEach(item => { console .log(item + i) }) } catch (error) { console .log('发现错误' ,error) } finally { console .log('天下第一' ) }
错误类型:
Error
EvalError
RangeError
ReferenceError
SyntaxError
TypeError
URIError
1 2 3 4 5 6 其中, Error是基类型,其他错误类型都继承自该类型,因此,所有错误类型共享了- -组相同的属性(错误对象中的方法全是默 认的对象方法》。Error类型的错误很少见,如果有也是浏览器抛出的;这个基类型的主要目的是供开发人员抛出自定义错误。 EvalError.类型的错误是在使用eal()函数而发生异常时抛出。ECMA-262中对这个错误有如下描述:“表示全局函数eval的 使用方式与其定义不相行。"除此之外,并没有救到底什么情况会引发这种错误给出说明。在实际开发中碰到这种错误的可能性 并不大。 RangeError.类型的错误会在数值超出相应范围时触发。例如,在定义数组时,如果指定了数组不支持的项数(如-20或Number.MAX_ _VALUE) ,就会触发这种错误。
1 2 3 4 5 6 7 当try-catch语句中发生错误时,浏览器会认为错误已经被处理了。因而不会通过前面讨论的机制记录或报告错误。对于那些不要求用户懂技术,也不需要用户理解错误的Web应用程序,这应该说是个理想的结果。不过, try-catch 能够让我们实现自己的错误处理机制。 使用try-catch最适合处理那些我们无法控制的错误,假设你在使用-一个大型的JavaScript库中的函数,该函数可能会有意无 意地抛出- -些错误。由于我们不能修改这个库的源代码,所以大可将对该函数的调用放在try-catch 语句当中。万-有什么错 误发生,也好恰当地处理它们。 在明明白白地知道自己的代码会发生错误时,再使用try-catch语句就不太合适了●例如,如果传递给函数的参数是字符串而 非数值,就会造成函数出错,那么就应该先检查函数的类型,然后再决定如果去做。在这种情况下,不应该使用try-catch语 句。
1 2 3 4 5 6 7 8 9 10 11 5. try-catch语句执行顺序 看下面的例子: try { throw "test"; } catch (ex) { console. log(ex); } finally { console. log('finally'); //test //finally 执行顺序为:首先执行try语句块中的代码,如果抛出异常,接着执行catch语句块中代码,如果没有异常,catch语句块中代码将会被忽略,但不管是否有异常,最后最会执行finally子句.try后面必须接着-一个catch或者fnally ,也就是说JavaScript中的try-catch可以有3中组合形式。即try-catch. try-Finally、 try-catch-Finally 三种形式。
promise 1 2 3 4 5 Promise的含义 Promise是异步编程的一种解决方案,比传统的解决方案--回调函数和事件 --更合理 和更强大。它由社区最早提出和实现, ES6将其写进了语言标准,统一了用法,原生提供了Promise对象 所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果o从语法上说,Promise是一个对象,从它可以获取异步操作的消息。Promise提供统- - 的API,各种异步操作都可以用同样的方法进行处理。 有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外, Promise对象提供统一的接口,使得控制异步操作更加容易。
异步:同时执行,并发
1 2 3 4 5 6 7 8 9 setTimeout(() => { console .log('helo 11' ) },30 ) setTimeout(() => { console .log('helo 22' ) },50 ) setTimeout(() => { console .log('helo 33' ) },10 )
同步:按顺序执行
1 2 3 console .log('hello 1' )console .log('hello 2' )console .log('hello 3' )
异步队列:注意回调地狱
1 2 3 4 5 6 7 8 9 10 setTimeout(() => { console .log('11' ) setTimeout(() => { console .log('22' ) setTimeout(() => { console .log('33' ) },0 ) },30 ) },50 )
promise对象:
Promise对象:
1)new Promise()对象的时候需要将一个函数作为参数传递过去
2)作为参数的函数,需要接收两个参数,resolve,reject,这两个参数自身又是函数
3)Promise对象有三个状态
pending:进行中
fullfilled: 已成功
rejected: 已失败
状态的转换有两种途径:
pending ———> fullfilled 统一描述为:resolved
pending ———> rejected 统一描述为:rejected
常见方法
catch()
then()
finally()
基本语法:
1 2 3 4 5 6 7 8 Promise实例生成以后,可以用then方法分别指定resolved状态rejected状态的回调函数。 promise.then(function(value) { success }, function(error) { failure }); then方法可以接受两个回调函数作为参数。第一一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。这两个 函数都接受Promise对象传出的值作为参数。
举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 const promise = new Promise ((resolve,reject )=> { resolve(10 ); }) promise.then(data => { console .log(data) },err => { console .log(err) }) console .log(promise)
promise使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const p = new Promise ((resolve,reject ) => { setTimeout(() => { reject(JSON .stringify({ code: 401 , msg: '异常错误' })) }) }) p.then(data => { console .log(data) },err => { console .log(err) })
依次输出:settimeout 11 30毫秒
settimeout 22 50毫秒
settimeout 33 0毫秒 用promise实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 let fn1 = () => { return new Promise ((resolve, reject ) => { setTimeout(() => { console .log('11' ) resolve() }, 30 ) }) } let fn2 = () => { return new Promise ((resolve, reject ) => { setTimeout(() => { console .log('22' ) resolve() }, 50 ) }) } let fn3 = () => { setTimeout(() => { console .log('33' ) }, 0 ) } fn1().then(fn2).then(fn3)
promise发起ajax请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const promise = new Promise ((resolve,reject )=> { let xhr = new XMLHttpRequest() xhr.open('GET' ,'https://douban.uieee.com/v2/movie/coming_soon' ) xhr.onreadystatechange = function ( ) { if (this .status==200 && this .readyState ==4 ){ resolve(this .responseText) } } xhr.send(null ) }) promise.then(data => { console .log(JSON .parse(data)) })
封装ajax,用promise:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 function ajax (method, url, fn, params ) { let xhr = new XMLHttpRequest() if (method == 'GET' && params != undefined ) { url = url + '?' + params } xhr.open(method, url, true ) xhr.onreadystatechange = function ( ) { if (this .readyState == 4 && this .status == 200 ) { fn(this .responseText); } } if (method == 'POST' && params != undefined ) { xhr.send(params) } else { xhr.send(null ) } } function ajax (method, url, params ) { return new Promise (function (resolve, reject ) { let xhr = new XMLHttpRequest() if (method == 'GET' && params != undefined ) { url = url + '?' + params } xhr.open(method, url, true ) xhr.onreadystatechange = function ( ) { if (this .readyState == 4 && this .status == 200 ) { resolve(this .responseText); } } if (method == 'POST' && params != undefined ) { xhr.send(params) } else { xhr.send(null ) } }) }
模块化 1 2 3 4 5 6 7 8 9 10 概述 历史.上, JavaScript一直没有模块(module)体系,无法将- -个大程序拆分成互相依赖的小文件,再用简单的方法拼装 起来I其他语言都有这项功能,比如Ruby的require、Python的import,甚至就连CSS 都有@import ,但是JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。 在ES6之前,社区制定了一些模块加载方案,最主要的有CommonlS 和AMD两种。前者用于服务器,后者用于浏览器。 ES6在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以职代CommonJS 和AMD规范,成为浏览器 和服务器通用的模块解决方案。 ES6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonIS和AMD 模块,都只能在运行时确定这些东西。比如,CommonJS模块就是对象,输入时必须查找对象属性。 ES6模块不是对象,而是通过export命令显式指定输出的代码,再通过import命令输入。
export: 导出
import: 导入
import —–from———- 从什么模块,导入
严格模式: 严格模式主要有以下限制:
变量必须声明后再使用
函数的参数不能有同名属性,否则报错
不能使用with语句
不能对只读属性赋值,否则报错
不能使用前缀0表示八进制数,否则报错
不能删除不可删除的属性,否则报错
不能删除变量delete prop
,会报错,只能删除delete global[prop]
eval
和arguments
不能被重新赋值
arguments
不会自动反映函数参数的变化
不能使用arguments.callee
不能使用arguments.caller
禁止this
指向全局对象
不能使用fn.caller
和fn.arguments
获取函数调用的堆栈
增加了保留字(比如protected
、static
、interface