本文详细解析JavaScript ES6中Class类的实现原理。从ES5构造函数到ES6语法的演变入手,阐述constructor构造函数的作用,深入讲解extends继承机制及super关键字的使用限制,并分析static静态属性和方法的调用规则与应用场景,帮助开发者掌握面向对象编程的核心概念。
ES6 Class类概述与语法演变
在JavaScript ES6标准发布之前,语言中并不存在Class(类)这一概念。当时,生成实例对象的传统且主要的方式是通过定义构造函数来实现的。
例如:
function Mold(a,b){
this.a=a;
this.b=b;
}
Mold.prototype.count=function(){
return this.a+this.b;
};
let sum=new Mold(1,2);
console.log(sum.count()) //3
这种写法与传统面向对象语言存在较大差异,代码结构相对繁杂,可读性较差。
ES6标准引入了更加贴近其他主流面向对象语言的语法,正式引入了Class(类)的概念。类作为对象的模板,允许开发者通过class关键字来定义类,其用法类似于Python、Java等语言。
需要注意的是,ES6中的大部分功能在ES5中均能通过其他方式实现。ES6的class本质上可以看作是一种语法糖,它并未改变JavaScript基于原型的本质,而是提供了更简洁、更清晰的定义类的方式,使其更接近传统的面向对象编程思想。对比上述ES5写法,使用ES6实现相同功能的代码如下:
class Mold{
constructor(a,b){
this.a=a;
this.b=b;
}
count(){
return this.a+this.b;
}
}
let sum=new Mold(1,2);
console.log(sum.count()) //3
在上述ES6代码中,定义类时只需使用class关键字,且类中的方法无需再使用function关键字进行定义。此外,ES6引入了constructor方法,专门用于定义类的构造逻辑;该方法中的this关键字指向新创建的实例对象。对比前文ES5中的构造函数Mold,它实际上对应于ES6中Mold类的constructor方法。
constructor构造函数的原理
constructor
在ES6中,实例对象的构造函数即为该类本身。当使用new关键字实例化类(如new 类名())时,实际上就是执行了该类的constructor函数。
例如:
class Mold{
constructor(){
console.log("aaa")
}
}
let m=new Mold();// aaa
console.log(m.constructor===Mold);//true
以上代码展示了Mold类的constructor逻辑,在实例化对象时会自动执行默认的constructor方法。
JavaScript中任何对象都拥有构造函数,且该构造函数与当前对象所属的类是一致的。
例如:
let arr=new Array();
console.log(arr.constructor===Array);//true
let str=new String();
console.log(str.constructor===String);//true
let obj=new Object();
console.log(obj.constructor===Object);//true
类的继承extends机制
2. 类的继承 extends
子类通过extends关键字继承父类后,将自动获得父类的所有方法和属性,这其中包括静态方法和静态属性。
如果子类在定义时没有显式声明constructor方法,JavaScript引擎会默认为其添加一个空的constructor方法。
因此,任何子类都必然拥有constructor方法。
例如:
//class 类名 extends 被继承的类{}
Class Father{
constructor(){
}
sum(){
console.log("abc");
}
static fn(){
console.log("hello")
}
}
Class Son extends Father{
}
let s=new Son();
s.sum()//abc,继承了父类的sum()方法
Son.fn()//hello 继承了父类的静态方法fn()
继承后的子类对父类方法的处理通常有三种方式:
1). 完全继承:如果子类不需要修改父类方法的行为,则无需重写该方法,子类执行的方法内容与父类完全相同。
2). 重写覆盖:如果子类需要改变父类方法的逻辑,只需在子类中重新定义该方法即可覆盖继承过来的父类方法。
3). 加工扩展:子类可以使用super关键字调用父类的方法或属性,在此基础上结合子类自身特有的方法和属性进行扩展。
super关键字的使用限制
3. super
在子类中调用父类的构造函数时,直接使用super()即可,并且可以向super传递参数以初始化父类状态。
在子类的构造函数中,必须首先调用super()方法,之后才能使用this关键字。如果在调用super()之前使用this,程序将报错。
例如:
//super.父类函数();
class Father{
constructor(){
console.log("bbb");
}
}
class Son extends Father{
constructor(x){
this.x=x;//ReferenceError,报错
super();
this.x=x;//正确
}
}
let sum=new Son();//bbb
static静态属性与方法的应用
4. 类的static静态
在类的属性或方法定义前添加static关键字,即可定义类的静态属性和静态方法。
所有的静态属性和静态方法都无法通过实例化的对象进行调用。
静态属性和静态方法必须通过类本身来调用。它们是类的专属成员,与具体的实例化对象无关。常见的例子包括数组工具方法Array.from()和数学方法Math.random()。
例如:
class Mold{
static x=0;
y=1;
static fn1(){
console.log("aaa")
}
fn2(){
console.log("bbb");
}
}
let m=new Mold();
console.log(m.x,m.y);//undefined , 1
m.fn1(); // TypeError
m.fn2(); // bbb
//需要通过类来调用
Mold.fn1(); //aaa
console.log(Mold.x);//0
静态成员的主要使用场景包括:
一般静态方法用于解决针对某一类对象的通用问题。
它们处理的是具体类型层面的逻辑,而非针对某个具体对象实例的逻辑。
静态属性通常用于存储该类的一系列通用属性变量。
这种存储机制在类定义加载时即已存在,相当于全局变量,可以在代码的任何位置调用,且不会被自动销毁或回收。
以上就是本文关于JavaScript ES6 Class类实现原理的全部内容,希望对大家的学习有所帮助,也欢迎大家继续支持本站。