Class的基本语法和继承

JS引擎是一个大的工厂,
工厂的专家制作出了Object.prototyp产品
在这个产品的基础上又制造出了Function.prototype
在这个原型的基础上制造除了两个非常厉害的机器 Object函数和Function函数
Object函数用来制造队形
Function函数用来制造函数
比如制做一个空的数组[]这么一个对象
在对象身上都有一个proto这么一个属性,用来指明这个对象的原型是谁
在每个对象的原型身上又有constructor这个属性,用来表明它的构造函数是谁

// 在ES5下通常我们会这么写
const Meizi = function(a,b){
  this.a = a;
  this.b = b;
  return this;
  }
Meizi.prototype = {
  constructor:Meizi,
  print: function(){
    console.log(this.a+' '+this.b)
  }
 }
const Meizi  = new Meizi ('hello','world').print();
// 用class改写
class Meimei{
  constructor(a,b) {
    this.a = a,
    this.b = b
    return this;
  }
  print() {
    console.log(this.a+' ' +this.b)
  }
}
const Meizi = new Meimei('hello','world').print();
console.log(typeof Meimei);//function

1.Meizi 中的constructor方法是构造方法,
this关键字则代表实例对象。也就是说,ES5
的构造函数Meizi ,对应ES6的Meizi 这个类的构造方法。

2.Meizi 这个类除了构造方法,还定义了一个print方法。
注意,定义“类”的方法的时候,前面不需要加上function
这个关键字,直接把函数定义放进去就可以了。另外,方法之间
不需要逗号分割,加了会报错。

3.构造函数的prototype属性,在ES6的“类”上面继续存在。而且类的所有方法都
定义在类的prototype属性上面

console.log(Meizi.prototype)

4.定义在类中的方法都是不可以枚举的

console.log(Object.keys(Meizi.prototype))//[]

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

6.生成类的实例对象的写法,与ES5完全一样,也是使用new命令。
如果忘记加上new,像函数那样调用class,将会报错

class的继承相关知识

  • 子类继承父类 使用extends关键字
  • 为父类指定静态方法,使用static方法名字

super

  • 在构造函数中可以当一个函数来使用,相当于调用父类的构造函数
  • 在原型方法中,可以当一个对象来使用,相当于父类的原型对象,并且
    会自动绑定到this到子类上

Class的继承

子类继承父类 使用extends关键字
为父类指定静态方法,使用static方法名字

super

  • 在构造函数中可以当一个函数来使用,相当于调用父类的构造函数
  • 在原型方法中,可以当一个对象来使用,相当于父类的原型对象,并且
    会自动绑定this到子类上
const canvas = document.querySelector('#canvas');
    
    const ctx = canvas.getContext('2d');
    
    const w = canvas.width = 600;
    const y = canvas.height = 400;
    
    class Ball {
        constructor(x,y,r) {
            this.x = x;
            this.y = y;
            this.r = r;
            this.color = `rgb(${~~Ball.rpFn([55,255])},
            ${~~Ball.rpFn([55,255])},${~~Ball.rpFn([55,255])})`;//两个波浪线可以看作Math.floor()的偷懒写法
            return this;
        }
        render(ctx){ //接收一个参数:绘图环境
            ctx.save();
            ctx.translate(this.x,this.y);
            ctx.fillStyle = this.color;
            ctx.beginPath();
            ctx.arc(0,0,this.r,0,2*Math.PI);
            ctx.fill();
            ctx.restore();
            return this;
        }
        //静态方法
        static rpFn(arr) { //Ball.rpFn([1,10])
            let max = Math.max(...arr),
                min = Math.min(...arr);
            return Math.random()*(max - min) + min;
        }
    }
    //const ball = new Ball(100,100,30).render(ctx);
    
    
    
    //什么都不写就代表子类完全的继承了父类,但这么写是没有意义的
    //class SuperBall extends Ball {}
    
    
    
    //继承
    class SuperBall extends Ball {
        constructor(x,y,r){
            super(x,y,r);//super调用完毕就相当于子类已经继承了父类的所有属性
                         //在没调用super之前,子类是没有自己的this的
            //纵向速度
            this.vy = SuperBall.rpFn([2,4]);
            //重力加速度
            this.g = SuperBall.rpFn([0.2,0.4]);
            
            this.a = 0;
            return this;
        }
        
        //子类的原型方法
        move(ctx){

            //super(); //报错

            this.y += this.vy
            this.vy += this.g
            
            let current = this.vy * -0.75
            
            if(this.y+this.r >= ctx.canvas.height) {
                this.y = ctx.canvas.height - this.r
                
                if(Math.abs(current - this.a) < 0.01) return false;
                
                //为了让这个小球反弹回去
                this.a = this.vy *= -0.75
                
                
            }
            
            ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
            
            //这里的super指向的是父类的原型对象
            super.render(ctx);
            return true;
        }
    };
    //const ball = new SuperBall(100,100,30).render(ctx);
    
    let ball,timer;
    
    canvas.onclick = function (e){
      window.cancelAnimationFrame(timer)
      let x = e.offsetX, y = e.offsetY;
      let r = ~~Ball.rpFn([25,55]);
      
      //为了点击画布只新建一个小球,绘制之前先清除一下画布
      ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height)
      ball = new SuperBall(x,y,r).render(ctx);
      
      ballMove();
      
    }
    
    function ballMove() {
      timer = window.requestAnimationFrame(ballMove);
      
      if(!ball.move(ctx)){
        window.cancelAnimationFrame(timer)
      }
    }

以下是其他资料笔记

//基本定义和生成实例
class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
}
let v_parent = new Parent('v');
console.log('构造函数和实例',v_parent)

继承

class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
}
class Child extends Parent{

}

console.log('继承',new Child())

继承传递参数

class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
}
class Child extends Parent{
    constructor(name='child'){
        //覆盖父函数的name
        super(name);

        //定义自己的属性,一定要放在super之后
        this.type = 'child';
    }
}

console.log('继承传递参数',new Child('hello'))

gettter setter

class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
    
    //下面是属性
    get longName(){
        return 'mk'+this.name
    }
    set longName(value) {
        this.name = value;
    }
}
let v = new Parent();
console.log('getter',v.longName);
v.longName='hello';//赋值就是setter操作
console.log('setter',v.longName)

静态方法

class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
    static tell(){
        console.log('tell');
    }
}
Parent.tell();

静态属性


class Parent {
    constructor(name='mukewang'){
        this.name = name;
    }
    static tell(){
        console.log('tell');
    }
    
}
Parent.type = 'test'
console.log('静态属性',Parent.type)
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容