class类
在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类,但是其本质是 function ,可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法,类的声明不可以重复,与let等一样,类定义不会被提升,这意味着必须在访问前对类进行定义,否则就会报错
// 命名类
class Example {
constructor(a) {
this.a = a;
}
}
// 匿名类
let Example = class {
constructor(a) {
this.a = a;
}
}
需要注意, ES6的类中不能直接定义变量,变量被定义在constructor中 ,constructor 方法是类的默认方法,创建类的对象时被调用。也被称为类的构造方法(构造函数、构造器)。一个类中有且仅有一个构造方法
class People {
constructor() {
console.log("你好");
}
}
new People(); //将执行constructor方法
类存在方法,一是原型方法,二是静态方法
原型方法不需要使用function关键字,通过“对象.原型方法”调用
静态方法使用static修饰,调用时不需要创建对象,直接通过“类名.静态方法”调用
//原型
class People {
say(world) {
console.log(`say ${world}`);
}
}
let p = new People();
p.say("hello"); //say hello
//静态
class People {
static sum(a, b) {
console.log(a + b);
}
}
People.sum(1, 2);
与Java中的类一样,js中的类也可以继承,使用extends关键字实现继承 ,子类可以继承父类中所有的方法和属性 ,但子类只能继承一个父类(单继承),一个父类可以有多个子类 ;子类的构造方法中必须有super()来指定调用父类的构造方法,并且位于子类构造方法中的第一行 ;子类中如果有与父类相同的方法和属性,将会优先使用子类的(覆盖)。通过继承,解决了代码的复用
class People {
//父类构造方法
constructor() {
this.a = 100; //父类中定义的变量
console.log("People constructor");
}
//原型方法
eat() {
console.log("eat...")
}
//静态方法
static play() {
console.log("play...")
}
}
class Student extends People {
//子类构造方法
constructor() {
super(); //调用父类构造器,必须存在,且位于子类构造器第一行的位置
this.b = 200; //子类定义的变量
console.log("Student constructor");
}
study() {
console.log("study...");
}
}
let stu = new Student();
console.log(stu.a, stu.b);
stu.eat();
stu.study();
Student.play();
内部类:属于外部类的成员,必须通过“外部类.内部类”访问
// 外部类
class Outer {
constructor() {
console.log("outer");
}
}
// 内部类
Outer.Inner = class {
constructor() {
console.log("Inner");
}
}
new Outer.Inner();
箭头函数
箭头函数定义
箭头函数提供了一种更加简洁的函数书写方式。基本语法是:
参数 => 函数体
(参数) => {函数体}
基本语法:
//普通函数
var f = function(a){
return a;
}
f(1); //1
//箭头函数
var f = a => a
f(10); //10
当箭头函数没有参数或者有多个参数,要用 () 括起来
var f = (a,b) => a+b;
f(6,2); //8
当箭头函数函数体有多行语句,用 {} 包裹起来,表示代码块,当只有一行语句,并且需要返回结果时,可以省略 {} , 结果会自动返回
var f = (a,b) => {
let result = a+b;
return result;
}
f(6,2); // 8
当箭头函数要返回对象的时候,为了区分于代码块,要用 () 将对象包裹起来
var f = (id,name) => ({id: id, name: name});
f(6,2); // {id: 6, name: 2}
使用箭头函数时,要注意this等关键字的指向,因为箭头函数没有 this、super、arguments 和 new.target 绑定
箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象
function a() {
setTimeout(function() {
console.log(this); //this始终指向全局Window对象
}, 100)
}
a.call({num: 200});
function b() {
setTimeout(() => {
console.log(this); //this绑定的是b函数中的this对象
}, 100);
}
b.call({num: 300});
箭头函数不可以作为构造函数,也就是不能使用 new 命令,否则会报错 ,且箭头函数只能定义式(没有名字)
function Person() {
console.log(this);
}
new Person(); //Person {}
var People = ()=>{
console.log(this);
}
new People(); //TypeError: People is not a constructor
箭头函数可以与解构一起使用
//变量为目标,返回值为源
let cal = (a, b) => {
return {
add: a+b,
sub: a-b,
mul: a*b,
div: a/b
};
}
let {add, sub, mul, div} = cal(10, 5);
//形参为目标,实参为源
var show = ({one, two}) => {
console.log(one + "---" + two);
}
show({one: "hello", two: "你好"});
适合使用的场景
ES6 之前,JavaScript 的 this 对象一直很令人头大,回调函数,经常看到 var self = this 这样的代码,为了将外部 this 传递到回调函数中,那么有了箭头函数,就不需要这样做了,直接使用 this 就行。
所以,当我们需要维护一个 this 上下文的时候,就可以使用箭头函数。
总结
-
要有个箭头
-
箭头的前面是小括号,放形参,只有一个形参的时候可以省略小括号;
-
箭头的后面是函数体;
-
如果函数体只有一个语句,没有{},此时的返回值不需要return;
-
箭头函数里面的this总是指向最靠近的function 内部的this;
-
对象里面的方法,尽可能不要使用箭头函数;
-
箭头函数里面没有arguments,可以使用…reset,接收过来就是数组类型,接收的是形参之外的所有的实参;
var show = (a, b, ...reset) => {
console.log(a + b);
console.log(reset);
}
show(1, 2, 3, 4, 5);
模块
概述
-
ES6 引入了模块化,其设计思想是在编译时就能确定模块的依赖关系,以及输入和输出的变量。
-
ES6 的模块化分为导出(export) 与导入(import)两个模块。
特点
-
ES6 的模块自动开启严格模式,不管你有没有在模块头部加上 use strict;。
-
模块中可以导入和导出各种类型的变量,如函数,对象,字符串,数字,布尔值,类等。
-
每个模块都有自己的上下文,每一个模块内声明的变量都是局部变量,不会污染全局作用域。
-
每一个模块只加载一次(是单例的), 若再去加载同目录下同文件,直接从内存中读取
export导出
与default关联使用,并且一个js模块中只能有一个export default语句 (即默认导出,一般包含了导出文件的大部分内容),其余的使用export 语句(单个导出)
//导出字符串
export default "abc";
//导出数字
export default 123;
//导出布尔值
export default true;
//导出数组
export default [1,2,3];
//导出对象
var obj = {
name: '张三',
age: 20
}
export default obj;
//导出函数
var func = function() {
console.log("func函数");
return 100;
}
export default func;
//导出类
class People {
constructor() {
this.a = 100;
}
say() {
console.log("say...");
}
}
export default People;
import导入
与from关联使用,此时script标签的type必须设置为module
单例模式:多次重复执行同一句 import 语句,那么只会执行一次,而不会执行多次。import 同一模块,声明不同接口引用,会声明对应变量,但只执行一次 import
<script type="module">
import People from './js/myModule.js';
let p = new People();
p.say();
</script>
导出 export default 修饰的内容时可以自定义变量名,但导入export修饰的内容时,需要使用{},且变量名需要与导出文件中的变量名相同
import obj, { fn, fm3, fm4 } from "./a.js"
异步编程
promise对象
Promise对象是一种数据容器,Map、Set等也是,在函数中不区分大小写
概述
promise是异步编程的一种解决方案。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息
Promise 异步操作有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。除了异步操作的结果,任何其他操作都无法改变这个状态
Promise 对象只有:从 pending 变为 fulfilled 和从 pending 变为 rejected 的状态改变。只要处于 fulfilled 和 rejected ,状态就不会再变了即 resolved(已定型)
Promise是一个构造函数,其原型上有then、catch方法,对象上有reject、resolve方法
promise使用
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('完成');
resolve('数据');
}, 1000);
});
参数说明:
-
resolve:异步操作执行成功后的回调函数
-
reject:异步操作执行失败后的回调函数
上面的代码中,直接通过new创建了Promise对象,并没有调用它,但是传进去的函数已经执行了。因此我们用Promise的时候一般是包含在一个函数中,在需要的时候去运行这个函数
function runAsync(){
var p = new Promise(function(resolve, reject){
//做一些异步操作
setTimeout(function(){
console.log('执行完成');
resolve('随便什么数据');
}, 2000);
});
return p;
}
runAsync()
通过return返回了一个Promise对象。也就是说调用这个包装函数可以得到Promise的对象,接下来就可以使用Promise对象上的then与catch方法了
runAsync().then(function(data){
console.log(data);
//后面可以用传过来的数据做些其他操作
//......
});
在runAsync()的返回上直接调用then方法,then接收一个参数,是函数,函数的参数data将会拿到我们在runAsync中调用resolve时传的的参数
此时then里面的函数就是回调函数,能够在runAsync这个异步任务执行完成之后被执行
链式操作用法
因为Promise 中的return返回的是一个Promise对象,所有可以继续所有then方法
runAsync1()
.then(function(data){
console.log(data);
return runAsync2();
})
.then(function(data){
console.log(data);
return runAsync3();
})
.then(function(data){
console.log(data);
});
这就是链式操作用法,通过这种操作,可以处理地域回调的问题
catch的用法
Promise对象除了then方法,还有一个catch方法 ,它和then的第二个参数一样,用来指定reject的回调 ,效果和写在then的第二个参数里面一样。不过它还有另外一个作用:在执行resolve的回调(也就是上面then中的第一个参数)时,如果抛出异常了(代码出错了),那么并不会报错卡死js,而是会进到这个catch方法中
getNumber()
.then(function(data){
console.log('resolved');
console.log(data);
console.log(somedata); //此处的somedata未定义
})
.catch(function(reason){
console.log('rejected');
console.log(reason);
});
在链式操作方法中,可以只写一个catch
async函数
async
async 是 ES7 才有的与异步操作有关的关键字,和Promise有很大的关联
async 函数返回一个 Promise 对象,可以使用 then 方法添加回调函数
async function helloAsync(){
return "helloAsync";
}
await
async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值
await 操作符用于等待一个 Promise 对象, 它只能在异步函数 async function 内部使用。如果在 async function 函数体外使用 await ,你只会得到一个语法错误
返回值返回 Promise 对象的处理结果。如果等待的不是 Promise 对象,则返回该值本身 ;如果一个 Promise 被传递给一个 await 操作符,await 将等待 Promise 正常处理完成并返回其处理结果
await针对所跟不同表达式的处理方式:
-
Promise 对象:await 会暂停执行,等待 Promise 对象 resolve,然后恢复 async 函数的执行并返回解析值。
-
非 Promise 对象:直接返回对应的值