Class 学习 (Es6阮一峰)

 

es5 构造函数 实例:

 1 function Point(x, y) {
 2   this.x = x;
 3   this.y = y;
 4 }
 5 
 6 Point.prototype.toString = function () {
 7   return '(' + this.x + ', ' + this.y + ')';
 8 };
 9 
10 var p = new Point(1, 2);

 

作为对象的模板,通过class关键字,可以定义类,相当于创建一个 实例

 1 //定义类
 2 class Point {
 3   constructor(x, y) {
 4     this.x = x;
 5     this.y = y;
 6   }
 7 
 8   toString() {
 9     return '(' + this.x + ', ' + this.y + ')';
10   }
11 }
12 typeof Point // "function"
13 Point === Point.prototype.constructor // true
14 //ES6 的类,完全可以看作构造函数的另一种写法。

 

 

可以看到里面有一个constructor方法,这就是构造方法,this则代表实例对象

ES5 的构造函数Point,对应 ES6 的Point类的构造方法。

定义“类”的方法的时候,前面不需要加上function这个关键字,直接把函数定义放进去了就可以了。另外,方法之间不需要逗号分隔,加了会报错。

类的数据类型就是函数,类本身就指向构造函数。 直接对类使用new命令,跟构造函数的用法完全一致。

构造函数的prototype属性,在 ES6的“类”上面继续存在。 事实上,类的所有方法都定义在类的prototype属性上面。

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

  toString() {
    // ...
  }

  toValue() {
    // ...
  }
}

// 等同于

Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

 

Object.assign方法可以很方便地一次向类添加多个方法:

 1 Object.assign(Point.prototype, {
 2   toString(){},
 3   toValue(){}
 4 });
5// 类的内部所有定义的方法,都是不可枚举的 6 7 Object.keys(Point.prototype) 8 // [] es5 : ["toString"] 9 Object.getOwnPropertyNames(Point.prototype) 10 // ["constructor","toString"]

类的属性名,可以采用表达式。

let methodName = 'getArea';

class Square {
  constructor(length) {
    // ...
  }

  [methodName]() {
    // ...
  }
}

类和模块的内部,默认就是严格模式 只要你的代码写在类或模块之中,就只有严格模式可用。 ES6 实际上把整个语言升级到了严格模式

 

constructor方法

constructor方法是类的默认方法, 通过new命令生成对象实例时,自动调用该方法

一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。 相当于es5 new Vue

 1 class Point {
 2 }
 3 
 4 // 等同于 
 5 class Point {
 6   constructor() {} //JavaScript 引擎会自动为它添加一个空的constructor方法。
 7 }
 8 // 等同于
 9 new Point (){
10     
11 }
12 constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
13 
14 class Foo {
15   constructor() {
16     return Object.create(null);
17   }
18 }
19 
20 new Foo() instanceof Foo
21 // false

类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行, 与 ES5 一样,类的所有实例共享一个原型对象。

 私有属性

表达式定义一个类

 1 const MyClass = class Me {
 2   getClassName() {
 3     return Me.name;
 4     //这个类的名字是MyClass而不是Me,Me只在 Class 的内部代码可用,指代当前类。
 5   }
 6 };
 7 //内部没用到Me的话可以省略Me
 8 const YouClass = class {
 9 //...
10 };
11 采用 Class 表达式,可以写出立即执行的 Class。
12 
13 let person = new class {
14   constructor(name) {
15     this.name = name;
16   }
17 
18   sayName() {
19     console.log(this.name);
20   }
21 }('张三');
22 
23 person.sayName(); // "张三"

 

不存在变量提升(hoist),必须保证子类在父类之后定义),这一点与 ES5 完全不同。

new Foo(); // ReferenceError
class Foo {}

继承类

{
  let Foo = class {};
  class Bar extends Foo {
  //Bar继承Foo
  }
}

私有方法

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

有三种方法可模拟

//第一种
class Widget {

  // 公有方法
  foo (baz) {
    this._bar(baz);
  }

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

  // _bar方法前面的下划线,表示这是一个只限于内部使用的私有方法 但是,在类的外部,还是可以调用到这个方法。
}



//第二种
class Widget {
  foo (baz) {
    bar.call(this, baz);
  }

  // 内部调用了bar.call(this, baz),成为了当前模块的私有方法
}
//私有方法移出模块
function bar(baz) {
  return this.snaf = baz;
}


//第三种
const bar = Symbol('bar');
const snaf = Symbol('snaf');

export default class myClass{

  // 公有方法
  foo(baz) {
    this[bar](baz);
  }

  // 私有方法 
  [bar](baz) {
    return this[snaf] = baz;
  }

  // 利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
};

 

私有属性的提案

方法是在属性名之前,使用#表示。

class Point {
  #x=0;// 私有属性可以指定初始值,在构造函数执行时进行初始化。

  constructor(x = 0) {
    #x = +x; // 写成 this.#x 亦可
  }

  get #x() { return #x }
  set #x(value) { #x = +value }
  #sum() { return #a + #b; }  //私有方法
  
  //  #x是一个私有属性,它的读写都通过get #x()和set #x()来完成。 #x和x是两个不同的属性
}
//JavaScript 是一门动态语言,没有类型声明,使用独立的符号似乎是唯一的比较方便可靠的方法,能够准确地区分一种属性是否为私有属性。"@" 已经留给了 Decorator。

 

私有属性不限于从this引用,类的实例也可以引用私有属性

class Foo {
  #privateValue = 42;
  static getPrivateValue(foo) {
    return foo.#privateValue;
  }
}

Foo.getPrivateValue(new Foo()); // 42
console.log(Foo.#privateValue) // 报错


//class 的取值函数(getter)和存值函数(setter) class MyClass { constructor() { // ... } get prop() { return 'getter'; } set prop(value) { console.log('setter: '+value); } } let inst = new MyClass(); inst.prop = 123; // setter: 123 inst.prop // 'getter'

 

 

 

posted @ 2018-12-05 20:00  G_Owen  阅读(1145)  评论(0编辑  收藏  举报