ES6 class类

女爷i 2023-07-03 04:46 59阅读 0赞

ES6中的类

js中生成实例对象的传统方法是通过构造函数。而ES6提供了更接近传统语言的写法,引入了class类这个概念,作为对象的模板,通过class类关键字,可以定义类。

ES6的class可以看做一个语法糖而已,它的绝大部分功能,ES5都可以做到,只不过写法让对象原型的写法更加清晰。更像面向对象的语法而已:

ES5与ES6对比:

对比两者的写法:还是ES6看起来更加清晰、明了,里边有一个constructor方法,这就是构造方法,this关键字代表实例对象。height方法前面不需要加function,而且方法之间不可以加逗号。加了会报错!!!

  1. //ES5
  2. function Test(name,age){
  3. this.name = name;
  4. this.age = age;
  5. }
  6. Test.prototype.height = function(){
  7. console.log("170cm");
  8. }
  9. var test = new Test("lxc",20);
  10. //ES6
  11. class Test{
  12. constructor(name,age){
  13. // 类中的属性
  14. this.name = name;
  15. this.age = age;
  16. }
  17. // 原型上的方法
  18. height(){
  19. console.log("170cm");
  20. }
  21. }
  22. var test = new Test("lxc",20);

es6中类的原型prototype还在:

  1. class Test{
  2. name(){
  3. console.log("lxc")
  4. }
  5. age(){
  6. console.log("20")
  7. }
  8. height(){
  9. console.log("170cm");
  10. }
  11. }
  12. var test = new Test();
  13. console.log(Test.prototype)
  14. // 打印结果:
  15. // > {constructor: ƒ, name: ƒ, age: ƒ, height: ƒ}
  16. // > age: ƒ age()
  17. // > constructor: class Test
  18. // > height: ƒ height()
  19. // > name: ƒ name()
  20. // > __proto__: Object

上边代码,类里边所有的方法都是在原型上了。。。在类的实例上边调用方法,就是调用原型上的方法。

  1. class Test{}
  2. var test = new Test();
  3. console.log(test.constructor === Test.prototype.constructor) //true

上边代码,test是Test的实例,它的constructor方法就是Test类原型上的constructor的方法!!!

通过Object.assign( ) 向类的原型添加多个方法:

  1. class Test{}
  2. var test = new Test();
  3. Object.assign(Test.prototype,{
  4. name(){},
  5. age(){},
  6. height(){}
  7. })
  8. console.log(Test.prototype)

打印结果:

20190703102207559.jpg

是否可枚举:

ES6类中的方法都是不可枚举的 ( 也就是原型上的方法 ) ,与ES5中不同:

  1. class Test{
  2. constructor(){
  3. this.a = "a"
  4. }
  5. name(){}
  6. age(){}
  7. height(){}
  8. }
  9. var test = new Test();
  10. console.log(Object.keys(Test.prototype)) // []
  11. //取原型对象上边的方法
  12. console.log(Object.getOwnPropertyNames(Test.prototype))// ["constructor", "name", "age", "height"]

constructor方法:

创建一个类的时候,类里边必须有constructor方法,如果没有显式定义,js引擎会自动为它添加一个空的constructor方法。

  1. class Test{}
  2. // 等于
  3. class Test{
  4. constructor(){
  5. }
  6. }

constructor方法默认返回实例对象(即this),但也是完全可以指定返回另外一个对象。

  1. class Test{
  2. constructor(){
  3. return Object.create(null)
  4. }
  5. }
  6. var test = new Test();
  7. console.log(test instanceof Test) //false

上边代码,constructor函数返回一个全新的对象,结果导致实例对象不是Test类的实例。。。

注意点:

只要你写代码写在类或模块中,就只有严格模式下可用,因为ES6把整个语言升级到了严格模式。。。

类中的getter、setter

类中的getter与setter和Object.defineProperty()对一个属性的读取和赋值进行控制一样:它们都是对一个属性进行控制而出现的。

下边使用get和set相当于给age属性加上了getter和setter,这样就可以对age属性进行校验了,既可以设置初始化的值( 10 ), 你也可以为age赋值。

tips:

1、在属性前边加上get、set,该属性并不是在原型上的;

2、下边例子中,当我们给a赋值时,a.age = 100 相当于 a调用set方法;当获取a.age 时,相当于调用类中get方法;

3、在类中,我们通过使用get和set,可以非常方便的实现对属性进行控制,而传统对对象属性进行控制需要使用 Object.defineProperty()。

  1. class Person{
  2. constructor(data) {
  3. this.age = data
  4. }
  5. set age(data) {
  6. if(typeof(data) !== 'number') throw new Error('number property must be a number')
  7. this._age = data
  8. }
  9. get age() {
  10. return this._age
  11. }
  12. }
  13. const a = new Person(10)
  14. console.log( a.age ) // 10
  15. a.age = 100
  16. console.log(a.age) // 100

静态成员:

所为静态成员,就是通过类直接添加的属性或者在类型直接定义的属性或方法。(与python中的类中的类变量和实例变量类似)

类相当于实例的原型,所有在类中定义的方法,都会被实例所继承,(啰嗦一句前这段话的意思是:类上边的属性和方法都可以被实例调用)。**如果在一个方法前面加上static关键字,表示该方法不会被实例继承(也就是实例不能调用),而是直接通过类来调用,这就是”静态成员”。**

静态方法几个重要点:

**1、里边的this指向类,而不是实例;**

eg:下边代码:静态方法和非静态方法同名,静态方法this指向类,所以打印:” 我叫吕星辰:) “

  1. class Son{
  2. static name(){
  3. this.name();
  4. }
  5. static name(){
  6. console.log("我叫吕星辰:)")
  7. }
  8. name(){
  9. console.log("我是谁?")
  10. }
  11. }
  12. let son = new Son();
  13. Son.name()//我叫吕星辰:)

**2、在类中,静态方法可以与非静态方法重名;**

3、静态方法,可以被子类继承;

  1. eg:下边代码,子继承父类的静态方法,可以掉用age方法
  2. class Father{
  3. static age(){
  4. return "20"
  5. }
  6. }
  7. class Son extends Father{
  8. constructor(){
  9. super();
  10. }
  11. }
  12. var son = new Son();
  13. console.log(Son.age())//20
  14. **4class类种没有静态属性**

字段初始化器(ES7):

字段初始化器,就是类中实例初始化的简写,如下:

(某些属性在初始化时,是固定的,此时会用字段初始化器来初始化属性,实际上初始化的属性还是在实例中的!!!)

  1. class Person{
  2. constructor() {
  3. this.age = 20
  4. this.name = 'lxc'
  5. this.height = 180
  6. }
  7. }
  8. const a = new Person()
  9. console.dir(a)
  10. // 相当于(下边就是字段初始化器)
  11. class Person{
  12. age = 20
  13. name = 'lxc'
  14. height = 180
  15. }
  16. const a1 = new Person()
  17. console.dir(a1)

20200202140722540.png

tips:

1、添加在static上的字段初始化器,是静态方法(属性)

2、没有添加在static上的字段初始化器,属于实例对象上边的属性(方法)

3、字段初始化器是一个箭头函数时,里边的this指向类本身,比如:

  1. class Person{
  2. age = 20
  3. name = () => {
  4. alert('lxc,age为:' + this.age) // lxc,age为:20
  5. }
  6. height = 180
  7. }
  8. const a = new Person()
  9. console.dir(a.name())
  10. /*
  11. 上边相当于
  12. */
  13. class Person{
  14. constructor() {
  15. this.age = 20
  16. this.name = () => {
  17. alert('lxc,age为:' + this.age) // lxc,age为:20
  18. }
  19. this.height = 180
  20. }
  21. }
  22. const a = new Person()

class中的继承:

class继承是通过extends关键字实现继承,这比ES5的通过修改原型继承要清晰、方便。

eg:我们分别写下ES5和ES6构造函数继承:

  1. // +++++++++++ES5继承
  2. function Father(name,age){
  3. this.name=name;
  4. this.age = age;
  5. }
  6. Father.prototype.say = function(){
  7. alert("hello world");
  8. }
  9. var father = new Father();
  10. function Son(){
  11. Father.apply(this,["lxc",20]);
  12. }
  13. Son.prototype = Object.create(Father.prototype);
  14. Son.prototype.constructor = Son;
  15. var son = new Son();
  16. console.log(son.say())//hello world
  17. console.log(son.age,son.name)//20,lxc
  18. // +++++++++++++ES6继承
  19. class Father{
  20. constructor(name,age){
  21. this.name = name;
  22. this.age = age;
  23. }
  24. say(){
  25. alert("hello world");
  26. }
  27. }
  28. var father = new Father();
  29. class Son extends Father{
  30. constructor(){
  31. super("lxc",20); //相当于Father.call(this,···)
  32. }
  33. }
  34. var son = new Son();
  35. son.say()//hello world
  36. console.log(son.name)//lxc
  37. console.log(son.age)//20

上边代码:在constructor中出现super关键字,在这里表示父类构造函数,用来创建父类的this对象的。子类在继承父类时,constructor方法中,第一行必须运行super(),调用父类实例,否则会报错。。。这也不难理解,让子类的this指向父类构造函数,才能完成子类继承父类。

补充:

1、下边是三个类,A类被B类继承,B类被C类继承,要求封装一个方法,返回所有类中以alias开头的属性,以及所有类原型上的以validator开头的方法:

如:

  1. class A {
  2. constructor() {
  3. this.aliasA = 'a'
  4. }
  5. validatorA() {
  6. console.log('a')
  7. }
  8. }
  9. class B extends A {
  10. constructor() {
  11. super()
  12. this.aliasB = 'b'
  13. }
  14. validatorB() {
  15. console.log('b')
  16. }
  17. }
  18. class C extends B {
  19. constructor() {
  20. super()
  21. this.aliasC = 'c'
  22. }
  23. validatorC() {
  24. console.log('c')
  25. }
  26. }
  27. const c = new C()
  28. // 传入参数:
  29. filter(c, 'alias', 'validator')

输出:

2020021213042144.png

实现大致思路:

所有类中的的属性很好实现,由于继承关系,所以实例c中可拿到所有类中实例属性,遍历,以name开头的属性,push到数组即可;

所有类原型上的方法,需要递归遍历,通过Object.getPropertyOf()获取一个对象的原型,使用Object.getOwnPropertyNames,输出所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性),判断 属性中有’alias’ 的属性,push到数组中去,最后需要递归遍历,第一个参数,刚开始是实例c,递归第二次时,参数一为实例c的原型的原型,说白了就是通过递归在原型链上不断地查找;

开始,我是通过实例的__proto__方法(原型链)寻找类原型上的属性的,由于__proto__是一个内置方法,不建议使用,后来改用: Object.getPropertyOf() 来获取类的原型。

  1. let arr = []
  2. function test(instance, alias, validator) {
  3. if(instance){
  4. Object.keys(instance).forEach(ele => {
  5. (ele.indexOf(name) !== -1) ? arr.push(ele) : ''
  6. })
  7. }
  8. const isValidator = Object.getOwnPropertyNames(Object.getPrototypeOf(instance))
  9. if(isValidator) {
  10. isValidator.forEach(item => {
  11. if(item.indexOf(validator) !== -1) {
  12. arr.push(item)
  13. test(Object.getPrototypeOf(instance), 'alias', validator)
  14. }
  15. })
  16. }
  17. }
  18. test(c,'alias', 'validator')
  19. console.log(arr)

发表评论

表情:
评论列表 (有 0 条评论,59人围观)

还没有评论,来说两句吧...

相关阅读

    相关 ES6中新增class

    我们都知道JavaScript是弱类型的语言,其缺陷就是缺乏严谨性,但是在JavaScript发展的过程中需要慢慢的弥补这些缺陷,于是便在ES6中出现了类的概念。 文

    相关 ES6 class

    ES6中的类 js中生成实例对象的传统方法是通过构造函数。而ES6提供了更接近传统语言的写法,引入了class类这个概念,作为对象的模板,通过class类关键字,可以定义

    相关 ES6 class的继承

    类的继承:`extends`关键字用于[类声明][Link 1]或者[类表达式][Link 2]中,以创建一个类,该类是另一个类的子类。 `extends`关键字用来创建一个

    相关 ES6--Class

    Class概述 概述 在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。 class 的本质是 function。 它可以