关于javascript:js类Class

28次阅读

共计 3619 个字符,预计需要花费 10 分钟才能阅读完成。

JavaScript 中的 Class

  1. 类的根本语法
  2. 类的继承
  3. 润饰器

1. 类的根本语法

能够看成 ES5 中构造函数的语法糖,它的大部分性能 ES5 都能够做到

1.1 定义一个类

ES5

function Student(name,age){
    this.name = name
    this.age = age
}
Student.prototype = {
    constructor:Student,
    showName(){return this.name}
}

Class

class Student {constructor(name, age) {
        this.name = name
        this.age = age
    }
    showName() {return this.name}
}
console.log(Student.prototype);//{constuctor showName}

class 的办法 constructor 与 showName 都是定义在原型上的,每个办法之间不必逗号隔开

1.2 constructor 办法

class 默认的办法,没有定义就默认加一个空的办法,在用 new 生成实例时 主动调用该办法

class Student {constructor(name, age) {
        this.name = name
        this.age = age
    }
    showName() {return this.name}
}
const std1 = new Student("张三")
console.log(std1);//{name:"张三",age:undefined}

与 ES5 不同的是,定义类不存在变量晋升,就是实例化肯定要在定义之后

1.3 公有办法和公有属性

只在类的外部调用和应用的办法与属性
公有办法

const private1 = Symbol('private1')
const prop1 = Symbol('prop1')
class Studnet {
    // 私有办法
    foo(parm1, parm2) {
        // 外部应用公有办法
        this[private1](parm1)
        private2.call(this, parm2)
    }
    // 公有办法
    [private1](parm) {return this[prop1] = parm
    }
}
// 公有办法
function private2(parm) {return this.prop2 = parm}

应用 Symbol 或者内部的构造函数的形式,能够实现办法外部的公有,实例化的对象不能拜访到这些办法

公有属性

class Studnet {
    #a = 'private'
    constructor(a) {this.a = this.#a}
    get() {return this.#a}
}

用 #来标识公有属性,在内部不能间接拜访这个属性,仅供外部应用

1.4 静态方法和动态属性

不能被实例继承的办法与属性
静态方法

class Foo {static fn1() {this.fn2()
    }
    static fn2() {console.log("Hello");
    }
    fn2() {console.log("World");
    }
}
Foo.fn1() //"Hello"
let foo = new Foo()
foo.fn2() //"World"

静态方法能够和实例办法重名,静态方法只能在类上调用

class Foo1 extends Foo {
}
Foo1.fn2()// "Hello"

子类能够继承父类的静态方法

动态属性
与静态方法雷同,在实例属性前加 static 即可

class Foo {
    static _name = "a"
    _name = "b"
}

console.log(Foo._name);//"a"
let foo = new Foo()
console.log(foo._name);//"b"

静态方法能够与实例办法重名,实例不能继承到静态方法,它属于结构器,不属于原型对象
同样静态方法能够被子类继承

1.5 new.target 属性

在类中指向该类,父类被继承时指向子类

class Foo {constructor() {console.log(new.target);
    }
}
class Foo1 extends Foo { }
let foo = new Foo() //Foo
let foo1 = new Foo1()//Foo1
  • 用该办法能够管制一些类必须在继承后能力应用

    class Foo {constructor() {if (new.target === Foo) {throw new Error("须要先继承")
          } else {console.log(new.target);
          }
      }
    }
    class Foo1 extends Foo { }
    let foo = new Foo() //Error 须要先继承
    let foo1 = new Foo1() //Foo1

2 Class 的继承

应用 extends 关键字将父类中的属性与办法拷贝到子类

2.1 super 关键字

  • 类继承的本质是先创立父类的实例对象 this,再用子类的构造函数批改 this
  • super 就为子类提供了父类的 this 对象,相当于 Parent.prototype.constructor.call(this),执行父类构造函数并 批改 this

    class Parent {constructor(x, y) {
          this.x = x
          this.y = y
      }
      getX() {console.log(this.x);
      }
    }
    class Child extends Parent {constructor(x, y, z) {super(x, y)
          this.z = z
      }
      getY() {console.log(this.y);
      }
    }
    let obj1 = new Child(1, 2, 3)
    console.log(obj1);//{x:1,y:2,z:3}
    obj1.getX()//1
    obj1.getY()//2
  • super指向父类的原型 ,能够作为一个对象去 调用原型上的办法 ,并 批改 this指向子类

    class Parent {constructor(x) {
          this.x = x
          this.y = "a"
      }
      getY() {console.log(this.y);
      }
    }
    class Child extends Parent {constructor(x, y) {super(x)
          this.y = y
      }
      runner() {super.getY()
      }
    }
    let obj1 = new Child(1, 2)
    obj1.runner()//2

    super.getY()相当于 Parent.prototype.getY.call(this)
    如果 Child 上没有 y 属性,则返回父类的 y 值为 ”a”
    如果 Child 上有 y 属性,但实例化的时候没有传值,则返回 undefined,不会去原型链上找

2.2 原型链

class A { }
class B extends A { }
const a1 = new A()
const b1 = new B()

// 子类的__proto__指向父类
B.__proto__ === A//true
// 父类的原型对象是子类原型对象的原型
B.prototype.__proto__ === A.prototype//true
// 父类实例的原型是子类实例的原型的原型就
b1.__proto__.__proto__ === a1.__proto__

要害还是在于第二个示例,父类的原型对象是子类原型对象的原型
因为类的原型对象就是实例对象的__proto__指向的对象,能够推出第三个示例

2.3 混入(Minxin)

实现继承多个类,先将多个类混入到一个类中,再继承
Minxin 的实现

// 混入
function mix(...mixins) {class Mix {}
    for (let mixin of mixins) {copyProperties(Max, mixin)
        copyProperties(Max.prototype, mixin.prototype)
    }
    return Mix
}
// 拷贝属性
function copyProperties(target, source) {for (let key of Reflect.ownKeys(source)) {
        if (key !== "constructor"
            && ket !== "prototype"
            && key !== "name"
        ) {let desc = Object.getOwnPropertyDescriptor(source, key);
            Object.defineProperty(target, key, desc)
        }
    }
}

ES6 规范 阮一峰

如果只是 办法 的追加则应用 Object.assign(target,source) 即可

3 润饰器(Decorator)

润饰器能够用来润饰类的行为
润饰器还在提案中,然而 babel 转码器曾经反对润饰器
能够装置 babel 的模块去编译 应用了润饰器的写法,转码成向下兼容的 ES5 写法,这样就能够失去想要的后果

  • 这里仅举一个类润饰器的例子

    @addStatic
    class A{}
    
    function addStatic(target){target.hello = "Hello"}

    target 就是类 A,@ + 润饰函数 相当于给类 A 增加一个动态属性 hello
    属性润饰器以及其余内容不再举例

正文完
 0