ES6--》读懂JS中—Class类

简介: 详解JS中class类的使用

Class类

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰,更像面向对象编程的语法。

初识class

之前ES5通过构造函数实现实例化的方法

<script>// 定义人类functionPeople(name,age){
this.name=namethis.age=age    }
// 添加方法People.prototype.say=function (){
console.log('hello world');
    }
// 实例化方法letperson=newPeople('张三',18)
person.say()//hello worldconsole.log(person);//People {name: '张三', age: 18}</script>

ES6 class 方法实现

constructor()方法是类的默认方法,通过 new 命令生成对象实例时,自动调用该方法,一个类必须有constructor()方法,如果没有显示定义,一个空的constructor()方法会被默认添加。

<script>// classclassPeople {
// 构造方法 名字是固定格式不能修改constructor(name,age){
this.name=namethis.age=age        }
// 方法必须使用该语法,不能使用 ES5 的对象完整形式say(){
console.log('hello world');
        }
    }
// 实例化对象letperson=newPeople('张三',18)
person.say()//hello worldconsole.log(person);//People {name: '张三', age: 18}</script>

class中getter和setter设置

<script>classPeople {
getname(){
console.log('我是张三');
return'这是我的名字'//如果不写return,默认是undefined        }
setname(Name){//形参必须有console.log('我的名字被修改了');
        }
    }
// 实例化对象letp=newPeople()
// 只要读取 p 的实例化属性,就会执行 get 关键字函数里面代码,而且这个函数的返回值就是属性的一个值console.log(p.name);
// 只要对 name 属性进行一个修改,如果有set关键字函数,就会执行该函数p.name='f'</script>

图片.png

表达式方式书写

和函数一样,类可以用表达式定义书写,需要注意的是:定义的类名只能在Class内部使用,指代当前类,在Class外部,类只能用自己定义等于类的常量。

<script>constmyClass=classMe {
getClass(){
returnMe.name//返回类名        }
    }
letc=newmyClass()
console.log(c.getClass())//MeMe.name//Me is not defined // 如果类的内部没用到的话,可以省略Me,也就是可以写成下面的形式constMyClass=class {};
</script>

静态属性与静态方法

静态属性是指 Class 本身的属性,即 Class.propName,而不是定义在实例对象 this 上的属性。

实例对象和函数对象的属性是不相通的,实例对象的属性和构造函数的原型对象相通,实例对象只能继承构造函数原型中的属性和方法。

<script>functionPeople(){
    }
// 函数属性和方法People.name='张三'People.say=function(){
console.log('hello world');
    }
// 原型对象属性和方法People.prototype.age=18// 实例化对象letp=newPeople()
console.log(People.name,People.say());
console.log(p.age);
console.log(p.name,p.say());
</script>

图片.png

以class方法展示,因为ES6明确规定,Class内部只有静态方法,没有静态属性,而要想得到设置静态属性,需要在实例属性前面加上 static 关键字;静态方法也要加上 static 关键字,表示该方法不会被实例继承,而是直接通过类来调用。

<script>classPeople {
// 静态属性staticname='张三'staticsay(){
console.log('hello world');
        }
    }
letp=newPeople()
console.log(p.name);//undefinedconsole.log(People.name);//张三</script>

私有属性和私有方法

常见需求:私有属性和方法,是只能在类内部访问的属性和方法,外部不能访问,有利于代码的封装。

ES6中正式为class添加了私有属性和方法,方法是在属性和方法名之前使用 # 表示,如果不带 # ,会被当作另一个属性和方法。

<script>classperson {
// 私有属性#nameconstructor(name){
this.#name = name        }
// 私有方法#sayName(){returnthis.#name        }
result(){
console.log(this.#name);        }
    }
letp=newperson()
p.result='张三'console.log(p);//person {result: '张三', #sayName: ƒ, #name: undefined}p.#name//报错</script>

当我们想判断某个类的私有属性是否存在时,我们可以用 in 运算符进行判断。

<script>classA {
#foo = 0;m() {
console.log(#foo in this); // trueconsole.log(#bar in this); // Private field '#bar' must be declared in an enclosing class(提示我们:私有字段“#bar”必须在封闭类中声明)        }
    }
leta=newA()
a.m()
</script>

Class继承

构造函数实现继承

通过原型链进行继承,如果有不熟悉原型链的朋友,可以看一下我之前的文章:原型和原型链

<script>// 动物functionAnimals(name,age){
this.name=namethis.age=age    }
Animals.prototype.call=function(){
console.log('我是动物');
    }
// 狗functionDog(name,age,color,gender){
// 改变this的指向,继承父类Animals.call(this,name,age)
this.color=colorthis.gender=gender    }
// 设置子类构造函数的原型Dog.prototype=newAnimals//此时子类的实例对象就会继承父类上面的方法Dog.prototype.constructor=Dog// 声明子类的方法Dog.prototype.say=function(){
console.log('汪汪汪!!!');
    }
// 子类对象进行实例化constd=newDog('小明',3,'棕色','雄')
console.log(d);
</script>

图片.png

class类实现继承

class可以通过 extends 关键字实现继承,让子类继承父类属性和方法,可以看出 extends 的写法比上文 原型链继承 清晰方便的多。

<script>classAnimals {
// 构造方法constructor(name,age){
this.name=namethis.age=age        }
// 父类成员的属性call(){
console.log('我是动物');
        }
    }
classDogextendsAnimals {
// 构造方法constructor(name,age,color,gender){
// 调用父类方法,需要用super(),super()就是父类的constructor()方法super(name,age)
this.color=colorthis.gender=gender        }
// 子类独有的方法say(){
console.log('汪汪汪!!!');
        }
// 当子类和父类重名时,优先调用的是子类的方法call(){
console.log('我也是动物');
// 如果想调用父类方法,使用如下语句:super.父类方法()super.call()
        }
    }
// 实例化子类对象constd=newDog('小明',3,'棕色','雄')
console.log(d);
d.call()
d.say()
</script>

图片.png

super 关键字

上面代码用到 super 这个关键字,这里简单说明一下:子类继承父类的 constructor() 构造函数中必须要有 super(),代表调用父类的构造函数,没有就会报错,super虽然代表父类的构造函数,但是返回的是子类的实例,即super内部的this指的是子类的实例。作为函数时,super() 只能用在子类的构造函数中,用在其他地方就会报错。

判断继承是否存在

Object.getPrototypeOf()方法可以用来从子类上获取父类,所以可以用来判断一个类是否继承另一个类。

<script>classpeople {}
classboyextendspeople {}
console.log(Object.getPrototypeOf(boy) ===people);//true</script>

静态属性和方法继承

父类的静态属性和方法也能被子类继续,如下:

<script>classpeople {
// 父类静态属性 属性为数值staticage=18// 父类静态属性 属性为对象statich= {height:180}
// 父类静态方法staticsay(){
console.log('hello world');
        }
    }
// 子类继承父类classboyextendspeople {
constructor(){
// 调用父类的构造函数super()
// boy类继承静态属性时,会采用浅拷贝,拷贝父类静态属性的值,因此people.age和boy.age是两个彼此独立的属性。boy.age--// 如果父类的静态属性的值是一个对象,那么子类的静态属性也会指向这个对象,因为浅拷贝只会拷贝对象的内存地址所以,子类修改这个对象的属性值,会影响到父类。boy.h.height--        }
    }
// 实例化子类letb=newboy()
boy.say()
console.log(people.age);
console.log(boy.age);
console.log(boy.h.height);
console.log(people.h.height);
console.log(b);
</script>

图片.png

私有属性和方法继承

私有属性和方法只能定义在它本身的class里面使用,所以子类会继承父类所有的属性和方法除了私有属性和方法,那么如何让子类访问到父类中的私有属性和方法呢?如果父类定义了私有属性的读写方法,子类就可以通过这些方法,读取私有属性。

<script>classpeople {
#name = '张三'// 定义用来读取私有属性和方法的函数getName(){
returnthis.#name        }
    }
classboyextendspeople {
constructor(){
// 调用父类的构造函数super()
console.log(this.getName());//张三        }
    }
letb=newboy()
</script>

class显示原型与隐式原型关系

每个对象都有隐式原型 __proto__ 属性,指向对应的构造函数的显示原型 prototype 属性,class作为构造函数的语法糖,同时也具有 prototype 属性和 __proto__ 属性,所以存在两条继承链。当然这里这做一个了解。

<script>classpeople {}
classboyextendspeople{}
// 子类的__proto__属性,表示构造函数的继承,总是指向父类。console.log(boy.__proto__===people); // true// 子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。console.log(boy.prototype.__proto__===people.prototype); // true</script>


相关文章
|
25天前
|
缓存 JavaScript 数据安全/隐私保护
js开发:请解释什么是ES6的Proxy,以及它的用途。
`ES6`的`Proxy`对象用于创建一个代理,能拦截并自定义目标对象的访问和操作,应用于数据绑定、访问控制、函数调用的拦截与修改以及异步操作处理。
17 3
|
25天前
|
JavaScript
js开发:请解释什么是ES6的类(class),并说明它与传统构造函数的区别。
ES6的类提供了一种更简洁的面向对象编程方式,对比传统的构造函数,具有更好的可读性和可维护性。类使用`class`定义,`constructor`定义构造方法,`extends`实现继承,并可直接定义静态方法。示例展示了如何创建`Person`类、`Student`子类以及它们的方法调用。
21 2
|
26天前
|
自然语言处理 JavaScript 网络架构
js开发:请解释什么是ES6的箭头函数,以及它与传统函数的区别。
ES6的箭头函数以`=&gt;`定义,简化了函数写法,具有简洁语法和词法作用域的`this`。它无`arguments`对象,不能用作构造函数,不支持`Generator`,且不改变`this`、`super`、`new.target`绑定。适用于简短表达式,常用于异步编程和高阶函数。
17 5
|
27天前
|
JavaScript 前端开发
js开发:请解释原型继承和类继承的区别。
JavaScript中的原型继承和类继承用于共享对象属性和方法。原型继承利用原型链查找属性,节省内存但不支持私有成员。类继承通过ES6的class和extends实现,支持私有成员但占用更多内存。两者各有优势,适用于不同场景。
18 0
|
1月前
|
前端开发 JavaScript 开发者
探索JavaScript ES6的八种常见使用技巧:开启现代编程之旅
探索JavaScript ES6的八种常见使用技巧:开启现代编程之旅
|
25天前
|
JavaScript 前端开发
js开发:请解释什么是ES6的async/await,以及它如何解决回调地狱问题。
ES6的`async/await`是基于Promise的异步编程工具,能以同步风格编写异步代码,提高代码可读性。它缓解了回调地狱问题,通过将异步操作封装为Promise,避免回调嵌套。错误处理更直观,类似同步的try...catch。
|
25天前
|
JavaScript
js开发:请解释什么是ES6的Generator函数,以及它的用途。
ES6的Generator函数是暂停恢复的特殊函数,用yield返回多个值,适用于异步编程和流处理,解决了回调地狱问题。
16 6
|
25天前
|
存储 JavaScript 索引
js开发:请解释什么是ES6的Map和Set,以及它们与普通对象和数组的区别。
ES6引入了Map和Set数据结构。Map的键可为任意类型,有序且支持get、set、has、delete操作;Set存储唯一值,提供add、delete、has方法。两者皆可迭代。示例展示了Map和Set的基本用法,如添加、查询、删除元素。
13 2
|
25天前
|
JavaScript
js开发:请解释什么是ES6的Symbol,以及它的用途。
ES6的Symbol数据类型创建唯一值,常用于对象属性键(防冲突)和私有属性。示例展示了如何创建及使用Symbol:即使描述相同,两个Symbol也不等;作为对象属性如`obj[symbol1] = &#39;value1&#39;`;也可作枚举值,如`Color.RED = Symbol(&#39;red&#39;)`。
|
25天前
|
JavaScript
js开发:请解释什么是ES6的扩展运算符(spread operator),并给出一个示例。
ES6的扩展运算符(...)用于可迭代对象展开,如数组和对象。在数组中,它能将一个数组的元素合并到另一个数组。例如:`[1, 2, 3, 4, 5]`。在对象中,它用于复制并合并属性,如`{a: 1, b: 2, c: 3}`。
12 3