文章目录
- 原型链关键字总结
- 原型对象: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