十一、JS的类
看起来像是对象字面量的声明,但是其方法属性之间不需要逗号:
class PersonClass {
//构造器
constructor(name){
this.name = name;
}
//prototype上的方法
sayName(){
return this.name;
}
}
let person = new PersonClass("nico");
let name = person.sayName();//"nico"
person instanceof PersonClass;//true
person instanceof Object;//true
typeof PersonClass;//"function"
typeof PersonClass.prototype.sayName;//"function"
注意:
- 类声明不会被提升
- 类声明中的所有代码均处于严格模式下,且不可退出严格模式
- 类的所有方法都是不可枚举的
- 类的所有方法内部没有[[Construct]],使用new调用会报错
- 在类内部重写类名会报错(可在外部重写)
创建单例
立即调用类构造器
let person = new class {
constructor(name){
this.name = name;
}
sayName(){
return this.name;
}
}("nico");
person.sayName();//"nico"
访问器属性
类允许在原型上定义访问器属性:
class CustomHTMLEle {
constructor(ele){
this.element = ele;
}
get html(){
return this.element.innerHTML;
}
set html(value){
this.element.innerHTML = value;
}
}
需计算的属性名:使用中括号;
静态方法:static
标注,不能通过实例来访问,只能通过类自身访问;
let method = "sayName";
class PersonClass{
constructor(name){
this.name = name;
}
[method](){
return this.name;
}
static create(name){
return new PersonClass(name);
}
}
let person = Person.create("nico");
继承:
class Rectangle {
constructor(length, width){
this.length = length;
this.width = width;
}
getArea(){
return this.length * this.width;
}
}
class Square extends Rectangle {
constructor(length){
super(length, length);
}
}
let square = new Square(3);
square.getArea();//9
继承其他类的类叫派生类,若派生类指定了构造器就要使用super,否则报错;不指定构造器则会自动调用super()方法。
在派生类中定义的同名方法会屏蔽基类的同名方法。
一个表达式能够返回具有[[Construct]]属性与原型的函数,则可以对其使用extends
。extends后可接任意类型表达式(除了null和生成器函数,不具有[[Construct]]),可通过函数动态地决定继承的类。
十二、增强的数组功能
创建数组
let arr = new Array(2);
//长度为2,两项都为undefined
//而非长度为1,首项为2
避免此类单值传入的特异情景,使用Array.of()
方法创建数组:
let arr = Array.of(2);
//长度为1,首项为2
Array.from()
方法将可迭代对象或数组对象转换为数组。
映射转换:Array.from()
方法传入第二个参数,即映射函数,完成数组中每一个值的转换:
function translate(){
return Array.from(arguments, (value)=>value+1);
}
let nums = translate(1,2,3);//2,3,4
使用对象的方法时,传入第三个参数用于指定this
值:
let obj = {
diff : 1,
add(val){
return this.diff + val;
}
};
function translate(){
return Array.from(arguments, obj.add, obj);
}
新方法
find()
与findIndex()
方法接收两个参数:一个回调函数与可选的指定回调函数内部this
值。
find返回匹配的值,findIndex返回匹配位置索引。
let nums = [1,2,3];
nums.find(n=>n>1);//2
nums.findIndex(n=>n>1);//1
二者往往用于查找特定条件,而indexOf()
与lastIndexOf()
用于查找特定值。
fill()
填充数组:单个值传入则全部填充,第二个参数传入则作为开始索引(包含),第三个参数传入作为结束索引(不包含)。
let nums = [1,2,3,4];
nums.fill(1);//[1,1,1,1]
nums.fill(0,2);//[1,1,0,0];
nums.fill(2,1,3);//[1,2,2,0];
copyWithin()
方法用于复制粘贴数组内部的元素:第一个参数表示开始粘贴位置,第二个参数表示开始复制位置,第三个参数表示结束复制位置(不包含)。
let num = [1,2,3,4];
num.copyWithin(2,0,1);//[1,2,1,4];
num.copyWithin(2,0);//[1,2,1,2];
十三、Promise异步方法
此前出现的异步操作常见有事件监听与回调,易出现回调地域(依次调用功能函数形成链式调用,深层次嵌套,难维护)
生命周期
起初为挂起 pending, 表示异步操作尚未结束,也代表未决的 unsettled;当异步操作结束时,被认定为已决的 settled,并进入两种状态之一:
- 已完成 resolve 即fulfilled,异步操作成功结束;
- 已拒绝 rejected异步操作未成功结束,可能由错误导致;
内部的[[PromiseState]]
属性会被设置为pending
、fulfilled
、rejected
。
使用then()
方法在Promise
状态改变时进行操作。接收两个可选的参数,Promise
被完成或拒绝时要调用的函数,关于成功或拒绝相关的附加数据会被传入:
let promise = readFile("exam.txt");
promise .then(function(contents){
console.log(contents);
},function(err){
console.log(err);
});
//或仅传入第一个参数,或传入null与第二个参数
Promise
也具有catch()
方法,等同于只传第二个拒绝处理函数给then()
:
promise.catch(function(err){
console.log(err);
});
创建
使用Promise构造器创建:
new Promise(
function(resolve, reject){
resolve();
//reject();
}
).then(
res => {console.log(res)},
err => {console.log(res )}
);
创建已决的Promise:
let promise = Promise.resolve(42);
promise.then((value)=>{console.log(value)})
串联
每次对then()
或catch()
的调用实际上创建并返回了一个新的Promise,仅在当前Promise被完成或拒绝后,下一个Promise才会被决议。
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
p1.then(function(value) {
console.log(value);
return value+1;
}).then(function(value) {
console.log(value);
}).then(function() {
console.looooog("Finished");
}).catch(function(){
console.log("err");
});
//一般在末尾添加错误处理
//42
//43
//err
但是这种方法无法控制resolve
顺序执行,若在其中包含setTimeout
,事实上会继续向下执行而非等待其执行结束。
应当使用定义的Promise
作为返回值:
let p1 = new Promise((resolve)=>{resolve()});
p1.then(()=>{
return new Promise((resolve)=>{
setTimeout(()=>{
console.log("2");
resolve();
},1000);
});
}).then(res=>{
console.log("3");
});
//2
//3
Promise.all()
方法:传入一个元素都为Promise
的可迭代对象(比如数组),返回一个Promise
。当所有元素完成后,返回的Promise
才会被完成。若其中某一个Promise
元素被拒绝,则返回的Promise会立即被拒绝,元素之后的Promise不会再执行。
Promise.race()
方法:传入一个元素都为Promise
的可迭代对象(比如数组),返回一个Promise
。当其中一个Promise完成后,返回的Promise会立即被解决。(即赛跑,胜出的Promise元素决定了返回的Promise结果被完成或是拒绝)
async 与 await
async
用于声明一个方法是异步的,await
用于等待另一个异步方法执行完成。
async函数返回一个Promise对象,若在函数内部return一个直接量,则该直接量通过Promise.resolve()传递。
await
等待其后的Promise执行完毕,如果其结果可能为rejected
则应当放在try-catch
块中。await
命令应当使用在async
中,否则报错。
function timeout(ms){
return new Promise((resolve)=>{
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms){
await timeout(ms).catch((err)=>{console.log(err)});
console.log(value);
}
asyncPrint('hello', 50);
十四、代理与反射接口
原先只存在于内置对象上的工作通过代理(proxy)暴露出来。
代理是一种封装,拦截并改变JS引擎的底层操作。