微任务&宏任务
JS是单线程执行。所有要执行的任务都要排队。
所有的同步任务会在主线程上排队,等待执行。
异步任务:不会进入主线程,而是会进入任务队列。等到主线程上的任务执行完成之后,通知任务队列,执行异步任务。
在任务队列中,也存在着简单的任务和复杂的任务,因此,把任务队列中的复杂任务称为宏任务,把简单的任务称为微任务。
在主线程执行完同步任务后,先去执行任务队列的微任务,然后是宏任务
console.log(1); //同步任务
let p = new Promise((resolve) => {
console.log(2); //promise内部也是同步任务
resolve(3); //异步任务---微任务
});
p.then((res) => {
{
console.log(res);
}
});
console.log(4); //同步任务
//1 2 4 3
微任务有:
- promise的then方法
- async...await 后面的代码
宏任务有:
- setTimeout
- setinterval
setTimeout(() => {
console.log(0); //宏任务
}, 100);
console.log(1); //同步任务
let p1 = new Promise((resolve) => {
console.log(2); //promise内部也是同步任务
resolve(3); //异步任务---微任务
});
p1.then((res) => {
{
console.log(res);
}
});
console.log(4); //同步任务
//输出:1 2 4 3 0
function f2() {
console.log(1);
}
console.log(2);
async function f3() {
console.log(3);
await f2(); //f2为什么会在console.log(5)前执行?
console.log(4);
}
f3();
console.log(5);
//输出2 3 1 5 4
//await f2()会同步执行,实际上await后面的代码会放到任务队列中作为微任务去执行
class
ES5中定义类
/*******************ES5中定义类,通过构造函数定义对象****************** */
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return this.x;
};
var p = new Point(2, 4);
ES6中定义类
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ":hello world");
}
}
let animal = new Animal("jack");
animal.speak();
ES6 的class可以看作只是一个语法糖【type of Animal 是一个function】,它的绝大部分功能,ES5 都可以做到。
constructor是类中默认的方法,虽然没有在Point中显式定义constructor。constructor存在于Point类的原型对象中。
class只能通过new运算符进行构造
class Point {
}
let p2 = Point();//Uncaught TypeError: Class constructor Point cannot be invoked without 'new'
class继承
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
coordinate() {
return [this.x, this.y];
}
}
//extends&super配使用实现继承
class CircleDot extends Point {
//extends关键字实现继承
constructor(x, y) {
super(x, y); //关键字,代表父类的构造函数
//super相当于:Point.prototype.constructor.apply(this);
}
}
let dot = new CircleDot(10, 20);
//当子类和父属性重名,子类属性将覆盖从父类继承来的属性
//当子类和父方法重名,子类方法将覆盖从父类继承来的方法
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
coordinate() {
return [this.x, this.y];
}
}
class CircleDot extends Point {
constructor(x, y, z) {
super(x, y);
this.x = z;
}
coordinate() {
console.log("CircleDot");
super.coordinate(); //调用父类的方法
}
}
let circle = new CircleDot(1, 2, 3);
类的多重继承
一个类可以继承多个父类叫多继承
class默认不直接支持多继承。extends只能从一个类继承。Object.assign(Animal.prototype, EatMixin, SleepMixin)
//定义一个混合特性
let EatMixin = {
eat() {
console.log("eat");
},
};
let SleepMixin = {
sleep() {
console.log("sleep");
},
};
class Animal {}
Object.assign(Animal.prototype, EatMixin, SleepMixin);//混合特性
let a = new Animal();
a.eat();
ES6模块化
模块通常是指编程语言所提供的代码组织机制,利用此机制可将程序拆解为独立且通用的代码单元。所谓模块化主要是解决代码分割、作用域隔离、模块之间的依赖管理以及发布到生产环境时的自动化打包与处理等多个方面
简单的说:模块化就是将变量和函数 放入不同的文件中
ES6模块(module)
模块Module 一个模块,就是一个对其他模块暴露自己的属性或者方法的文件
导出Export,作为一个模块,它可以选择性地给其他模块暴露(提供)自己的属性和方法,供其他模块使用
针对默认的模块文件:module.js
//一个文件内可以进行多次导出
export const n1 =10;
export const n2 =20;
export const n3 =30;
在引用时,使用:import { n1, n2, n3 } from "./module";
为什么使用{}进行导入接收。默认一个模块文件,在导出时是一个对象
const id = 1;
const name = "jack";
const msg = "success";
function sum(n1, n2) {
return n1 + n2;
}
//直接暴露,很清晰
export { id, name, msg, sum };
使用时:
import { id, name, msg, sum } from './module2'
导出时使用别名:export { id as _id, name as _name, msg as _msg, sum };
导入时使用别名:import { id, name, msg, sum as _sum } from './module2'
export default {
x: "x",
y: "y",
};
使用的时候:
import obj from './module3'
- 如果使用export {}或者export const a ,引入的时候,import {} from ''---需要加{}
- 如果使用export default {},import 不需要加{},直接使用obj进行接收
export default { x: "x", y: "y" };
export const a = 1;
export const b = 2;
引入时:
import obj, { a, b } from './module5'
Proxy
proxy 在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截
var proxy = new Proxy(target, handler);
target:目标对象;
handler:具体拦截的行为
基本使用
//目标对象
let target = {
id: 1,
};
let handler = {}; //行为也是一个对象
let proxy = new Proxy(target, handler);
console.log(proxy.id); //通过代理对象获取原对象的属性
//具体的实现方式:handler有2个属性
let handler = {
get: function (target, property) {
console.log("handler");
return target[property];
},
}; //行为也是一个对象
let proxy = new Proxy(target, handler);
console.log(proxy.id); //通过代理对象获取原对象的属性
handler 本身就是 ES6 所新设计的一个对象.它的作用就是用来 自定义代理对象的各种可代理操 作 。它本身一共有 13 中方法,每种方法都可以代理一种操作.其 13 种方法如下:
- get(target,property):拦截对象属性的读取
- set(target,prokey,value):拦截对象属性的设置
- has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值
- deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值
- ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、 Object.keys(proxy)、for...in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而 Object.keys()的返回结果仅包括目标对象自身的可遍历属性
- getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象
- defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、 Object.defineProperties(proxy, propDescs),返回一个布尔值
- preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值
- getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
- isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值
- setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种 额外操作可以拦截。
- apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(...args)、proxy.call(object, ...args)、 proxy.apply(...)
- construct(target, args):拦截 Proxy 实例作为构造函数调用的操作,比如new proxy(...args)。
Object.defineProperty()与Proxy
/*********************Object.defineProperty()与Proxy的异同************************ */
let obj = {};
Object.defineProperty(obj, "arr", {
get: function () {
console.log("Get");
return v;
},
set: function (value) {
console.log("Set");
v = value;
},
});
obj.arr = []; //触发set
obj.arr = [1, 2, 3]; //触发set
obj.arr.push(10); //没有触发set,而是触发get
obj.arr[3] = 4; //没有触发set,而是触发get
//vue2通过Object.defineProperty实现双向绑定,
//但是针对数组类型,通过push等操作数组的方法虽然能够改变数组的值,但是不能触发界面更新
//vue2的解决办法是:this.$set()方法
/********************Vue3***************** */
let arr = [];
let handler3 = {
set: function (target, property, value) {
console.log("set");
target[property] = value;
return true;
},
get: function (target, property) {
console.log("Get");
return target[property];
},
};
let p2 = new Proxy(arr, handler3);
p2.push(10); //触发了4次,包括2次get,2次set