ES6新特性实现面向对象编程,上万字详解用class语法定义类

了解ES5中对象概念的小伙伴应该知道,对象中有两个存储器属性,分别为 gettersetter,它们是对象中某个属性的特性,并且可以通过 Object.getOwnPropertyDescriptor()方法获得对象中某个属性的属性描述符

//查询Person.prototype中属性number的属性描述符

Object.getOwnPropertyDescriptor(Person.prototype, ‘number’)

/*

{

get: [Function: get number],

set: [Function: set number],

enumerable: false,

configurable: true

}

*/

因此,我们在 class类中写的 getset 函数只是设置了某个属性的属性特性,而不是该类的方法。

(5) 静态方法


class类中的方法都是写在原型上的,因此生成的实例对象可以直接调用。现在有一个关键字 static,若写在方法的前面,则表示此方法不会被写在原型上,而只作为该类的一个方法,这样的方法叫做静态方法;相反,若没加关键字 static 的方法就叫做非静态方法

我们来看一下具体的例子

class Person {

show() {

console.log(‘我是非静态方法show’)

}

static show() {

console.log(‘我是静态方法show’)

}

static hide() {

console.log(‘我是静态方法hide’)

}

}

Person.show() // 我是静态方法show

var person = new Person()

person.show() // 我是非静态方法show

person.hide() /* person.hide()

^

TypeError: person.hide is not a function

*/

我们分析一下这个例子:

首先我们直接调用 Person类的 show方法,实际调用的就是有关键字 staticshow方法;

然后我们生成了一个实例对象 person,然后调用 person实例对象上的 show方法,实际调用的就是没有关键字 staticshow方法,从这我们可以看出,静态方法和非静态方法可以重名

最后我们调用了 person实例对象上的 hide方法,但报错了,因为在 class类中,我们定义的是静态方法,即有关键字 statichide方法,也就是此方法没有被写进类的原型中,因而实例对象 person无法调用此方法。


我们都知道,类中定义的方法内的 this指向的是实例对象,但在静态方法中的 this指向的是类对象

我们来看一个例子

class Person {

constructor() {

this.name = ‘Lpyexplore’

}

show() {

console.log(this.name)

}

static cite() {

this.show()

}

static show() {

console.log(‘我是静态方法show’)

}

}

Person.cite() // 我是静态方法show

var person = new Person()

person.show() // Lpyexplore

我们来分析一下这段代码:

首先我们直接调用 Person类的静态方法 cite,执行代码 this.show(),因为静态方法中的 this指向 Person类,所以其实调用的就是静态方法 show,所以打印了 我是非静态方法show

然后我们生成了一个实例对象 person,调用 personshow方法,因为在非静态方法 show中,this指向的是实例对象 person,因此打印了 Lpyexplore

(6)实例属性的简易写法


原先我们为实例对象定义的属性都是写在 constructor函数中的,例如

class Person {

constructor() {

this.name = ‘Lpyexplore’

this.age = 18

}

show() {

console.log(‘hello world’)

}

}

var person = new Person()

console.log(person.name) // Lpyexplore

console.log(person.age) // 18

现在我们用实例对象的属性新写法来改写以上代码

class Person {

name = ‘Lpyexplore’

age = 18

show() {

console.log(‘hello world’)

}

}

var person = new Person()

console.log(person.name) // Lpyexplore

console.log(person.age) // 18

这种写法就是将 constructor函数中的属性定义放到了外部,同时不需要写 this,因为此时的属性定义与其他方法也处于同一个层级。因此这样的写法看上去就会比较一目了然,一眼就能看到实例对象有几个属性有几个方法。

虽然这样的写法比较简便,但也有一定的缺点,那就是用这种写法定义的属性是写死的。

我们都知道在生成实例对象时,可以传入参数,传入的参数会作为 constructor函数的参数,所以我们在 constructor函数中定义的属性的值就可以动态地根据参数改变而改变。

而实例属性的简易写法就无法根据参数的改变而改变,所以用这种写法的时候需要稍微注意一下。

(7)静态属性


既然有静态方法,那怎么能少了静态属性呢?其实,原本的 class类中是没有静态属性这个概念的,后来才加上的。静态属性就只属于 class类的属性,而不会被实例对象访问到的属性。

同样的,静态属性的申明就是在属性的前面加关键字 static。上面我们刚讲到,实例对象的属性的定义可以不写在 constructor函数中,而是直接写在外部,此时我们可以暂且称之为非静态属性

class Person {

name = ‘我是实例对象的name属性’

static name = ‘我是Person类的name属性’

static age = 18

}

console.log(Person.name) // 我是Person类的name属性

var person = new Person()

console.log(person.name) // 我是实例对象的name属性

console.log(person.age) // undefined

这段代码中,定义了非静态属性 name 、静态属性 name 和 静态属性 age

因此我们在访问 Person类的 name属性时,访问的是静态属性 name,即加了关键字 staticname属性;

生成实例对象 person,访问其 name属性,实际访问的就是非静态属性 name,即没有加关键字 staticname属性;

最后我们访问实例对象 personage属性,返回了 undefined。因为 age是静态属性,是属于 Person类的,而不会被实例对象 person访问到。

三、class的继承

===================================================================

继承是面向对象编程中一个非常重要的概念,那什么是继承呢?

(1)继承的概念


继承就是使一个类获得另一个类的属性和方法。就好比一个手艺精湛的师傅传授给你他所有的毕生绝学,那么就相当于你继承了他,此时你既学会了你师傅教你的技能,同时你也一定有属于自己的技能,这不是从你师傅那学来的。

(2)ES5中实现继承


其实在ES5中是通过修改原型链实现继承的,我们可以来看一下简单的例子

// 创建构造函数 Parent

function Parent() {

// 定义了实例对象属性 name1

this.name1 = ‘parent’

}

// 为 Parent原型定义方法 show1

Parent.prototype.show1 = function() {

console.log(‘我是Parent的show1方法’)

}

// 创建构造函数 Child

function Child() {

this.name2 = ‘child’

}

// 将构造函数 Child的原型设置成 Parent的实例对象

Child.prototype = new Parent()

// 为Child原型定义方法 show2

Child.prototype.show2 = function() {

console.log(‘我是Child的show2方法’)

}

// 生成实例对象 child

var child = new Child()

console.log(child.name1) // parent

console.log(child.name2) // child

child.show1() // 我是Parent的show1方法

child.show2() // 我是Child的show2方法

我们可以看到,我们通过改变构造函数 Child的原型 prototype为构造函数 Parent生成的实例对象,实现了继承,即通过构造函数 Child生成的实例对象具有 Parent中定义的属性name1和方法show1,同时也具有属于自己的属性name2和方法show2

(3)ES6中class实现继承


ES5中实现继承的写法显然有些麻烦,所以在 class类中,我们可以通过关键字 extends来实现继承

我们来改写一下ES5中的继承实现

class Parent{

constructor() {

this.name1 = ‘parent’

}

show1() {

console.log(‘我是Parent的show1方法’)

}

}

// Child类 继承 Parent类

class Child extends Parent{

constructor() {

super();

this.name2 = ‘child’

}

show2() {

console.log(‘我是Child的show2方法’)

}

}

var child = new Child()

console.log(child.name1) // parent

console.log(child.name2) // child

child.show1() // 我是Parent的show1方法

child.show2() // 我是Child的show2方法

继承得实现整体上看上去非常得简洁

在上述代码中,我们看到了,我们在定义 Child类时用到了关键字 extends,申明了 Child类继承Parent类,同时在 Child类得 constructor函数中调用了 super函数。仅仅用两个关键字就实现了继承,这里我们要对 super进行详细得讲解

(4)super


在ES6中规定了,在子类继承了父类以后,必须先在子类的 constructor函数中调用 super函数,其表示的就是父级的 constructor函数,作用就是为子类生成 this对象,将父类的属性和方法赋值到子类的 this上。因此,若没有调用 super函数,则子类无法获取到 this对象,紧接着就会报错

class A{

constructor() {

this.name1 = ‘A’

}

}

class B extends A{

constructor() {

this.name2 = ‘B’

}

}

var b = new B()

/*

this.name2 = ‘B’

^

ReferenceError: Must call super constructor in derived class before accessing ‘this’ or returning from derived constructor

*/

上述代码中,B类继承 A类,但 B类的 constructor函数中没有调用 super函数,因此没有生成 this对象,所以 this.name2 = 'B'就报错了

若子类省略了 constructor函数,则默认会帮你调用 super函数的

class A{

constructor() {

this.name1 = ‘A’

}

}

class B extends A{

}

var b = new B()

// 没有报错


super()代表的是父类的构造函数,其实 super还可以作为对象使用,即不作为函数调用。当 super在子类的普通方法内时,指向的是父类的原型对象;在子类的静态方法内时,指向的时父类

class A{

show1() {

console.log(‘我是A类的show1方法’)

}

}

class B extends A{

constructor() {

super()

}

show2() {

super.show1()

}

}

var b = new B()

b.show2() // 我是A类的show1方法

上述代码,B类继承 A类,其中 A类有一个 show1方法,是写在其原型 A.prototype上的,而在 B类的 show2方法中调用了 super.show1(),我们说过 super在普通的方法中指向的是父类的原型对象,所以 super.show1() 相当于 A.prototype.show1()

我们再来看一个 super在子类的静态方法中的例子

class A{

static hide1() {

console.log(‘我是A类的hide1方法’)

}

}

class B extends A{

constructor() {

super()

}

static hide2() {

super.hide1()

}

}

B.hide2() // 我是A类的hide1方法

上述代码,B类继承 A类,B类在其静态方法 hide2中调用了 super.hide1(),因为 super在静态方法中指向的是父类,所以 super.hide1() 就相当于 A.hide1()

说到静态方法,其实类的继承,也是可以继承静态方法的

class A{

static show() {

console.log(‘我是A类的show方法’)

}

}

class B extends A{

}

B.show() // 我是A类的show方法


还需要注意的是,当我们在子类的普通方法中通过 super调用父类的方法时,方法中的 this指向的是当前子类的实例对象

class A {

constructor() {

this.name = ‘Jack’

}

show1() {

console.log(this.name)

}

}

class B extends A{

constructor() {

super();

this.name = ‘Lpyexplore’

}

show2() {

super.show1()

}

}

var b = new B()

b.show2() // Lpyexplore

那么,当我们在子类的静态方法中通过 super调用父类的方法时,方法中的 this指向的是子类,而不是子类的实例对象

class A {

constructor() {

this.x = 1

}

static show1() {

console.log(this.x)

}

}

class B extends A{

constructor() {

super();

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
img

前端资料汇总

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。

首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。

更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。
找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。
最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。
,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-WWBKrZLh-1710594501351)]
[外链图片转存中…(img-MuiFNCZP-1710594501351)]
[外链图片转存中…(img-kXFBzP9f-1710594501352)]
[外链图片转存中…(img-KOjS2YER-1710594501352)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-Usgd775a-1710594501353)]

前端资料汇总

开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】

我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。

首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。

更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。
找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。
最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值