异步编程与面向对象知识总结

文章目录


原型链关键字总结

原型对象:prototype

函数的属性,指向一个对象,这个对象是通过该函数作为构造函数创建的所有实例的原型

修改原型会影响所有已创建的实例,但重写整个原型对象不会影响已创建的实例。

如下

重写了整个原型对象,但依旧输出1,只有新建的才输出2

个人理解是
new调用构造函数时,会给实例的__ proto__,(也就是函数的prototype),赋予函数的prototype值,也就是浅拷贝,二者指向同一对象,而再次新建时修改了原指针,指向了新的原型对象,但旧实例,还是有原对象的索引

js 复制代码
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__

对象的属性:指向该对象的构造函数的原型(对象)

js 复制代码
console.log(man.prototype);//man是函数,manba是其实例
console.log(manba.__proto__);
//{ name: '', age: '' }
//{ name: '', age: '' }
复制代码
new` 关键字会创建一个新的空对象,并将该对象的 `__proto__` 设置为 `man.prototy
javascript 复制代码
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

javascript 复制代码
Object.create(People.prototype);
//创建一个新People.prototype对象,它的原型指向People.prototype

class实现

js 复制代码
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());(无)

面向对象编程

封装

  1. 私有属性

    _约定,#真语

    同样有静态属性和方法

    js 复制代码
    class Person {
      constructor(name, age) {
        this._name = name; // 使用下划线表示私有属性
        this._age = age;
      }
    }
  2. 私有方法

    js 复制代码
    class animal{
        #name;
        constructor(name){
            this.#name=name
            this.#firstPrint()
        }
        
        getName(){
            return this.#name
        }
    
        #firstPrint(){
            console.log(this.#name);
            
        }
        firstPrint(){
            console.log(this.#name);
            
        }
    }
    let dog =new animal('dog')
    dog.firstPrint()

    带#与不带#可以同时存在,为俩种不同的方法

    还可以组合私有静态

js 复制代码
class Cat extends Animal{
    static  #count=0

    constructor(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 关键字被调用,以及调用时的构造函数是什么。

js 复制代码
// 模拟抽象类
class Shape {
    constructor() {
        if (new.target === Shape) {
            throw new Error("Cannot instantiate abstract class");
        }
    }
    
    // 抽象方法
    area() {
        throw new Error("Abstract method must be implemented");
    }
}

多态

实现多态发生原型链的分支

js 复制代码
class Cat extends Animal{
    static  #count=0

    constructor(name){
        super()
        this.name=name;
        (Cat.#count)++
    }
  
    static getNum(){
        return Cat.#count
    }
    Print(){
        console.log( `cat: ${this.name}`);
        
    }
}

class dog extends Animal{
    static #count=0
    constructor(name){
        super()
        this.name=name;
        (dog.#count)++
    }
    static getNum(){
        return dog.#count
    }
    Print(){
        console.log(`dog: ${this.name}`);
        
    }
}

总结

并未含有java类似的关键字(abstract)严格声明,而是通过抛出错误等来进行限制

异步编程

基础循环

遵循同步任务->微任务->宏任务

清空微任务队列后,才会进入下一次宏任务,如此循环
微任务由js自身发起的,如promise
宏任务由浏览器发起,如settimeout

javascript 复制代码
setTimeout(() => {
  // 宏任务
  console.log('setTimeout');
}, 0);

new Promise((resolve, reject) => {
  resolve();
  console.log('promise1'); // 同步任务
}).then((res) => {
  // 微任务
  console.log('promise then');
});

console.log('同步任务'); // 同步任务

解析

  1. 第一个宏任务setTimeout暂存,
  2. 执行promise的构造函数(同步任务)//修改promise的状态,触发then的微任务暂存并输出promise1
  3. 执行最终的log输出同步任务
  4. 微任务队列不为空,执行输出promise then
  5. 执行最终宏任务 输出setTimeout

输出顺序

javascript 复制代码
promise1
同步任务
promise then
setTimeout

宏任务嵌套微任务

javascript 复制代码
new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve();
    console.log('setTimeout'); // 宏任务
  }, 0);
  console.log('promise1');
}).then((res) => {
  // 微任务
  console.log('promise then');
});

console.log('同步任务');
  1. 暂存promise构造函数中的宏任务并输出promise1
  2. 由于promise的状态在宏任务中改变,故then还未触发,输出最后的同步任务
  3. 此时 微任务未空,执行暂存的宏任务, resolve();触发微任务,并输出同步任务promise1'
  4. 执行then输出promise then