微任務&宏任務
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 = []; //觸發setobj.arr = [1, 2, 3]; //觸發setobj.arr.push(10); //沒有觸發set,而是觸發getobj.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