8. es6 class 类,

      function Animal (name, age) {
        this.name = name;
        this.age = age;
      }

构造函数的缺点

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

es6 class

      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 进行调用
      Animal();/ 报错
      new Animal();/ 不报错
  • 在同一个块级作用域下,不允许重复声明
  • 先定义后使用, 也就是有暂时性死区(TDZ)

constructor

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

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

为什么用原型?

  • 增加代码复用性
  • 节省空间
            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()

            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();
              }
              
              let obj = create(class{
                constructor (){
                  this.name = 'mike'
                }
              });
              console.log(obj);

立即执行

              let obj = new class {
                constructor (name ){
                  this.name = name;
                }
                
              }('mike');
              
              console.log(obj);

被返回

              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;
                }
                
                *[Symbol.iterator](){
                  yield *this.arr[Symbol.iterator]()
                }
              }
              
              let arr = new iteratorArray([1,2,3]);
              
              for(let item of arr) {
                console.log(item);
              }
image.png

上面的代码到底干了什么?
一个类返回的对象可以通过 设置 *Symbol.iterator{yield} , 进行迭代
yield *this.arrSymbol.iterator 的意思是把arr的指针添加进实例对象的指针组之中.

测试 可以 yield * this.arr, 因为默认会调用arr的迭代器[Symbol.iterator]

              class iteratorArray {
                constructor (arr = []) {
                  this.arr = arr;
                }
                
                *[Symbol.iterator](){
                  yield *this.arr
                }
              }
              
              let arr = new iteratorArray([1,2,3]);
              
              for(let item of arr) {
                console.log(item);
              }
image.png

测试: 我们可以任意的添加各种指针

              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

测试是否可以用next


image.png

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

es5继承

          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继承

          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) {
// 这一句确实不太懂, 如果new 了个构造函数, 有可能会让this 是 undefined嘛? 
// 下面报错信息翻译 大概是说, super 没有被调用, 初始化失败?
          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;
      }

// 这是用来 保证 用 new
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];

    _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) {
保证用new 的方式调用
    _classCallCheck(this, Person);

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

  return Person;
}(Animal);

var p = new Person();

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • class的基本用法 概述 JavaScript语言的传统方法是通过构造函数,定义并生成新对象。下面是一个例子: ...
    呼呼哥阅读 4,091评论 3 11
  • 高效能慢生活践行第293天 2018.11.11❤吴虞晨间检视 ❤愿余生都是爱和理想 就寝22:00晨起4:55周...
    _万山无阻_阅读 415评论 0 1
  • 今日体验:今天节后第一天上班,状态还算不错,下午去保险公司定损,挺早就去了,再那里排号,真的很慢,等了有2个多小时...
    京心达王绎龙阅读 87评论 0 0
  • 1、察言观色 懂得去观察客户喜怒哀乐,这对于做业务的人非常重要。而且能起到一个很好的作用,我们回想下小时候,父母开...
    青春沸腾阅读 590评论 0 0
  • 有时候关爱可以温暖有教养的人心,有时候关爱可以让没教养的人得寸进尺。 无论爱与被爱,我们该去丈量深浅吗? 都说公道...
    静谧夜空阅读 744评论 0 2