8. es6 class 类,

"Hello World, Hello Blog"

Posted by wudimingwo on December 15, 2018
1
2
3
4
      function Animal (name, age) {
      	this.name = name;
      	this.age = age;
      }

构造函数的缺点

  • 不看函数体, 无法知道是普通函数还是构造函数
  • 构造函数当做普通函数执行, 会产生全局变量.

es6 class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
      class Animal {

      }
      console.log(typeof Animal);/ function


babel翻译

"use strict";
      / 可以看出 这个函数的作用,就是为了让构造函数只能用 new 的方式进行调用
      function _classCallCheck(instance, Constructor) {
        if(!(instance instanceof Constructor)) {
          throw new TypeError("Cannot call a class as a function");
        }
      }

      var Animal = function Animal() {
        _classCallCheck(this, Animal);
      };
  • 只能通过 new 进行调用
    1
    2
    
        Animal();/ 报错
        new Animal();/ 不报错
    
  • 在同一个块级作用域下,不允许重复声明
  • 先定义后使用, 也就是有暂时性死区(TDZ)

constructor ``` class Animal { /注意在这里定义函数 不能出现 function (){} 只能用es6声明函数的方法 constructor(name, age = 18){ this.name = name; this.age = age; } }

1
          console.log(Animal.prototype.constructor == Animal);/ true ``` > * 可知 class {} 这个大括号不是 对象, 是一种语法糖 > * 语义化很好, 类名, 构造函数 两个概念分了开来. > * 疑问? 在 这个类里定义的函数, 是在这个类的 原型上定义嘛? > 是的

为什么用原型?

  • 增加代码复用性
  • 节省空间
1
2
3
4
5
6
7
8
9
10
11
12
13
            class Animal {
                constructor(name, age = 18){
                  this.name = name;
                  this.age = age;
                }
/ 相当于定义在原型上.
                showName () {
                  console.log(this.name);
                }
            }
              
              let dog = new Animal('dog',2);
              console.log(dog.showName == Animal.prototype.showName);/true

可知, 在class{ } 里定义的函数, 就是定义在原型上的.

什么是静态属性,静态方法? 就像 jq里的工具方法 对应的是 实例方法, 原型链上的方法. 例子 Object.is()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
            class Animal {
                constructor(name, age = 18){
                  this.name = name;
                  this.age = age;
                }
                showName () {
                  console.log(this.name);
                }
                / 相当于 Animal.createInstance 在Animal 函数上进行定义
                static createInstance (name,age) {
                  return new Animal(name,age)
                }
                static a = 123/ 报错
            }
              
              let dog = Animal.createInstance('dog',2);
              console.log(dog);
              

可知, static 方式只能在 Animal 上定义方法, 暂不能定义属性


一等公民 class function

  • 可以当做参数
  • 可以被返回
  • 可以立即执行
  • 可以赋值给其他变量

当参数 ``` function create (fn) { return new fn(); }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
          let obj = create(class{
            constructor (){
              this.name = 'mike'
            }
          });
          console.log(obj); ``` > 立即执行 ```
          let obj = new class {
            constructor (name ){
              this.name = name;
            }
            
          }('mike');
          
          console.log(obj); ``` > 被返回
1
2
3
4
5
6
7
8
9
10
11
12
13
14
              function returnClass () {
                let count = 0;
              	return class{
              	  constructor (name) {
              	    this.name = name;
              	    this.count = count;
              	  }
              	}
              }
              
              let obj = new (returnClass())('mike')/ 正常
/这里可以看出 默认会先 执行 new returnClass, 再对返回函数进行()执行
              let obj = new returnClass()('mike')/ 报错
              console.log(obj);

class 生成器方法 ``` class iteratorArray { constructor (arr = []) { this.arr = arr; }

1
2
3
4
5
6
7
8
9
10
            *[Symbol.iterator](){
              yield *this.arr[Symbol.iterator]()
            }
          }
          
          let arr = new iteratorArray([1,2,3]);
          
          for(let item of arr) {
            console.log(item);
          } ``` ![image.png](https://upload-images.jianshu.io/upload_images/13637909-a81d5e40194e6be8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) > 上面的代码到底干了什么? > 一个类返回的对象可以通过 设置 *[Symbol.iterator](){yield} , 进行迭代 > yield *this.arr[Symbol.iterator]() 的意思是把arr的指针添加进实例对象的指针组之中.

测试 可以 yield * this.arr, 因为默认会调用arr的迭代器[Symbol.iterator] ``` class iteratorArray { constructor (arr = []) { this.arr = arr; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
            *[Symbol.iterator](){
              yield *this.arr
            }
          }
          
          let arr = new iteratorArray([1,2,3]);
          
          for(let item of arr) {
            console.log(item);
          } ``` ![image.png](https://upload-images.jianshu.io/upload_images/13637909-ee44c8c30e321f46.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) > 测试: 我们可以任意的添加各种指针 ```
          class iteratorArray {
            constructor (arr = [],arr1 = []) {
              this.arr = arr;
              this.arr1 = arr1;
            }
            
            *[Symbol.iterator](){
              yield *this.arr;
              yield *this.arr1;
              yield *[7,8,9];
              yield 10
            }
          }
          
          let arr = new iteratorArray([1,2,3],[4,5,6]);
          
          for(let item of arr) {
            console.log(item);
          } ``` ![image.png](https://upload-images.jianshu.io/upload_images/13637909-bb9ada1834db151d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) > 测试是否可以用next ![image.png](https://upload-images.jianshu.io/upload_images/13637909-80c49126031421b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

继承, 增加代码复用 类,本身的概念里就包好,要把相似共同的部分抽象出来

es5继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
          function Father (name,age) {
          	this.name = name;
          	this.age = age;
          }
          Father.prototype.showName = function () {
          	console.log(this.name);
          }
          
          function Son () {
          	Father.call(this);
          }
          严格来讲, 实际上是有几种继承方式的
          这几种方式,都会继承但不会让父级实例化,
          或者说, 这几种算是 无new继承
          Son.prototype = Object.create(Father.prototype);
          Son.prototype.__proto__ = Father.prototype;
          Object.setPrototypeOf(Son.prototype,Father.prototype);       
          
          当然最经典的继承 应该是 new 实例化
          圣杯继承
            function temp () {}
            temp.prototype = Father.prototype;
            Son.prototype = new temp();
   

es6继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
          class Animal {
            constructor (name = 'mike', age) {
              console.log(name);
              this.name = name;
              this.age = age;
            }
            showName(){
              console.log(this.name);
            }
          }
          子类,派生类
          class Person extends Animal {
            constructor(name){
              super(name)
        /相当于 Animal.call(this,name)
        / 或者应该这么理解?
            /this = new Animal() / 返回一个this?

            }
            show () {
              console.log(super.showName = Animal.prototype.showName);/true
              console.log(super == Animal.prototype);/ 报错, 
            }

          }
            let p = new Person();

注意, 子类使用extends 继承父类时, constructor里一定要有super字段 否则报错. 不许把super() 放在 this.赋值语句的前面,否则报错. super 作为对象的时候, 指向的是父类的原型 Father.prototype, 但this自动指向实例 super 必须执行,或者调用属性, 否则报错?

好奇,babel怎么翻译的 ``` ‘use strict’;

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable   false; descriptor.configurable = true; if (“value” in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError(“this hasn’t been initialised - super() hasn’t been called”); } return call && (typeof call === “object”   typeof call === “function”) ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== “function” && superClass !== null) { throw new TypeError(“Super expression must either be null or a function, not “ + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.proto = superClass; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(“Cannot call a class as a function”); } }

var Animal = function () { function Animal() { var name = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ‘mike’; var age = arguments[1];

1
2
3
4
5
_classCallCheck(this, Animal);

console.log(name);
this.name = name;
this.age = age;   }

_createClass(Animal, [{ key: ‘showName’, value: function showName() { console.log(this.name); } }]);

return Animal; }();

var Person = function (_Animal) { _inherits(Person, _Animal);

function Person(name) { _classCallCheck(this, Person);

1
return _possibleConstructorReturn(this, (Person.__proto__ || Object.getPrototypeOf(Person)).call(this, name));   }

return Person; }(Animal);

var p = new Person(); ```

好奇害死猫, 陌生字段有点多, 回头再看吧…