class

作者: 田成力 | 来源:发表于2019-10-09 20:36 被阅读0次

    Class

    ES5中的类
    使用ES5中的类特点:使用function来进行模仿的

    function Animal(name) {
      if (!(this instanceof Animal)) {
        //如果this不是自己的实例,则说明没有实例化而是直接调用的 
        throw new Error('不能直接调用,必须使用实例调用')
      }
    
      //实例属性:
      this.name=name;
      this.age=10;
    }
    
    //公共属性
    Animal.prototype.eat=function(){
    
    }
    

    实例 & 类 & Object的关系

    let dog=new Animal('张三');
    dog.name//张三
    

    name是dog实例的属性 找到name是通过this.找到的
    eat是dog的共有属性 如何找到eat方法的呢?
    dog中有一个属性 __proto__用于指向Animal.prototype而在Animal.prototype对象中有一个constructor指向Animal

    例子:

    function Animal(name) {
      if (!(this instanceof Animal)) {
        //如果this不是自己的实例,则说明没有实例化而是直接调用的 
        throw new Error('不能直接调用,必须使用实例调用')
      }
    
      //实例属性:
      this.name=name;
      this.age=10;
    }
    
    //公共属性
    Animal.prototype.eat=function(){
    console.log("in eat method");
    }
    
    
    let dog=new Animal('zhangsan');
    console.log(dog.name);
    dog.eat();
    
    console.log(dog.__proto__===Animal.prototype);
    console.log(dog.__proto__.constructor===Animal);
    console.log(dog.__proto__.__proto__===Object.prototype);
    

    类的继承

    function Animal(){
      this.type='哺乳动物'
    }
    Animal.prototype.eat=function(){
      console.log("我在吃东西");
    }
    
    function Dog(name){
      this.name=name;
      Animal.call(this);
    }
    // Dog.prototype.__proto__=Animal.prototype;
    // Object.setPrototypeOf(Dog.prototype, Animal.prototype)
    Reflect.setPrototypeOf(Dog.prototype, Animal.prototype);
    let dog=new Dog('zhangsan');
    console.log(dog.name);
    console.log(dog.type);
    dog.eat();
    
    //这三句话的意思是相同的:
    // Dog.prototype.__proto__=Animal.prototype;
    // Object.setPrototypeOf(Dog.prototype, Animal.prototype)
    // Reflect.setPrototypeOf(Dog.prototype, Animal.prototype);
    
    
    //原理:
    //Animal.call(this);// 想要再dog中有Animal中的实例属性,只能改变this的指向
    //在Dog中的this是dog 所以执行下Animal并修改Animal的this指向即可
    
    //Dog.prototype.__proto__=Animal.prototype;
    //如何才能找到Animal中的prototype中的方法呢?
    //dog先找自己的实例方法发现没有eat,再通过它的__proto__找到Dog的prototype,发现还是没有eat方法
    //这时我们希望 再去找Animal的prototype有误eat方法怎么办呢?
    //当Dog.prototype中找不到时就会通过Dog.prototype.__proto__去找上一级,而我们改变了它的__proto__属性,让他指向Animal的prototype 这样就形成了一个原型链
    
    

    继承的第二种方法

    function Animal() {
      this.type = '哺乳动物'
    }
    Animal.prototype.eat = function () {
      console.log("我在吃东西");
    }
    
    function create(parentPrototype) {
      function FN() {
    
      }
      FN.prototype = parentPrototype;
      return new FN();
    }
    function Dog(name) {
      this.name = name;
      Animal.call(this);
      Dog.prototype = Object.create(Animal.prototype, { constructor: { value: Dog } });
    }
    
    let dog = new Dog('zhangsan');
    console.log(dog.name);
    console.log(dog.type);
    dog.eat();
    

    Es6 Class

    
    //这样的写法是 规范写法
    class Animal {
      constructor(){
        this.name='name';
        this.type='type';
      }
    }
    
    //这种写法是es的实验性写法
    //在Node环境中是不能运行的
    //在webpack 需要插件的帮助转换@babel/plugin-proposal-class-properties
    class Animal{
      type='type';
      name='name'
    }
    
    class Animal{
      type="name";
      getName(){
        console.log(this)
      }
    }
    
    let getName=new Animal().getName;
    getName();//undefined ES6的规范
    
    //只能先绑定
    let animal=new Animal();
    let getName=animal.getName.bind(animal);
    getName();
    

    如何将属性直接定义到原型上呢?

    class Animal {
      constructor(name) {
        this.name = name;
      }
      getName(){
        return name;
      }
    
      //将a属性保证成get方法
      get a() {
        return 1;
      }
    }
    let  animal=new Animal()
    console.log(animal);
    
    //发现: a属性不仅会出现在Animal.prototype上也会出现在Animal的实例属性上
    
    

    静态属性

    静态属性是直接定义到类上的属性
    注意点: static age=18(静态属性)语法是ES7的语法,不能直接在Node环境中使用 需要webpack
    @babel/plugin-proposal-class-properties转换
    但是 static getAge(){} (静态方法)是ES6的语法,可以直接使用

    
    class Animal {
      constructor(name) {
        this.name = name;
      }
      getName() {
        return name;
      }
      get a() {
        return 1;
      }
    
      static age = 18;
    }
    let animal = new Animal()
    console.log(animal);//打印结果发现,并没有age属性
    console.log(Animal.age);//18 在类中
    
    
    //如果不想使用ES7的语法但也想直接使用静态属性,如何使用呢?
    
    class Animal{
      constructor(name) {
        this.name = name;
      }
      getName() {
        return name;
      }
    
      static get age(){
        return 18
      }
    }
    

    ES6的继承

    class Animal{
      
    }
    class Dog extends Animal{
    
    }
    
    //静态方法也会被这类继承
    class Animal{
      static flag=false;
    }
    class Dog extends Animail{
    }
    
    console.log(Dog.flag)//true
    
    

    Super的用法

    
    //调用父类的钩子函数
    class Animal{
      constructor(name){
        this.name=name;
      }
    }
    class Dog extends Animal{
      constructor(name){
        super(name);
      }
    }
    
    //super的纸袋问题?
    // super是指父类
    
    //主动调用父类的方法(原型方法)
    class Animal{
      constructor(name){
        this.name=name;
      }
    
      getName(){
        console.log('parent getName')
      }
    }
    class Dog extends Animal{
      constructor(name){
        super(name);
      }
    
      getName(){
        console.log('son getName');
        super.getName();//super指定的是 Animal.prototype
      }
    }
    

    new的模拟

      function Animal() {
        this.name = "zhangsan"
        this.age = 18;
      }
    
      Animal.prototype.say = function () {
        console.log("in say");
      }
    
      function mockNew(parent) {
        let obj = {};
        Animal.call(obj);
        obj.__proto__ = parent.prototype;
        return obj;
      }
    
      // let dog=new Animal();
      let dog = mockNew(Animal);
      console.log(dog.name);
      console.log(dog.age);
      dog.say();
    
    

    类的装饰器

    
    //可以修饰类 也可以修饰类的属性
    @type1
    @type2
    class Animal{
    
    }
    
    //1.type1 和 type2 都是函数
    //function type1(Constrtuctor){}
    //2.它的意思是 声明了Animal类,并且调用 type函数
    //3.调用顺序是 就近调用 先调用的是type2再调用type1
    

    装饰器的小例子:

    function type(typeName) {
      console.log(typeName);
      return function (Constructor) {
        Constructor.type=typeName;
        console.log("in type inter");
      }
    }
    
    function name(n) {
      console.log(n);
      return function (Constructor) {
        
        Constructor.name=n;
        console.log("in name inter");
      }
    }
    @type('哺乳类')
    @name('张三')
    class Animal {
    
    }
    
    let dog=new Animal();
    console.log(dog);
    console.log(Animal.name);
    
    //执行顺序是 type函数 name 函数 再执行 name的 inter 和 type的inter
    

    使用装饰器装饰类的小例子:

    
      //混合对象的属性和类
      let obj = {
        name: "zhangsan",
        age: 18
      }
    
      @mixin(obj)
      class Zhangsan {
    
      }
    
      function mixin(obj) {
        return function (Constrcutor) {
          Object.assign(Constrcutor.prototype, obj);
        }
      }
    
      console.log(new Zhangsan().name);
    
    

    使用装饰器装饰类的属性

    class Circle{
      @readonly type="circle"
    }
    
    //ClassPrototype: CirCle.prototype
    //key: 要修饰的key
    //descriptor: key的描述信息 configurable enumerable writable initializer
    function readonly(ClassPrototype,key,descriptor){
      console.log(descriptor);
      //将该属性的writable设置为false,就不能被更改了
      descriptor.writable=false;
    }
    let circle=new Circle();
    //尝试修改type的值
    circle.type="1122"
    //打印出来的结果依然是circle
    console.log(circle.type);
    
    

    使用装饰器装饰类的方法

      class Circle {
        @readonly type = "circle"
        @before getName() {
          console.log("getName");
        }
      }
    
      //ClassPrototype: CirCle.prototype
      //key: 要修饰的key
      //descriptor: key的描述信息 configurable enumerable writable initializer
      function readonly(ClassPrototype, key, descriptor) {
        console.log(descriptor);
        //将该属性的writable设置为false,就不能被更改了
        descriptor.writable = false;
      }
    
      function before(ClassPrototype, key, descriptor) {
        //在装饰函数中descriptor.value就是函数本身,就像例子中的"getName"
        let oldMethod = descriptor.value;
        descriptor.value = function () {
          console.log("in before method");
          oldMethod();
    
        }
      }
      let circle = new Circle();
      //尝试修改type的值
      circle.type = "1122"
      //打印出来的结果依然是circle
      console.log(circle.type);
      circle.getName();
    

    装饰模式

    对原有的方式进行包装
    既不破坏原函数的核心逻辑代码 又可以在其函数上添加逻辑
    es6的使用@,但只能在class上使用

    
    let obj={
      type:"人"
    };
    let obj2={
      genor:"男"
    }
    @mixin(obj)
    @mixin(obj2)
    class Zhangsan{
    }
    #### EventLoop
    
    

    相关文章

      网友评论

          本文标题:class

          本文链接:https://www.haomeiwen.com/subject/pchnpctx.html