es5的部分继承以及es6的class

一、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)