es6 class

类 class

对象是由属性和方法组成的:属性:事物的特征,在对象中用属性来表示(常用名词)、方法:事物的行为,在对象中用方法来表示(常用动词);

类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象;

面向对象的思维特点:抽取(抽象)对象共用的属性和行为 组织(封装)成一个类(模板)对类进行实例化, 获取类的对象。暂且把class理解为一个模板;

类声明不会被提升,这与函数定义不同。类声明的行为与 let 相似

es5 中类通过原型来实现

  function Pa(x,y){
    //构造函数中写属性
    this.x=x;
    this.y=y;
  }
    //原型上写 公共属性或方法
    Pa.prototype.say=function(){
      console.log(this.x);
    }
  //new 一个实例   实例就会有原型上的方法 和构造函数中的属性
  let p=new Pa("a",2);
  p.say();  // a

es6中跟es5 原理是一样的只是写法不同而已,es5 构造函数和原型对象分开写,es6 是全部写到class中

  class Pa{
    //constructor  就是es5中的构造函数 
    constructor(x, y) {
      this.x = x;
      this.y = y;
    }
    //不需要分割符,直接写  原型方法
    say() {
      console.log(this.x);
    }
  }
  let p=new Pa("a",2);
  p.say(); //a
  console.log(Pa == Pa.prototype.constructor); //true
  //Pa 就是那个构造函数
  class Pa {}
  // 等同于
  class Pa {
    constructor() {}
  }

class 的属性和方法

公有的属性和方法: 即每一个实例对象又能访问的属性和方法, 只有公有属性才会遍历出来

  class PP {
    constructor () {
      this.a = 1
    }
    p = 2 // 与 constructor是一样的效果 
    say () { console.log(this) }
  }
  let p = new PP()
  p.a = 5
  console.log(p) // {p: 2, a: 5}
  let p1 = new PP()
  console.log(p1)// {p: 2, a: 1} 每一个实例互不影响
  p1.say() // 返回实例对象  {p: 2, a: 1}

私有的属性和方法: 只能通过类名进行访问的 私有的属性 通过添加 static 表示 😭 ES6 明确规定,Class 内部只有静态方法,没有静态属性。静态属性只有提案,但是目前babel都支持静态属性。以下代码经babel编译后,静态属性正常使用。)

  class PP {
    static sing () {}
    static size = 10 // 只是提案。
  }
  let p = PP.initPP()
  console.log(PP.size) // 10

也有说通过Symbol 来实现私有属性,但这是有疑问的。
Symbol 作为属性名,该属性不会出现在for...in、for...of循环中,也不会被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名。

Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

class this的指向

constructor 里面的this指向实例对象,方法里面的this 指向这个方法的调用者, 在单例模式中 通过类名来执行静态属性;

实例对象上的不是静态属性不能通过类名来调用 单例中的 this.instance 就可以理解为 是class 的静态属性;

在类的内部 是可以通过 类名来访问到类的,公有私有方法都可以;

  class PP {
    constructor () {
      this.a = 1
    }
    p = 2 // 与 constructor是一样的效果
    static initPP () {
      console.log(this.p) // undefined  实例对象上的不是静态属性不能通过类名来调用
      console.log(this.a) // undefined
      console.log(this.instance) // 第一次undefined 第二次会返回实例对象
      console.log(this.sing) // function..  只是静态属性 才能通过类对象来调用
      console.log(this.say) // undefined
      //通过类名来访问到类的 
      if (!this.instance) this.instance = new PP()
      return this.instance
    }
    static sing () { console.log(this) }
    say () { console.log(this) }
  }
  let p1 = PP.initPP()
  PP.sing() // 返回类本身 PP{...}
  p1.say() // 返回实例对象 {p: 2, a: 1}

class 的继承 extends

子类必须在 constructor 方法中调用super方法,否则新建实例时会报错。

  class A{
    constructor(x) { this.x=x }
    say(){ console.log(this.x)}
  }
  let a=new A(6);
  a.say();//6
	
  // B继承A
  class B extends A{
    constructor(x,y){//B 自己的构造函数   构造函数通过new 会生成实例		
      super(x,y);
      //super(x),代表调用A的构造函数constructor(x)。 但是返回的是子类B的实例
      //super()在这里相当于A.prototype.constructor.call(this)。 this指的是B, 即:相当于把A的constructor给执行了,并且让方法中的this是B的实例,
      //super 之后才能使用this
      this.y=y; //B自己的属性
    }
  }
  let b=new B(5,9);
  b.say(); //5
  console.log(b.y)//9

继承的默认写法

  class B extends A { }
  // 等同于
  class B extends A{
    constructor(...args) {
      super(...args);
    }
  }

super 关键字

既可以当作函数使用,也可以当作对象使用

  • 做函数:只能在子类的构造函数之中当作函数使用,代表父类的构造函数;
  • 做对象:super在constructor中指向父类的原型对象,super在普通方法之中指向父类的原型对象。super在静态方法之中指向父类,可调用父类的静态方法;
  class A {
    constructor() {
      //实例的方法  是可遍历的
      this.x=function(){
        return 1;
      };
    }
    num = 123
    //原型上的方法
    p() {
      return 2;
    }
  }

  class B extends A {
    constructor() {
      // 当作函数使用
      super();
      // 当作对象使用
      console.log(super.num) // undefined 跟constructor一样
      console.log(super.p()); // 2 P是方法,在原型对象上
      console.log(super.x()); // x is not a function
      //A.prototype 的原型上没有x方法 就找不到
      //super  是指向 A.prototype的
    }
  }
  let b = new B();
  class A {
    static say(){ cconsole.log("132") }
  }
  class B extends A {
    kk(){
      super.say();   //super 没有这个say方法
      //作为对象 super在普通方法之中指向父类的原型对象。
    }
    static gg(){
      super.say(); //132  
      //作为对象 super在静态方法之中指向父类
    }
  }
  b.kk();   //kk   .say is not a function    
  B.gg();    //静态方法 所以用B 调用
posted @ 2019-11-05 22:45  雨天。我  阅读(154)  评论(0)    收藏  举报