<commit_before>---
layout:     post
title:      "2017-07-31-es6-classes"
date:       "2017-07-31 "
author:     "guozhaodong"
---

# es6之Classes

![image](/img/es6-classes/TM20170801103943.jpg)

### es5实现类的方式

> 通过定义一个构造函数，然后在构造函数上定义一些属性，在构造函数的原型上定义一些方法


``` js
function PersonType(name){
    this.name=name;
}

PersonType.prototype.sayName=function(){
    console.log(this.name);
}

var person = new PersonType('xiaoming');
person.sayName();   // "xiaoming"

console.log(person instanceof PersonType);  //true
console.log(person instanceof Object);   //true

```

### es6实现类的方式

#### 1、class声明

> 通过class关键字去声明一个类，并在里面constructor方法里定义一些属性，在里面直接定义的方法就是原型方法

``` js
class PersonClass{

    //等同于PersonType这个构造函数
    constructor(name){
        this.name=name;
    }

    //等同于PersonType.prototype.sayName
    sayName(){
        console.log(this.name);
    }

}

let person = new PersonClass('xiaoming');
person.sayName(); //  "xiaoming"

console.log(person instanceof PersonClass);   //true
console.log(person instanceof Object);   //true

console.log(typeof PersonClass);  // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"

```


#### 2、class表达式

> 函数有函数声明和函数表达式，类的创建同样，可以用class声明，也可以用class表达式来创建

1、匿名类表达式

``` js
let PersonClass = class{
    constructor(name){
        this.name=name;
    }

    sayName(){
        console.log(this.name);
    }
}

let person = new PersonClass('xiaoming');
person.sayName();   // "xiaoming"

console.log(person instanceof PersonClass); //true
console.log(person instanceof Object);   //true

console.log(typeof PersonClass);  //function
console.log(typeof PersonClass.prototype.sayName)  //function

```

2、具名类表达式

``` js
let PersonClass = class PersonClass2{
    constructor(name){
        this.name=name;
    }

    sayName(){
        console.log(this.name);
    }
}

console.log(typeof PersonClass);        // "function"
console.log(typeof PersonClass2);       // "undefined"

```

> 不管是类声明还是类表达式，主要区别就是代码风格不同，除此之外没有什么不同的，而且也不会像函数声明和函数表达式，存在被提升的概念。

上面三种方式定义类实质上就等于下面这种代码：

``` js
let PersonClass =(function(){
    'use strict';

    const PersonClass2 = function(name){
        if(typeof new.target === 'undefined'){
            throw new Error('Constructor must be called with new.');
        }

        this.name=name;
    }

    Object.defineProperty(PersonClass2.prototype,'sayName',{
        value:function(){
            if(typeof new.target !== 'undefined'){
                throw new Error('Method must be called with new.');
            }
            console.log(this.name);
        },
        enumerable:false,
        writable:true,
        configurable:true
    });

    return PersonClass2;
}());

console.log(typeof PersonClass); //function
console.log(typeof PersonClass2);  //undefined

let p1=new PersonClass('xiaoming');
console.log (p1.sayName()) //'xiaoming'

console.log(p1 instanceof PersonClass);  //true
console.log(p1 instanceof Object);  //true
```


#### 为什么要使用class关键字来定义类

1、class定义类时类不会被提升，和`let`一样。
2、 class定义类时所有代码都是运行在严格模式下，且无法退出。
3、class定义类，类的方法是不可枚举的，构造函数定义类只有通过[`Object.defineProperty()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)才能将方法改为不可枚举。
4、class定义类，类的所有方法内部都没有`[[Construct]]`，所以使用new来调用它们会报错。
5、调用类构造器时不使用`new`，会报错。

``` js
    class PersonClass{
        constructor(name){
            this.name=name;
        }    
        sayName(){
            console.log(this.name);
        }
    }
    var p1=new PersonClass('xiaoming');
    console.log(p1.sayName());
    PersonClass('xiaoming');
```

6、试图在类的方法内部重写类名,会抛出错误。

``` js
class Foo{
    constructor(){
        Foo='bar'
    }
}

new Foo();  //报错
```

### 类的一些新特性

#### 1、可作为一级公民<commit_msg>modify classes<commit_after>---
layout:     post
title:      "2017-07-31-es6-classes"
date:       "2017-07-31 "
author:     "guozhaodong"
---

# es6之Classes

![image](/img/es6-classes/TM20170801103943.jpg)

### es5实现类的方式

> 通过定义一个构造函数，然后在构造函数上定义一些属性，在构造函数的原型上定义一些方法


``` js
function PersonType(name){
    this.name=name;
}

PersonType.prototype.sayName=function(){
    console.log(this.name);
}

var person = new PersonType('xiaoming');
person.sayName();   // "xiaoming"

console.log(person instanceof PersonType);  //true
console.log(person instanceof Object);   //true

```

### es6实现类的方式

#### 1、class声明

> 通过class关键字去声明一个类，并在里面constructor方法里定义一些属性，在里面直接定义的方法就是原型方法

``` js
class PersonClass{

    //等同于PersonType这个构造函数
    constructor(name){
        this.name=name;
    }

    //等同于PersonType.prototype.sayName
    sayName(){
        console.log(this.name);
    }

}

let person = new PersonClass('xiaoming');
person.sayName(); //  "xiaoming"

console.log(person instanceof PersonClass);   //true
console.log(person instanceof Object);   //true

console.log(typeof PersonClass);  // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"

```


#### 2、class表达式

> 函数有函数声明和函数表达式，类的创建同样，可以用class声明，也可以用class表达式来创建

1、匿名类表达式

``` js
let PersonClass = class{
    constructor(name){
        this.name=name;
    }

    sayName(){
        console.log(this.name);
    }
}

let person = new PersonClass('xiaoming');
person.sayName();   // "xiaoming"

console.log(person instanceof PersonClass); //true
console.log(person instanceof Object);   //true

console.log(typeof PersonClass);  //function
console.log(typeof PersonClass.prototype.sayName)  //function

```

2、具名类表达式

``` js
let PersonClass = class PersonClass2{
    constructor(name){
        this.name=name;
    }

    sayName(){
        console.log(this.name);
    }
}

console.log(typeof PersonClass);        // "function"
console.log(typeof PersonClass2);       // "undefined"

```

> 不管是类声明还是类表达式，主要区别就是代码风格不同，除此之外没有什么不同的，而且也不会像函数声明和函数表达式，存在被提升的概念。

上面三种方式定义类实质上就等于下面这种代码：

``` js
let PersonClass =(function(){
    'use strict';

    const PersonClass2 = function(name){
        if(typeof new.target === 'undefined'){
            throw new Error('Constructor must be called with new.');
        }

        this.name=name;
    }

    Object.defineProperty(PersonClass2.prototype,'sayName',{
        value:function(){
            if(typeof new.target !== 'undefined'){
                throw new Error('Method must be called with new.');
            }
            console.log(this.name);
        },
        enumerable:false,
        writable:true,
        configurable:true
    });

    return PersonClass2;
}());

console.log(typeof PersonClass); //function
console.log(typeof PersonClass2);  //undefined

let p1=new PersonClass('xiaoming');
console.log (p1.sayName()) //'xiaoming'

console.log(p1 instanceof PersonClass);  //true
console.log(p1 instanceof Object);  //true
```


#### 为什么要使用class关键字来定义类

1、class定义类时类不会被提升，和`let`一样。

2、 class定义类时所有代码都是运行在严格模式下，且无法退出。

3、class定义类，类的方法是不可枚举的，构造函数定义类只有通过[`Object.defineProperty()`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)才能将方法改为不可枚举。

4、class定义类，类的所有方法内部都没有`[[Construct]]`，所以使用new来调用它们会报错。

5、调用类构造器时不使用`new`，会报错。

``` js
    class PersonClass{
        constructor(name){
            this.name=name;
        }    
        sayName(){
            console.log(this.name);
        }
    }
    var p1=new PersonClass('xiaoming');
    console.log(p1.sayName());
    PersonClass('xiaoming');
```

6、试图在类的方法内部重写类名,会抛出错误。

``` js
class Foo{
    constructor(){
        Foo='bar'
    }
}

new Foo();  //报错
```

### 类的一些新特性

#### 1、可作为一级公民
{'fraction_non_alphanumeric': 0.14945469233876396, 'fraction_numerical': 0.015618688568735694, 'mean_word_length': 3.26406429391504, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '341204', 'n_tokens_mistral': 3071, 'n_tokens_neox': 3098, 'n_words': 408}