文章目錄
- 原型鏈關鍵字總結
- 原型對象:prototype
- 對象原型:__ proto__
- 面向對象編程
- 封裝
- 抽象
- 多態
- 總結
- 異步編程
- 基礎循環
- 宏任務嵌套微任務
原型鏈關鍵字總結
原型對象:prototype
函數的屬性,指向一個對象,這個對象是通過該函數作為構造函數創建的所有實例的原型
修改原型會影響所有已創建的實例,但重寫整個原型對象不會影響已創建的實例。
如下
重寫了整個原型對象,但依舊輸出1,只有新建的才輸出2
個人理解是
new調用構造函數時,會給實例的__ proto__,(也就是函數的prototype),賦予函數的prototype值,也就是淺拷貝,二者指向同一對象,而再次新建時修改了原指針,指向了新的原型對象,但舊實例,還是有原對象的索引
function Foo() {}
const foo1 = new Foo();
const foo2 = new Foo();Foo.prototype.value = 1;
console.log(foo1.value);
console.log(foo2.value);Foo.prototype = { value: 2 };
const foo3 = new Foo();
console.log(foo1.value);
console.log(foo2.value);
console.log(foo3.value);
//1 1 1 1 2
對象原型:__ proto__
對象的屬性:指向該對象的構造函數的原型(對象)
console.log(man.prototype);//man是函數,manba是其實例
console.log(manba.__proto__);
//{ name: '', age: '' }
//{ name: '', age: '' }
new` 關鍵字會創建一個新的空對象,并將該對象的 `__proto__` 設置為 `man.prototy
function People(name){this.name=name}
//people方法
People.prototype.Hello=function(){return `Hello ${this.name}`
}function Student(name,score){People.call(this,name)this.score=score
}
//將student的原型指向Person的原型,繼承了person的方法
//未指定原型實例無法訪問父類方法Student.prototype=Object.create(People.prototype)//指定原型后constructor會指向父類構造函數,修復
Student.prototype.constructor=Student
//
let xiaoming= new Student('xiaoming','80')
console.log(xiaoming);
console.log(xiaoming.constructor);
console.log(xiaoming.Hello());
create
Object.create(People.prototype);
//創建一個新People.prototype對象,它的原型指向People.prototype
class實現
class People{constructor(name){this.name=name}Hello(){return `Hello ${this.name}`}
}//繼承
class Student extends People{constructor(name,score){super(name)this.score=score}printScore(){return `score : ${this.score}`}
}
let p1=new People('xiaoF')let stu=new Student('xiaoming','100')
console.log(stu.printScore());
console.log(stu.Hello());
console.log(p1.Hello());
//console.log(p1.printScore());(無)
面向對象編程
封裝
-
私有屬性
_約定,#真語
同樣有靜態屬性和方法
class Person {constructor(name, age) {this._name = name; // 使用下劃線表示私有屬性this._age = age;} }
-
私有方法
class animal{#name;constructor(name){this.#name=namethis.#firstPrint()}getName(){return this.#name}#firstPrint(){console.log(this.#name);}firstPrint(){console.log(this.#name);} } let dog =new animal('dog') dog.firstPrint()
帶#與不帶#可以同時存在,為倆種不同的方法
還可以組合私有靜態
class Cat extends Animal{static #count=0constructor(name){super()this.name=name;(Cat.#count)++}static getNum(){return Cat.#count}
}let cat1=new Cat('mm')
console.log( Cat.getNum());
抽象
沒有java類似的抽象類關鍵字
只能通過throw error來模擬抽象類
new.target
不僅可以在類的構造函數中使用,還可以在任何函數中使用。它是一個特殊的元屬性,用于檢測當前函數是否通過new
關鍵字被調用,以及調用時的構造函數是什么。
// 模擬抽象類
class Shape {constructor() {if (new.target === Shape) {throw new Error("Cannot instantiate abstract class");}}// 抽象方法area() {throw new Error("Abstract method must be implemented");}
}
多態
實現多態發生原型鏈的分支
class Cat extends Animal{static #count=0constructor(name){super()this.name=name;(Cat.#count)++}static getNum(){return Cat.#count}Print(){console.log( `cat: ${this.name}`);}
}class dog extends Animal{static #count=0constructor(name){super()this.name=name;(dog.#count)++}static getNum(){return dog.#count}Print(){console.log(`dog: ${this.name}`);}
}
總結
并未含有java類似的關鍵字(abstract)嚴格聲明,而是通過拋出錯誤等來進行限制
異步編程
基礎循環
遵循同步任務->微任務->宏任務
清空微任務隊列后,才會進入下一次宏任務,如此循環
微任務
由js自身發起的,如promise
宏任務
由瀏覽器發起,如settimeout
setTimeout(() => {// 宏任務console.log('setTimeout');
}, 0);new Promise((resolve, reject) => {resolve();console.log('promise1'); // 同步任務
}).then((res) => {// 微任務console.log('promise then');
});console.log('同步任務'); // 同步任務
解析
- 第一個宏任務setTimeout暫存,
- 執行promise的構造函數(同步任務)//修改promise的狀態,觸發then的微任務暫存并輸出promise1
- 執行最終的log輸出同步任務
- 微任務隊列不為空,執行輸出promise then
- 執行最終宏任務 輸出setTimeout
輸出順序
promise1
同步任務
promise then
setTimeout
宏任務嵌套微任務
new Promise((resolve, reject) => {setTimeout(() => {resolve();console.log('setTimeout'); // 宏任務}, 0);console.log('promise1');
}).then((res) => {// 微任務console.log('promise then');
});console.log('同步任務');
- 暫存promise構造函數中的宏任務并輸出promise1
- 由于promise的狀態在宏任務中改變,故then還未觸發,輸出最后的同步任務
- 此時 微任務未空,執行暫存的宏任務, resolve();觸發微任務,并輸出同步任務promise1’
- 執行then輸出promise then