zoukankan      html  css  js  c++  java
  • ES6的class

    ES6中引入的 JavaScript 类(class)实质上是 JavaScript 现有的基于原型的继承的语法糖。类语法并不会为JavaScript引入新的面向对象的继承模型。

    在es5中我们是使用构造函数实例化出来一个对象,那么构造函数与普通的函数有什么区别呢?其实没有区别,一般构造函数的函数名称用首字母大写来加以区分。但是es5的这种方式给人的感觉还是不够严谨,于是在es6中就有了class,就是把es5中的function换成了class,有这个单词就代表是个构造函数,然后呢对象还是new出来的,这一点并没有变化。

    以下代码定义了一个Point类,他里面有个constructor方法,这就是构造方法;而this关键字则代表实例对象。 Point类除了构造方法,还定义了一个toString方法,定义类的方法的时候,前面不需要加function这个关键字,直接将函数定义放进去就行了 ,另外,方法之间不需要逗号分隔;

    //定义类
    
    class Point {
        constructor (x, y) {
            this.x =x;
            this.y =y;
          }
    
            toString () {
            return `( ${this.x}, ${this.y} )`;
           }
           toValue () {
            return this.x+this.y;
           }
    }
    var p = new Point(1,2);
    p.toString();
    //"(1,2)"
    p.toValue();
    //3

    类的使用

    class Coder{
        name(val){
            console.log(val);
        }
    }
     
    let shuang= new Coder;
    shuang.name('shuang');   // shuang

    类的传参

    在es6中的对象的属性都是写在constructor里面,方法都是在原型身上。

    以下代码用constructor约定了两个参数,然后用add()方法把参数相加,这个地方跟以前不太一样,所以需要多注意一下。

    class Coder{
        name(val){
            console.log(val);
            return val;
        }
    
        constructor(a,b){
            this.a=a;
            this.b=b;
        }
     
        add(){
            return this.a+this.b;
        }
    }
     
    let shuang=new Coder(1,2);
    console.log(shuang.add());

    class的继承

    class的继承就是用extends

    以下代码声明一个shuang的新类,用extends继承了Coder,调用里面的name方法,发现也是可以输出的。

    class shuang extends Coder{
     
    }
     
    let shuang=new shuang;
    shuang.name('Angel爽');

    提升

    函数声明和类声明之间的一个重要区别是函数声明会提升,类声明不会。

    首先需要声明一个类,然后在访问它,否则像下面的代码会抛出一个ReferenceError:

    let p = new Rectangle();    // ReferenceError
    
    class Rectangle {}

    类表达式

    一个类表达式是定义一个类的另一种方式。类表达式可以是被命名的或匿名的。赋予一个命名类表达式的名称是类的主体的本地名称。类表达式也同样受到类声明中提到的提升问题的限制。类表达式也不会变量提升。

    /* 匿名类 */ 
    let Rectangle = class {
      constructor(height, width) {
        this.height = height;
        this.width = width;
      }
    };
    
    /* 命名的类 */ 
    let Rectangle = class Rectangle {
      constructor(height, width) {
        this.height = height;
        this.width = width;
      }
    };

    constructor

    constructor方法是类的默认方法,通过new 命令生成对象实例时,自动调用该方法,一个类有且只有一个constructor方法,如果没有显示定义,一个空的constructor方法会被默认添加;如果类包含多个constructor的方法,则将抛出 一个SyntaxError。

    原型方法

    class Rectangle {
        // constructor
        constructor(height, width) {
            this.height = height;
            this.width = width;
        }
        // Getter
        get area() {
            return this.calcArea()
        }
        // Method
        calcArea() {
            return this.height * this.width;
        }
    }
    const square = new Rectangle(10, 10);
    
    console.log(square.area);
    // 100

    静态方法

    static关键字用来定义一个类的一个静态方法。调用静态方法不需要实例化该类,也不能通过一个类实例调用静态方法。

    class Point {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }
    
        static distance(a, b) {
            const dx = a.x - b.x;
            const dy = a.y - b.y;
    
            return Math.hypot(dx, dy);
        }
    }
    
    const p1 = new Point(5, 5);
    const p2 = new Point(10, 10);
    
    console.log(Point.distance(p1, p2));

    当一个对象调用静态或原型方法时,如果该对象没有“this”值(或“this”作为布尔,字符串,数字,未定义或null) ,那么“this”值在被调用的函数内部将为 undefined。不会发生自动包装。即使我们以非严格模式编写代码,它的行为也是一样的,因为所有的函数、方法、构造函数、getters或setters都在严格模式下执行。因此如果我们没有指定this的值,this值将为undefined。

    class Animal { 
      speak() {
        return this;
      }
      static eat() {
        return this;
      }
    }
    
    let obj = new Animal();
    obj.speak(); // Animal {}
    let speak = obj.speak;
    speak(); // undefined
    
    Animal.eat() // class Animal
    let eat = Animal.eat;
    eat(); // undefined

    如果我们使用传统的基于函数的类来编写上述代码,那么基于调用该函数的“this”值将发生自动装箱。

    function Animal() { }
    
    Animal.prototype.speak = function() {
      return this;
    }
    
    Animal.eat = function() {
      return this;
    }
    
    let obj = new Animal();
    let speak = obj.speak;
    speak(); // global object
    
    let eat = Animal.eat;
    eat(); // global object

    extends

    extends关键字在类声明或类表达式中用于创建一个类作为另一个类的一个子类:

    class Animal { 
      constructor(name) {
        this.name = name;
      }
      
      speak() {
        console.log(this.name + ' makes a noise.');
      }
    }
    
    class Dog extends Animal {
      speak() {
        console.log(this.name + ' barks.');
      }
    }
    
    var d = new Dog('Mitzie');
    d.speak();  // 'Mitzie barks.'

    super

    super既能当作方法调用也能当对象使用:

    当做方法调用时只有是在子类构造函数constructor方法内;

    当做属性使用时,在普通方法中,指向父类的原型对象;

    在静态方法中,指向父类:

    class Parent {
      static myMethod(msg) {
        console.log('static', msg);
      }
      myMethod(msg) {
        console.log('instance', msg);
      }
    }
    class Child extends Parent {
      static myMethod(msg) {
        super.myMethod(msg);
      }
      myMethod(msg) {
        super.myMethod(msg);
      }
    }
    Child.myMethod(1); // static 1
    var child = new Child();
    child.myMethod(2); // instance 2

    在子类的静态方法中通过 super 调用父类的方法时,方法内部的 this 指向当前的子类,而不是子类的实例:

    class A {
      constructor() {
        this.x = 1;
      }
      static print() {
        console.log(this.x);
      }
    }
    class B extends A {
      constructor() {
        super();
        this.x = 2;
      }
      static m() {
        super.print();
      }
    }
    B.x = 3;
    B.m() // 3

    调用子类构造函数中的super方法可以继承父类构造函数中东西:

    class A {
      constructor() {
        this.show();
      }
    }
    class B extends A {
      constructor() {
        super();
      }
      show(){
        console.log('实例');
      }
      static show(){
        console.log('子类');
      }
    }
    new B()  //输出 '实例' ,new B 时触发了 B 的构造函数,所以触发了 super 方法,即触发了父类 A 的构造函数,此时的 this.show 的 this 指的是子类 

    在构造函数中super指向父类的原型对象:

    class A {
      p() {
        return 2;
      }
    }
    class B extends A {
      constructor() {
        super();
        console.log(super.p()); // 2  此时的super指向父类原型对象,即 A.prototype
      }
    }
    let b = new B();  //2

    由于在普通方法中的 super 指向父类的原型对象,所以如果父类上的方法或属性是定义在实例上的,就无法通过 super 调用的:

    class A {
      constructor() {  //在构造函数上定义的属性和方法相当于定义在父类实例上的,而不是原型对象上
        this.p = 2;
      }
    }
    class B extends A {
      get m() {
        return super.p;
      }
    }
    
    let b = new B();
    console.log(b.m) // undefined
    class A {
      constructor() {
        this.x = 1;
      }
      print() {
        console.log(this.x);
      }
    }
    class B extends A {
      constructor() {
        super();
        this.x = 2;
       super.y = 123;  // 如果通过super对某个属性赋值,这时super就是this,赋值的属性会变成子类实例的属性。
      }
      m() {
        super.print();   // 这里调用父类时,父类里的this指向是当前子类
      }
    }
    
    let b = new B();
    b.m() // 2
    console.log(b.y);  //123

    如果一个类里有一个属性,这个类的构造函数中也有一个同名属性,它的实例上会取哪个值呢?

    class Point{
        constructor(){
        this.x = 1;
        }
        x = 2
    }
    var p = new Point();
    console.log(p.x);   // 1 取构造函数中的值

    以上代码的原型链:

    class Point{
        constructor(){
        this.x = 1;
        }
        x = 2
    }
    var p = new Point();
    console.log(p.__proto__);   // 指向p的构造函数的prototype,这个prototype包括它的构造函数本身和它的__proto__

    原文:https://www.cnblogs.com/hsgg/p/8108927.html

    https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes

    https://www.cnblogs.com/wenxuehai/p/10361653.html

  • 相关阅读:
    plan
    模拟测试6
    codeforces gym100801 Problem J. Journey to the “The World’s Start”
    HDU6333 莫队+组合数学
    codeforces 1167B Lost Numbers
    codeforces 86D,Powerful array 莫队
    codeforces 220B . Little Elephant and Array 莫队+离散化
    SPOJ DQUERY
    poj/OpenJ_Bailian
    codeforces 540E 离散化技巧+线段树/树状数组求逆序对
  • 原文地址:https://www.cnblogs.com/xjy20170907/p/11572552.html
Copyright © 2011-2022 走看看