美文网首页
es5的部分继承以及es6的class

es5的部分继承以及es6的class

作者: 语目 | 来源:发表于2017-07-20 22:40 被阅读0次

    一、JavaScript常用的原型继承方式

    1. 原型链继承

    2,构造函数继承(对象冒充继承)

    3,组合继承(原型链继承+构造函数继承)

    原型链继承

    function Show(){
    this.name="run";
    }
    
    function Run(){
    this.age="20"; //Run继承了Show,通过原型,形成链条
    }
    Run.prototype=new Show();
    var show=new Run();
    alert(show.name)//结果:run
    

    构造函数继承(对象冒充继承)

    为了解决引用共享和超类型无法传参的问题,我们采用一种叫借用构造函数的技术,或
    者成为对象冒充(伪造对象、经典继承)的技术来解决这两种问题

    function Box(age){
        this.name=['Lee','Jack','Hello']
        this.age=age;
    }
    function Desk(age){
        Box.call(this,age); 
    }
    var desk = new Desk(200);
    alert(desk.age);//200
    alert(desk.name);//['Lee','Jack','Hello']
    desk.name.push('AAA'); //添加的新数据,只给 desk
    alert(desk.name)//['Lee','Jack','Hello','AAA']
    

    组合继承(原型链继承+构造函数继承)

    借用构造函数虽然解决了刚才两种问题,但没有原型,复用则无从谈起。所以,我们需要原型链+借用构造函数的模式,这种模式成为组合继承。

    function Box(age) {
        this.name = ['Lee', 'Jack', 'Hello']
        this.age = age;
    }
    Box.prototype.run = function () {
        return this.name + this.age;
    };
    function Desk(age) {
        Box.call(this, age); //对象冒充
    }
    Desk.prototype = new Box(); //原型链继承
    var desk = new Desk(100);
    alert(desk.run());
    

    二、class类的使用

    ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。类和模块内部使用的是严格模式

    class Point {
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    }
    

    类的定义需要constructor方法这是构造方法,this指向实例对象,定义方法时方法之间不需要使用逗号分隔,加了会报错

    类的数据类型是函数,它的指向是构造函数,所以在使用的时候和构造函数相同需要new关键字

    class Bar {
      doStuff() {
        console.log('stuff');
      }
    }
    
    var b = new Bar();
    b.doStuff() // "stuff"
    

    es6中的类也有prototype属性

    class Point {
      constructor() {}
    
      toString() {}
    
      toValue() {}
    }
    
    // 等同于
    
    Point.prototype = {
      constructor() {},
      toString() {},
      toValue() {},
    };
    
    let b = new Point();
    //调用相同以下
    b.constructor === B.prototype.constructor // true
    

    Object.assign可以使prototype同时绑定多个方法

    class Point {
      constructor(){}
    }
    
    Object.assign(Point.prototype, {
      toString(){},
      toValue(){}
    });
    

    prototype对象的constructor属性,直接指向“类”的本身,这与 ES5 的行为是一致的。

    Point.prototype.constructor === Point // true
    

    类的内部所有定义的方法,都是不被枚举的

    class Point {
      constructor(x, y) {}
    
      toString() {}
    }
    
    Object.keys(Point.prototype)
    // []
    Object.getOwnPropertyNames(Point.prototype)
    // ["constructor","toString"]
    

    上面代码中,toString方法是Point类内部定义的方法,它是不可枚举的。这一点与 ES5 的行为不一致。

    var Point = function (x, y) {}
    
    Point.prototype.toString = function() {};
    
    Object.keys(Point.prototype)
    // ["toString"]
    Object.getOwnPropertyNames(Point.prototype)
    // ["constructor","toString"]
    

    上面代码采用 ES5 的写法,toString方法就是可枚举的。

    类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行

    生成类的实例对象的写法,与 ES5完全一样,也是使用new命令。前面说过,如果忘记加上new,像函数那样调用Class,将会报错,同时class的原型书写格式也和es5相差不大

    class Point {
    
      constructor(x, y) {
        this.x = x;
        this.y = y;
      }
    
      toString() {
        return '(' + this.x + ', ' + this.y + ')';
      }
    
    }
    
    var point = Point(2, 3);//报错
    var point = new Point(2, 3);
    
    point.toString() // (2, 3)
    
    point.hasOwnProperty('x') // true
    point.hasOwnProperty('y') // true
    point.hasOwnProperty('toString') // false
    point.__proto__.hasOwnProperty('toString') // true
    

    采用 Class 表达式,可以写出立即执行的 Class。

    let person = new class {
          constructor(name) {
            this.name = name;
          }
        
          sayName() {
            console.log(this.name);
          }
        }('张三')
    

    Class 的取值函数(getter)和存值函数(setter)

    class CustomHTMLElement {
      constructor(element) {
        this.element = element;
      }
    
      get html() {
        return this.element.innerHTML;
      }
    
      set html(value) {
        this.element.innerHTML = value;
      }
    }
    
    var descriptor = Object.getOwnPropertyDescriptor(
      CustomHTMLElement.prototype, "html"
    );
    
    "get" in descriptor  // true
    "set" in descriptor  // true
    上面代码中,存值函数和取值函数是定义在html属性的描述对象上面,这与 ES5 完全一致。
    

    class静态方法static关键字不会被实例继承但是会被子类继承

    class Foo {
      static classMethod() {
        return 'hello';
      }
    }
    
    Foo.classMethod() // 'hello'
    
    var foo = new Foo();
    foo.classMethod()// TypeError: foo.classMethod is not a function
    
    class Bar extends Foo {}
    
    Bar.classMethod() // 'hello'
    //也可以这么使用
    class Bar extends Foo {
      static classMethod() {
        return super.classMethod() + ', too';
      }
    }
    
    Bar.classMethod() // "hello, too"
    

    new.target属性new是从构造函数生成实例的命令。ES6为new命令引入了一个new.target属性,该属性一般用在在构造函数之中,返回new命令作用于的那个构造函数。如果构造函数不是通过new命令调用的,new.target会返回undefined,因此这个属性可以用来确定构造函数是怎么调用的。

    私有方法是常见需求,但 ES6 不提供,只能通过变通方法模拟实现。

    在命名上加以区别

    class Widget {
    
      // 公有方法
      foo (baz) {
        this._bar(baz);
      }
    
      // 私有方法
      _bar(baz) {
        return this.snaf = baz;
      }
    }
    

    与私有方法一样,ES6 不支持私有属性。目前,有一个提案,为class加了私有属性。方法是在属性名之前,使用#表示。

    class Point {
      #x;
    
      constructor(x = 0) {
        #x = +x; // 写成 this.#x 亦可
      }
    
      get x() { return #x }
      set x(value) { #x = +value }
    }

    相关文章

      网友评论

          本文标题:es5的部分继承以及es6的class

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