es6面向对象的‘类’class的总结:

1.类的所有方法都定义在prototype属性上,用Object.assign()可以向类一次添加多个方法;

class Point {
  constructor(){
    // ...
  }
}

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

2.类内部定义的方法不可枚举,与es5不同;类的属性名也可以使用表达式。[methodName];

3.constructor方法返回实例对象(即this),也可以指定返回另外一个对象(如return Object.create(null)),则new出的实例不再是类的实例;

4.类必须使用new调用。(es5不new也可以使用。)

5.类的实例共享一个原型对象(p.__proto__);

6.当类用表达式定义时,const MyClass=class Me(){}中的Me只能在class内部代码使用,指代当前类。可以省略;

7.类不存在变量提升,与es5不同;

8.私有方法的实现:a.约定(_private);   b.将私有方法移除模块,在模块内部用call调用;   c.将私有方法命名为一个symbol值;

9.私有属性的实现:使用#在属性名前(提案);(_variableName 表示一个对象中的私有变量,只希望通过对象方法去访问。希望他人不要通过对象实例去访问这个变量,而并非真正意义上的私有变量。

10.this的指向问题:可以通过在constructor方法中bind(this);

class Logger {
  constructor(){
    this.printName=this.printName.bind(this)//防止this变成window等
  }
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
const { printName } = logger;
printName();

或者使用箭头函数

class Logger {
  constructor(){
    this.printName=(name='there')=>{
      this.print(`hello ${name}` )
    }
  }
  print(text) {
    console.log(text);
  }
}
const logger = new Logger();
const { printName } = logger;
printName();

或者使用proxy

11.在类内部可以使用get set关键字(定义在属性的描述对象Descripor上)

class P{
  constructor(){
    this.pp=333;
  }
  get prop(){
    return this.pp
  }
  set prop(val){
    this.pp=val;
  }
}
let p=new P();
p.prop=999
console.log(p.prop)//999

12.如果某个方法之前加上星号(*),就表示该方法是一个 Generator 函数。( * [Symbol.iterator]() {}

13.class的静态方法在方法前加static关键字,表示该方法不会被实例继承,直接通过类来调用。

class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function

如果静态方法里包含this 这个this指的是类;静态方法可以和非静态方法重名。静态方法可以被子类继承;也可以从super对象上调用;

14.class的静态属性可以在类后面直接添加如Foo.prop=1; 新提案里则是在类里写static prop=1;

15.new.target属性 ===Person或!==undefined 可以确保构造函数只能通过new命令调用;

new.target在实现继承时会返回子类,可以写出不能实例化,必须继承后才能使用的类;

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('本类不能实例化');
    }
  }
}

class Rectangle extends Shape {
  constructor(length, width) {
    super();
    // ...
  }
}

var x = new Shape();  // 报错
var y = new Rectangle(3, 4);  // 正确

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

class的继承:

1.使用extends关键字实现继承;

class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + ' ' + super.toString(); // 调用父类的toString()
  }
}

子类必须在constructor方法中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。

ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。ES6 的继承机制完全不同,实质是先创造父类的实例对象this(所以必须先调用super方法),然后再用子类的构造函数修改this

2.Object.getPrototypeOf方法可以用来从子类上获取父类。可以使用这个方法判断,一个类是否继承了另一个类。

3.super作为函数调用时,代表调用父类的构造函数,却返回子类的实例(即super内部this指向子类,相当于A.prototype.constructor.call(this)),只能用在子类的构造函数之中;

  super作为对象时,指向父类的原型对象(所以无法获取父类实例上的方法或属性(this.name=name等))

  通过super调用父类的方法时,方法内部的this指向子类。

class A {
  constructor() {
    this.x = 1;
  }
  print() {
    console.log(this.x);
  }
}

class B extends A {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
  }
}

let b = new B();
b.m() // 2

如果super作为对象,用在静态方法之中,这时super将指向父类,而不是父类的原型对象。

总结:super在静态方法之中指向父类,在普通方法之中指向父类的原型对象。

4.

(1)子类的__proto__属性,表示构造函数的继承,总是指向父类。

(2)子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class A {
}

class B extends A {
}

B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true

子类实例__proto__属性的__proto__属性,指向父类实例的__proto__属性。因此,通过子类实例的__proto__.__proto__属性,可以修改父类实例的行为。

p2.__proto__.__proto__.printName = function () {
  console.log('Ha');
};

p1.printName() // "Ha"

5.ES6 允许继承原生构造函数定义子类,因为 ES6 是先新建父类的实例对象this,然后再用子类的构造函数修饰this,使得父类的所有行为都可以继承。下面是一个继承Array的例子。

class MyArray extends Array {
  constructor(...args) {
    super(...args);
  }
}

var arr = new MyArray();
arr[0] = 12;
arr.length // 1

arr.length = 0;
arr[0] // undefined

6.mixin:

Mixin 指的是多个对象合成一个新的对象,新对象具有各个组成成员的接口。

将多个类的接口“混入”(mix in)另一个类。

function mix(...mixins) {
  class Mix {}

  for (let mixin of mixins) {
    copyProperties(Mix, mixin); // 拷贝实例属性
    copyProperties(Mix.prototype, mixin.prototype); // 拷贝原型属性
  }

  return Mix;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if ( key !== "constructor"
      && key !== "prototype"
      && key !== "name"
    ) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}

上面代码的mix函数,可以将多个对象合成为一个类。使用的时候,只要继承这个类即可。

class DistributedEdit extends mix(Loggable, Serializable) {
  // ...
}

 

posted @ 2017-12-18 20:10  九爷九  阅读(800)  评论(0编辑  收藏  举报