前端JS-Day24
JS高级:
面向过程编程POP:分析解决问题的步骤,按照步骤解决问题。
面向对象编程POP:将事务分解为一个个对象,按照对象的功能来解决问题。
面向对象编程具有灵活、易于维护和开发、代码可复用的特点。
面向对象的三大特性:封装性、继承性、多态性
构造函数体现了面向对象的封装特性。
面向对象比面向过程性能低!
对象:特指的某一个,通过类实例化产生的对象。
类:抽取了对象的公共部分,泛指的某一大类
面向对象思维特点:
1.抽取(抽象)对象共用的属性和行为组织(封装)成一个类(模板)
2.对类进行实例化、获取类的对象。
创建类:
1.通过class关键字创建类,通过new关键字生成实例。
2.类里有constructor函数,可以接受传入的参数,同时返回实例对象。
3.constructor函数是只要new生成实例时就会调用,不编写该函数,也会自动生成并去调用。
4.语法规范:创建类名后不需要加括号,生成实例类后加小括号,构造函数不需要加fuction!
5.多个函数间不需要加逗号!
类的继承:extends关键字、super关键词
extends:用于子类继承父类的属性和方法。
super:用于在子类中调用父类的函数,可以调用父类的构造函数或普通函数。
<script>
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
sum() {
console.log(this.x + this.y);
}
}
class Son extends Father {
constructor(x, y) {
super(x, y);
// 调用父类的构造函数!
}
}
let son = new Son(2, 4); //输出6
son.sum();
</script>
继承中的属性和方法的查找原则:就近原则
继承中,如果实例化子类输出一个方法,先看子类是否拥有该方法,如果有就先执行子类的,否则去执行父类中的方法。
子类构造函数中,super必须在this之前使用(必须先调用父类构造方法,再去使用子类构造方法)!
<script>
class Father {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class Son extends Father{
constructor(x, y) {
super(x, y);
this.x = x;
this.y = y;
// super必须在子类this之前调用
}
}
</script>
注意事项:
即每个对象实例都有一个对象原型属性__proto__,执行某些方法时,若对象自身没有该方法,则通过对象原型属性去寻找构造函数原型对象prototype中的方法。
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function () {
console.log('原型对象');
}
let a = new Star('a', 1);
console.log(a.__proto__ === Star.prototype); //true
// a.proto即实例化对象的原型对象 Star.prototype即对象原型
</script>
constructor函数:即构造函数本身,该属性被__proto__(对象原型)和prototype(原型对象)共有。
constructor用于指回构造函数:当原型以对象形式赋值时导致覆盖,就要利用constructor导回!
关键点:↓↓↓↓↓↓↓↓↓↓↓↓
如果对对象原型以对象的形式进行赋值,会造成对象的覆盖,导致实例化对象的constructor无法将指回到构造函数本身,这时我们要采用constructor属性对其进行重新定向,令其重新指回到对象的构造函数本身。
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype = {
constructor: Star,
// 指回Star对象
sing: function () {
console.log('原型对象');
},
dance: function () {
console.log('constructor');
}
}
// 相当于对对象原型赋值,造成对象覆盖,constructor无法指回
构造函数,实例,原型对象的三角关系:每个构造函数都有一个prototype原型对象,每一个对象都有一个__proto__属性,指向他的prototype原型对象。
原型链:现有的构造函数、原型对象、对象实例之间的链式关系。
每个对象都有一个__proto__属性,它指向prototype原型对象。而prototype原型对象又具有一个自己的prototype原型对象,同样通过原型__proto__属性指向,这样层层往上直到Object原型对象的prototype为null。
Javascript的原型链成员查找机制:就近原则,依靠__proto__属性向上查找它的原型(类似继承)
instanceof:用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上,简单来说就是检测是否属于某个构造函数。
原型对象的this指向:构造函数和原型对象中的this都指向实例对象(即调用者)
扩展内置对象:只能采取对象.prototype.方法名 = fuction(){}的方法扩展。
<script>
console.log(Array.prototype);
Array.prototype.sum = function() {
let sum = 0;
for(let i =0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
let a = [1,2,3];
console.log(a.sum());
console.log(Array.prototype);
console.log(a.__proto__);
</script>
继承:在ES6之前不存在extends关键字:
① 需要通过构造函数+原型链的方式实现继承,即组合继承。使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。
② 直接通过构造函数+原型对象的方式实现原型继承。
1.组合继承:
call函数:1.直接调用函数 2.修改this指向
<script>
function fn () {
console.log('213');
console.log(this);
}
var o = {
name: 'lwh'
};
// 1.call()调用函数
fn.call();
// 输出213 和 window对象
// 2.修改this指向
fn.call(o);
// 输出213 和 o对象
</script>
利用call方法可以实现继承关系,call修改this指向,并将相同参数传入其中,自定义参数则再用this创建。类似于es6中的super方法和extends一同实现。
<script>
function Father (uname, age) {
this.uname = uname;
this.age = age;
}
function Son(uname, age, score) {
Father.call(this, uname, age);
this.score = score;
}
// ES5
class Fathers {
constructor(uname, age) {
this.uname = uname;
this.age = age;
}
}
class Sons extends Fathers{
constructor(uname, age, score) {
super(uname, age);
this.age = age;
}
}
// ES6
</script>
借用父构造函数继承方法:ES6后使用extends即可,在ES5时,需要采用给子对象的原型对象赋值为父元素。
组合继承的最终形式:① 使用父类的构造函数生成自己的属性利用call改变this ② 利用子构造函数的原型prototype指向new Father()继承到父类的属性和方法。③ 最后使Son原型的constructor指回Son。
即子元素的prototype即子元素的原型对象成为了一个新的父元素的实例,但此时子元素的原型对象已发生改变,所以要修改原型对象的constructor值,使其重新指回子元素的构造函数。由于__proto__对象原型的存在,故能继承到父类的方法。
function Father (uname, age) {
this.uname = uname;
this.age = age;
}
Father.prototype.money = function (){
console.log('$$$');
}
Son.prototype = new Father();
Son.prototype.constructor = Son;
function Son(uname, age, score) {
Father.call(this, uname, age);
this.score = score;
}
原型继承:
原型继承的问题:直接给Man和Women的原型对象设置为Person会导致地址相同,对原型修改则对Person也进行了修改成为了公共方法,故只给women设置的方法会被man访问!
const Person = {
eyes: 2,
head: 1
}
Women.prototype = Person;
Women.prototype.constructor = Women;
function Women() {
}
Women.prototype.baby = function () {
console.log(123);
}
Man.prototype = Person;
Man.prototype.constructor = Man;
function Man() {
}
const p1 = new Women();
const p2 = new Man();
console.log(p1.baby());
console.log(p2.baby()); //此时均可输出baby的方法
原型继承的改进:对父类进行构造函数的封装,然后再对子对象的原型进行new实例化:(原型继承)
function Person() {
this.eyes = 2;
this.mouth = 1;
}
Women.prototype = new Person();
Women.prototype.constructor = Women;
function Women() {
}
Women.prototype.baby = function () {
console.log(123);
}
Man.prototype = new Person();
Man.prototype.constructor = Man;
function Man() {
}
const p1 = new Women();
const p2 = new Man();
console.log(p1.baby());
console.log(p2.baby());
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?