一、块级作用域绑定
1、在函数作用域或全局作用域中使用var声明的变量,都会被提升至当前作用域顶部
2、块级声明:
用于声明在指定块的作用域之外无法访问的变量
块级作用域存在于:
1)、函数内部
2)、{}之间的区域
3、同一个作用域中不能用let、const声明已经存在的标识符,会 导致语法错误
4、使用const声明的是常量,其值必须进行初始化,并且不可更改,如果常量是对象,对象中的值可以修改
5、js在扫描代码发现变量声明时:
1)、如果是var :提升至作用域顶部
2)、如果是let或const:先放至TDZ(临时死区),访问TDZ中的变量会触发运行时错误
6、在for-in,for-of,循环中let和const每次迭代都会创建新得绑定值
7、在for循环中,let会创建新的绑定值,但const在for循环声明则可能引发报错
8、当var被用于全局作用域时,会创建一个新的全局变量作为全局对象的属性,即:var很可能会无意中覆盖一个已经存在的全局属性
9、在全局作用域中使用let或const,会在全局作用域下创建一个新的绑定,但不会添加为全局对象额属性
二、字符串与正则表达式
1、codePointAt():字符串转编码,此方法接受编码单元的位置而非字符位置作为参数
String.fromCodePoint():编码转字符串
2、normalize():标准化字符串,接受:‘NFC’、‘NFD’、‘NFKC’、‘NFKD’为参数
3、正则表达式u修饰符:从编码单元操作模式切换为字符模式
正则表达式y修饰符:
会影响正则表达式搜索过程中的sticky属性,当在字符串中开始字符匹配时,会通知搜索从正则表达式的lastIndex属性开始进行,如果在指定位置没能匹配成功,则停止匹配。
y修饰符会把上次匹配后面一个字符的索引保存在lastIndex中,如果该操作匹配的结果为空,则lastIndex会被重置为0
4、字符串中的子串识别
includes():检测是否包含指定文本
startWith():在起始位置检测是否包含该文本
endWith():在结束位置检测是否包含该文本
以上3个方法都接受两个参数:第一个参数指定要搜索的文本,第二个参数可选,指定一个开始搜索的位置的索引值。
ps:endWith方法则从这个索引值减去欲搜索文本的长度,开始正向匹配
5、repeat():该方法接受一个Number类型的数字,表示将字符串重复的次数
6、source属性:返回正则表达式的文本
flags属性:返回应用于当前正则表达式的修饰符
7、模板字面量
1)、ES6用反撇号代替双引号表示字符串
2)、ES5通常依靠数组或字符串拼接的方法实现多行字符串显示,ES6只需在代码中直接换行(或用\n),即可同步显示换行到结果中,但需要注意缩进,因为反撇号中的所有空白符都属于字符串中的一部分
8、字符串占位符:${},可以嵌套,通过模板字面量可以实现字符串拼接功能
9、标签
1)、标签:模板字面量第一个反撇号(`)前面标注的字符串
2)、标签可以是一个函数,
function tag(literals,...substitutions){
}
第一个参数是一个数组,包含js解释过后的字面量字符串;它之后的所有参数都是每一个占位符的解释值。substitutions的值总是比literals少一个
3)、String.raw()标签:返回转义前的原生字符
三、函数
1、js中无论在函数定义中声明了多少形参,都可以传入任意数量的参数,对于函数的命名参数,如果不显示传值,则其值默认为undefined。
2、ES6中如果没为参数传入值或传入undefined,则可为其提供一个初始值,可以为任意参数指定默认值,初始值可以通过函数执行来得到,在引用参数默认值时,先定义的参数不能访问后定义的参数,在已指定默认值的参数后可以继续声明无默认值参数。null是一个合法的传入值
3、ES5非严格模式下,arguments对象会随参数的变化而变化;严格模式下不变。ES6无论严格与非严格模式下,arguments对象都不会碎参数的变化而变化。未传入参数时,其默认值为undefined
4、不定参数...
不定参数为一个数组,包含着自它之后传入的所有参数,通过此数组名即可逐一访问里面的参数
1)、每个参数最多只能声明一个不定参数,而且一定要放在所有参数的末尾
2)、不定参数不能用于对象字面量setter之中
3)、不论是否使用不定参数,arguments对象总是包含所有传入函数的参数
5、增强的Function函数
1)、Function构造函数接受字符串形式的参数,分别为函数的参数及函数体
2)、支持在创建函数时定义默认参数和不定参数,默认参数需用=添加默认值,不定参数使用...
6、展开运算符
1)、使用展开运算符可向Math.max(),函数中传入一个数组,再在数组前添加不定参数中使用的...符号。eg:Math.max(...arr);
2)、展开运算符可以与其他正常传入的参数混合使用,eg:Math.max(...arr,0);
7、js有两个不同的内部方法:Call与Construct。通过new关键字调用函数,执行的是Construct,不通过new调用的函数,执行的是Call
8、ES6中new.target属性可以用来判断该函数是否通过new关键字调用
9、块级函数
1)、ES5不支持在代码块中声明一个块级函数
2)、ES6支持在代码块中声明一个块级函数
1】、在严格模式下:块级函数会被提升至块的顶部
2】、在非严格模式下:块级函数会被提升至外围函数或全局作用域的顶部
四、箭头函数
1、箭头函数没有this、super、arguments和new.target绑定,箭头函数中的this、super、arguments和new.target值均由外围最近一层非箭头函数决定
2、箭头函数不能通过new关键字调用
3、箭头函数没有原型
4、当箭头函数只有一个参数时,可以直接写参数名,箭头紧随其后
5、如果要传入两个或两个以上的参数,要在参数的两侧添加一对小括号
6、如果函数没有参数,也要在声明的时候写一组没有内容的小括号
7、如果想创建一个空函数,需要写一对没有内容的花括号 ()=》{}
8、如果想让函数向外返回一个对象字面量,需要将该字面量包裹到小括号内
9、箭头函数始终可以访问外围函数的arguments对象
10、尾调用指的是:函数作为另一个函数的最后一条语句被调用
尾调用优化可以邦之函数保持一个更小的调用栈,从而减少内存的使用,避免栈溢出错误
1)、尾调用不访问当前帧栈的变量
2)、在函数内部,尾调用是最后一条语句
3)、尾调用的结果作为函数值返回
五、扩展对象的功能性
1、ES6当对象的属性和本地变量同名时,不必再写冒号和值,简单的只写属性名即可
function createPerson(name,age){
return {
name,
age
};
}
2、ES6中为对象字面量添加函数可以消除冒号和function关键字
var person = {
sayName(){
return this.name;
}
}
3、ES6中,在对象字面量中可以使用外部定义的变量做属性名称,但需要用【】表示
let lastName = “last name”;
let person = {
[lastName]:"Zakas";
}
4、新增方法
1】、Objet.is():弥补===的不准确运算
Object.is(+0,-0)//false
Object.is(NaN,NaN)//true
2】、Object.assign();浅复制及对象属性的合并,该方法接受一个接收对象和任意数量的源对象
若右多个源对象具有同名属性,则排位靠后的源对象会覆盖排位靠前的。
5、ES6不在检查属性重复性,对于每一组重复属性,都会选取最后一个取值
6、自有属性枚举顺序:数值字在先,字符串键在后,数值键总是按照升序排列,字符串键按照插入的顺序排列,最后加入动态加入的属性
7、通过Object.setPrototypeOf()方法可以任意修改对象的原型,在对象被创建后依然可以修改,该方法接受两个参数:被改变原型的对象,替代第一个参数中原型的对象
8、super相当于指向对象原型的指针,super的所有引用都通过[[HomeObject]]属性来确定后续的运行过程
六、解构
定义:将一个数据解构分解为更小的部分的过程,解构能够从对象或者数组里取出数据存为变量
1、对象解构:
1】、let node = {
type:"Identifier",
name:""foo
};
let { type, name} = node;
2】、使用let、var、const解构声明变量,必须提供初始化程序,即初始化等号后面的对象
3】、使用解构语法可以为多个变量赋值:({ type, name} = node)
4】、使用的结构赋值表达式时,如果指定的局部变量名称在对象中不存在,那么这个局部变量会被赋值为undefined,当指定的属性不存在时,可以随意定义一个默认值,在属性名称后添加等号=与相应的默认值即可:let{ type, name, value= true} = node;
5】、可以使用不同命名的局部变量来存储对象的值:
let { type:localType, name:localName } = nade;//读取type的属性值,并存储进localType变量
6】、解构对象支持嵌套
2、数组结构
1】、解构赋值:当通过let、var、const声明解构数组的绑定时,必须要提供一个初始化程序
let colors = ["red","green","blue"];
let [ firstColor, secondColor ] = colors;
let [ , , thirdColor] = colors;
2】、代替swap函数,交换两个变量的值
let a = 1, b = 2;
[ a, b] = [ b, a];
console.log(a);//2
console.log(b);//1
3】、可以在数组解构赋值表达式中,为数组的任意位置添加默认值
let [ firstColor,secondColor = "green"] = colors;
4】、嵌套解构数组:
let [ firstColor, [ secondColor ] ] = colors;
5】、不定元素:必须作为最后一个条目存在
ES5中,开发者常用concat()方法实现克隆数组,concat()方法设计初衷是连接两个数组,如果调用时不传递参数,就会返回当前数组的副本。
ES6中则可以通过不定元素实现:let [...clonedColors] = colors;
3、解构参数
1】、
function setCookie ( name, value, { secure , path , domain , expires }){
......................;
}
setCookie ("type","js",{
secure:true;
expires:60000
});
2】、默认情况下,如果调用函数时,不提供被解构的参数将导致程序抛出错误,可以为其提供默认值来解决这个问题
function setCookie ( name, value, { secure , path , domain , expires } = { }){
......................;
}
3】、可以为解构参数逐个提供默认值
function setCookie ( name, value,
{
secure = false ,
path = "/" ,
domain = "example.com" ,
expires = new Date(Date.now()+360000000)
}
){
......................;
}
4】、3】中如果调用setCookie ("type","js");会导致程序跑出错误
const setCookieDefaults = {
secure = false ,
path = "/" ,
domain = "example.com" ,
expires = new Date(Date.now()+360000000)
}
function setCookie ( name, value,
{
secure = setCookieDefaults.secure ,
path = setCookieDefaults.path ,
domain = setCookieDefaults.domain ,
expires = setCookieDefaults.expires
} = setCookieDefaults
){
......................;
}
七、Set集合
1、Set集合常被用于检查对象中是否存在某个键名,而Map集合常被用于获取已存在的信息
2、对象属性的键名必须是字符串,而Set与Map的键名可以是任意类型。
3、Set是一种有序、唯一的列表,其常用方法包含:
has():检测Set集合中是否存在某个值
add():向Set集合中添加元素
delete():从Set集合中删除某个元素
clear():清空Set集合中的全部元素
forEach(function(参数1,参数2,参数3){
。。。。。。。
})
//参数1:Set集合中下一次索引的位置,参数2:与第一个参数一样的值,参数3:被遍历的Set集合本身
let set = new Set([1,2]);
set.forEach(function(value,key,ownerSet){
console.log(key+" "+value);
});//1,1 2,2
4、Set集合转数组,有去重效果,使用...展开福
eg:function setDelRepeat(arr){
return [...new Set(arr)];
}
setDelRepeat([1,2,2,3,5,5,5]);//[1,2,3,5]
5、WeakSet,弱Set
1】、弱Set只存储对象的弱引用,集合中的弱引用如果是对象唯一的引用,则会被回收并释放相应内存,避免内存泄漏
2】、弱Set的构造函数的参数仅支持对象类型,不支持原始类型,会报错
3】、弱Set支持:has()、delete()、add()方法
4】、弱Set不支持:size属性、forEach方法、不可迭代不能使用for-of循环
八、Map集合
1、Set集合常被用于检查对象中是否存在某个键名,而Map集合常被用于获取已存在的信息
2、对象属性的键名必须是字符串,而Set与Map的键名可以是任意类型。
3、Map键名的等价性判断通过Object.is()实现,5与“5”不一样
4、Map常用方法:
set(key,value):向集合添加新的元素
get(key):获取集合中对应键的值,如果该键在集合中不存在,则返回undefined
has(key):检测指定的键名在集合中是否存在
delete(key):从集合中移除指定键名及其对应的值
clear():移除集合中所有的键值对
forEach(function(参数1,参数2,参数3){
.............................
});
//参数1:集合中下一次索引的位置,参数2:值对应的键名,参数3:Map集合本身
let map = new Map([["name","nike"],["age",19]]);
map.forEach(function(value,key,ownerMap){
console.log(key+" "+value);
});
//name nike
//age 19
5、Map支持批量添加数据,初始化Map使用数组包裹数组的方式
eg: let map = new Map([["name","nike"],["age",19]]);
6、WeakMap 弱Map
1】、弱Map集合中的键名必须是一个非null对象,值可以是任意类型,无序
2】、弱Map集合中保存的是这些对象的弱引用,如果在弱引用之外不存在其他的强引用,引擎的垃圾回收机制会自动回收这个对象,同时也会移除集合中的键值对,但如果只有键遵循这个规则,而键名对应的值如果是一个对象,则保存的是对象的强引用,不会触发垃圾回收机制。
3】、弱Map支持:has()、delete()、set()、get()
4】、弱Map不支持:size属性、键名枚举、clear()
7、WeakMap与Map的适用场景
WeakMap:只用对象作为键名的集合
Map:非常需要使用size属性、clear()、forEach方法
九、迭代器和生成器
1、迭代器:是一种特殊对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性,一个是value:表示下一个将要返回的值;另一个是done,在没有更多可返回数据时,返回true。
2、生成器:是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,使用yield关键字暂停
3、yield:每当执行完一条yield语句后,函数就会自动停止;yield关键字可以返回任何值或表达式;yield关键字只能在生成器内部使用,在其他地方使用, 会导致程序抛出错误,即使是在生成器内部的其他函数
4、创建生成器的两种方法(不能用箭头函数创建生成器):
1】、function *fun(){}
2】、函数表达式:let fun = function *(items){}
5、Symbol是ES6中新增的一种原始数据类型,表示独一无二的值,其最大的用途是用来定义对象的唯一属性名,通过Symbol.iterator可以访问对象的默认迭代器。
使用Symbol.iterator可以检测对象是否为可迭代对象
function isIterable(obj){
treturn typeof obj[Symbol.iterator] === "function";
}
6、默认情况下,开发者定义的对象都是不可迭代对象,但利用Symbol.iterator可将其变为可迭代对象
let collection = {
items :[],
*[Symbol.iterator](){
for(let item of items){
yield item;
}
}
};
7、集合对象内建迭代器
entries():返回一个迭代器,其值为多个键值对,Map默认
values():返回一个迭代器,其值为集合的值,数组和Set默认
keys():返回一个迭代器,其值为集合中的所有键名
8、ES5规定可以使用[]访问字符串中的字符
9、Dom标准中有一个NodeList类型,代表页面文档中所有元素的集合,ES6中NodeList也拥有了默认迭代器
10、高级迭代器功能
1】、给迭代器传递参数:在next()方法中传递参数,则这个参数的值将会替代生成器内部上一条yield语句的返回值
2】、在迭代器中抛出错误,next和throw就像是生成器的两条指令,调用next方法命令迭代器继续执行,调用throw方法也会命令迭代器继续执行,但同时也会抛出一个错误
3】、生成器返回语句:生成器中的return表示所有操作已经完成,属性done被置为true,如果同时提供了相应的值,则属value会被设置为这个值。return后面的yield语句将不再执行。展开运算符与for-of循环语句会直接忽略return语句指定的任何返回值,只要done为true,就立刻停止读取其他的值。
4】、委托生成器,使用yield语句添加*,将两个迭代器合二为一
11、异步任务执行
ES5实现异步:回调函数或者setTimeout();
ES6实现异步:通过生成器
十、js中的类
1、使用class关键字定义一个类,使用constructor关键字创建构造函数,自有属性只能在类的构造函数中创建。
2、类与自定义类型之间的区别:
1】、函数声明可以被提升,而类声明与let声明类似,不能被提升;真正执行类声明语句之前,它们会一直存在于临时死区
2】、类声明中的所有代码将自动运行在严格模式下
3】、在自定义类型中,通过Object.defineProperty()方法手动指定某个方法不可枚举,而类中所有方法都不可枚举
4】、每个类都有一个名为[[Construct]]的内部方法,通过关键字new调用不含[[Construct]]的方法会报错
5】、只能使用new关键字调用类的构造函数
6】、类内类名不可更改
3、类的两种存在形式:声明形式、表达式形式
声明形式:class Person{}
表达式形式:let PersonClass = class Person{}//Person只能在内部使用
4、可以通过变量给类定义的方法命名:
5、在类中可以定义生成器
6、使用static定义静态成员,必须直接使用类名访问静态成员,不可以在实例中访问静态成员
7、通过extends及super关键字实现继承
1】、继承时,子类中如果指定了构造函数,则必须调用super;如果选择不使用构造函数,则当创建新的类实例时会自动调用super并传入所有参数
2】、只能在存在继承关系的子类的构造函数中调用super
3】、js可以实现多继承
4】、如果父类中有静态成员,那么子类也可以用
5】、使用Symbol.species可以定义当子类的方法返回实例时,应该返回的类型
8、子类方法总是会覆盖父类中的同名方法,如果需要调用父类的该方法,可以使用super.mains();
9、在类的构造函数中,可以通过new.target属性来随着类被调用的多种方式而做出不同的对于,最常见的是创建一个抽象父类,如果直接实例化这个类会抛出错误,但是可以通过其他的类去实例化它。
十一、改进的数组功能
1、新增方法
1】、Array.of():不论参数是什么类型,总会创建一个包含所有参数的数组
2】、Array.from():
接收可迭代对象或类数组对象作为第一个参数,最终返回一个数组;
如果想要进一步转化数组,可以提供一个映射函数作为Array.from()的第二个参数;
如果用映射函数处理对象,也可以给Array.from()方法传入第三个参数来表示映射函数的this值。
可以处理类数组对象和可迭代对象,也就是说该方法能够将所有含有Symbol.iterator属性的对象转换为数组
eg1:
let helper = {
diff :1,
add(value){
return value + this.diff;
}
};
function translate(){
return Array.from(arguments,helper.add,helper);
}
console.log(translate(1,2,3));//2,3,4
eg2:
let numbers = {
*[Symbol.iterator](){
yield 1;
yield 2;
yield 3;
}
};
let numbers = Array.from(numbers,(value)=>value+1);
console.log(numbers);//2,3,4
3】、find(回调函数,指定函数中的this值(可选参数)):返回查找到的值
4】、findIndex(回调函数,指定函数中的this值(可选参数)):返回查找到的值的索引
let numbers = [20,25,66,85,9];
console.log(numbers.find(n=>n>33));//66
console.log(numbers.findIndex(n=>n>33));//2
ps:find/findIndex一旦回调函数返回true,会立刻停止搜索数组剩余的部分
5】、fill(value,开始索引(可选),结束索引(可选)):用指定的值填充一个或多个数组元素
eg:let numbers = [1,2,3,4];
console.log(numbers,fill(0,1,3).toString());//1,0,0,1
6】、copyWithin(开始填充值的索引位置,开始复制值的索引位置,限制被重写元素的数量(可选)):从数组中复制元素的值
eg:let numbers = [1,2,3,4];
console.log(numbers,copyWithin(2,0).toString());//1,2,1,2
默认情况下,copyWithin会一直复制直到数组末尾的值。
fill、copyWithin的所有参数都接受负数值,并且会自动与数组长度相加来作为最终使用的索引
2、定型数组
1】、定型数组:一种用于处理数值类型数据的专用数组
2】、数组缓冲区:一段可以包含特定数量字节的内存地址,let buffer = new ArrayBuffer(10);
3】、视图:用来操作内存的接口,DataView类型是一种通用的数组缓冲区视图
let buffer = new ArrayBuffer(10);
view = new DataView(buffer);
new DataView(buffer,byteOffset,byteLength)
4】、ES6中的特定类型视图:定型数组是视图 Int8Array,Uint8Array,Uint8ClampedArray,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array,
5】、创建定型数组的方法:
1)、传入DataView构造函数可接受的参数来创建新的定型数组,分别为:数组缓冲区、可选的比特偏移量、可选的长度值
let buffer = new ArrayBuffer(10),
view1 = new Int8Array(buffer,5,2);
2)、调用构造函数时传入一个数字
let ints = new Int16Array(2);
3)、调用构造函数时传入:定型数组、可迭代对象、数组、类数组对象
6】、定型数组和数组的相似之处:
1)、均支持不改变数组长度的基本方法
2)、展开运算符能够将可迭代对象转换为普通数组,也能将定型对象转换为普通数组
3)、可通过Symbol.species确认方法的返回值是定型数组而非普通数组
7】、定型数组与普通数组的差别
1)、定型数组不是普通数组,它不继承自Array
2)、定型数组不可改变数组大小,普通数组传入未知索引会改变大小
3)、对于会改变定型数组长度的方法均不可用,如push
4)、新增方法set():将其他数组复制到已有的定型数组,subarray():提取已有定型数组的一部分作为一个新的定型数组
十二、Promise
Promise是异步编程的一种解决方案,比传统的解决方案-回调函数和事件更合理和更强大。所谓Promise简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果,从语法上说,Promise是一个对象,从它可以获取异步操作的消息,Promise对象的状态不受外界影响。
三种状态:
pengding: 进行中
fulfilled: 已经成功
rejected: 已经失败
状态改变:Promise对象的状态改变,只有两种可能:这两种情况只要发生,状态就凝固了,这时就成为resolved(已定型)
从pengding变为fulfilled
从pengding变为rejected
基本用法:ES6规定,Promise对象是一个构造函数,用来生成Promise实例
const promise = new Promise(function(resolve,reject){
if(/*异步操作成功*/)
{
resolve(value);
}
else
{
reject(error);
}
});
resolve的作用是把Promise对象的状态从未完成变为成功,在异步操作成功时调用,并将异步操作的结果,作为参数传递出去
reject的作用是把Promise对象的状态从未完成变成失败,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去
Promise实例生成以后,可以用then方法分别指定resolve状态和resolve的回调函数
promise.then(function(value){
//success },function(error){
//failure
});
例子:
function timeout(ms){
return new Promise((resolve,reject)=>{
setTimeout(resolve,ms,'done');
});
}
timeout(100).then((value)=>{
console.log(value);
});
let promise = new Promise(function(resolve,reject){
console.log('Promise');
resolve();
});
promise.then(function(){
console.log('resolved');
});
console.log('Hi!');
//Promise
//Hi!
//resolved
//异步加载图片
function loadImageAsync(url){
return new Promise(function(resolve,reject){
const image = new Image();
image.onload = function(){
resolve(image);
};
image.onerror = function(){
reject(new Error('error');
};
image.src = url;
});
}
下面是一个用Promise对象实现的 Ajax 操作的例子。
const getJSON = function(url) {
const promise = new Promise(function(resolve, reject){
const handler = function() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
}else {
reject(new Error(this.statusText));
}
};
const client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send();
});
return promise;
};
getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('出错了', error);
});