Wang's blog Wang's blog
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Wang Mings

跟随大神,成为大神!
首页
  • 前端文章

    • HTML教程
    • CSS
    • JavaScript
  • 前端框架

    • Vue
    • React
    • VuePress
    • Electron
  • 后端技术

    • Npm
    • Node
    • TypeScript
  • 编程规范

    • 规范
  • 我的笔记
  • Git
  • GitHub
  • VSCode
  • Mac工具
  • 数据库
  • Google
  • 服务器
  • Python爬虫
  • 前端教程
更多
收藏
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Python爬虫

  • 前端教程

    • 团队规范

    • Project

    • JS

      • Canvas基础
      • 数据结构
      • 树的深度优先遍历与广度优先遍历
      • for in和for of区别
      • ES6-新增特性一览
      • ES6-解构赋值及原理
      • ES6-Object
      • ES6-模块详解
      • ES6-Class
        • [#](#_1-实例属性和原型方法) 1. 实例属性和原型方法
        • [#](#_2-this-指向) 2. this 指向
        • [#](#_3-继承时的原型链) 3. 继承时的原型链
        • [#](#_4-es5和es6继承的不同) 4. ES5和ES6继承的不同
      • ES6-ECMAScript特性汇总
      • 输入URL背后的技术步骤
      • JavaScript与浏览器 - 线程与引擎
      • HTTP跨域解决方案
      • Http 2与Http 1.x比较
      • JavaScript原型
      • JavaScript继承
      • JavaScript事件循环
      • 动手实现Promise
      • JS设计模式
      • JS 经典面试题
      • 排序算法
      • 正则表达式
      • MVC、MVP、MVVM区别
      • Array API与V8源码解析
      • 从V8 sort源码看插入排序
    • NodeJS

    • Vue

    • React

    • 效率工具

    • 读书笔记

  • 教程
  • 前端教程
  • JS
wangmings
2022-07-19
目录

ES6-Class

# # ES6-Class

ES6 的class可以看作只是一个语法糖,注意以下几个可能会犯错误的点。

# # 1. 实例属性和原型方法

实例属性除了定义在constructor()方法里面的this上面,也可以定义在类的最顶层(等于号赋值)。

类中的方法是定义在原型链上(Animal.prototyp),包括getter/setter函数。

详细可看Babel Class解析为ES5的代码 (opens new window) (opens new window)

    class Animal {
      // 实例属性,定义在类实例对象上(a.speak1)
      name = 'MyAnimal'
      speak1 = () => {
        return this
      }
    
      // 原型链方法,定义在原型上(Animal.prototype.speak)
      speak() {
        return this;
      }
      // get也是定义在原型上(Animal.prototype.[get getName])
      get getName() {
        return this.name
      }
    }
    
    const a = new Animal()
    console.log(a) // { name: 'MyAnimal', speak1: f , __proto__: {constructor, speak, ...} }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# # 2. this 指向

实例属性this在定义时就已确定指向当前实例(箭头函数)。

类的方法(包括get/set函数)this默认指向当前实例,但一旦遇到解构时(上下文环境变化),this的值可能变化。

    class Animal {
      // 实例属性。this在书写代码时,就已经确定为当前实例对象(箭头函数)
      speak1 = () => {
        console.log(this, 'speak1') // 在代码
        return this
      }
    
      // 原型链方法。this依赖于运行环境,默认是当前实例对象
      speak() {
        console.log(this, 'speak')
        return this;
      }
    }
    
    let a = new Animal()
    a.speak() // a
    a.speak1() // a
    
    let { speak, speak1 } = a
    speak() // undefined。重要:解构后原型链上的方法,this为undefined
    speak1() // a
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# # 3. 继承时的原型链

类继承时,属性是直接继承,而原型链上的方法是一层一层的继承。

    class B extends Animal {
        b1 = () => {
            console.log(this)
        }
        b() {
            console.log(this)
        }
    }
    
    // B(属性)->B.prototype -> A.prototype
    console.log(new B()) // { speak1, b1, __proto__(B): {b, __proto__(A): {speak} } }
    
    class C extends B {
        c1 = () => {
            console.log(this)
        }
        c() {
            console.log(this)
        }
    }
    // C(属性) -> C.prototype ->B.prototype -> A.prototype
    console.log(new C()) // { speak1, b1, c1, __proto__(C): {c, __proto__(B): {b, __proto__(A):{speak} } } }
    
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# # 4. ES5和ES6继承的不同

ES5的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.apply(this))。

ES6的继承则不同,在单重继承时,基本同ES5一致;当多重继承时,子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。详细看以下babel es6转es5 _possibleConstructorReturn应用。

es6:

    class Person {
      static body = 'bofy';
      constructor(age) {
        this.name = 123
        this.age = age
      }
    
      getName() {
        return this.name
      }
    }
    
    class Doctor extends Person {
        constructor(age) {
          super(age)
          this.skill = 'shoushu'
        }
    }
    
    // 多重继承
    class Superman extends Doctor {
    }
    
    var d = new Doctor(35)
    d.name
    
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

babel 转译为 es5:

    "use strict";
    
    function _typeof(obj) {
      if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
        _typeof = function _typeof(obj) {
          return typeof obj;
        };
      } else {
        _typeof = function _typeof(obj) {
          return obj &&
            typeof Symbol === "function" &&
            obj.constructor === Symbol &&
            obj !== Symbol.prototype
            ? "symbol"
            : typeof obj;
        };
      }
      return _typeof(obj);
    }
    
    function _possibleConstructorReturn(self, call) {
      // call有值,则返回call
      if (call && (_typeof(call) === "object" || typeof call === "function")) {
        return call;
      }
      return self
    }
    
    function _getPrototypeOf(o) {
      // setPrototypeOf是ES6提案
      _getPrototypeOf = Object.setPrototypeOf
        ? Object.getPrototypeOf
        : function _getPrototypeOf(o) {
            // getPrototypeOf在ES5就有,只是ES6中有一些改动
            return o.__proto__ || Object.getPrototypeOf(o);
          };
      return _getPrototypeOf(o);
    }
    
    // 原型链继承
    function _inherits(subClass, superClass) {
      if (typeof superClass !== "function" && superClass !== null) {
        throw new TypeError("Super expression must either be null or a function");
      }
      // 实现继承
      subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: { value: subClass, writable: true, configurable: true }
      });
      // 设置subClass.__proto__ = superClass,为的是getPrototypOf时能拿到superClass这个构造函数。
      if (superClass) _setPrototypeOf(subClass, superClass);
    }
    
    function _setPrototypeOf(o, p) {
      _setPrototypeOf =
        Object.setPrototypeOf ||
        function _setPrototypeOf(o, p) {
          o.__proto__ = p;
          return o;
        };
      return _setPrototypeOf(o, p);
    }
    
    function _instanceof(left, right) {
      if (
        right != null &&
        typeof Symbol !== "undefined" &&
        right[Symbol.hasInstance]
      ) {
        return right[Symbol.hasInstance](left);
      } else {
        return left instanceof right;
      }
    }
    
    // 只允许new方式创建class
    function _classCallCheck(instance, Constructor) {
      if (!_instanceof(instance, Constructor)) {
        throw new TypeError("Cannot call a class as a 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);
      }
    }
    
    function _createClass(Constructor, protoProps, staticProps) {
      if (protoProps) _defineProperties(Constructor.prototype, protoProps);
      if (staticProps) _defineProperties(Constructor, staticProps);
      return Constructor;
    }
    
    function _defineProperty(obj, key, value) {
      if (key in obj) {
        Object.defineProperty(obj, key, {
          value: value,
          enumerable: true,
          configurable: true,
          writable: true
        });
      } else {
        obj[key] = value;
      }
      return obj;
    }
    
    var Person =
      /*#__PURE__*/
      (function() {
        function Person(age) {
          // 检查必须使用new关键字创建类实例
          _classCallCheck(this, Person);
    
          this.name = 123;
          this.age = age;
        }
    
        // class中的方法,都是在Person.prototype
        // class中的静态属性,都是在Person上
        _createClass(Person, [
          {
            key: "getName",
            value: function getName() {
              return this.name;
            }
          }
        ]);
    
        return Person;
      })();
    
    _defineProperty(Person, "body", "bofy");
    
    var Doctor =
      /*#__PURE__*/
      (function(_Person) {
        // Doctor继承自Person
        // Doctor.prototype.__proto__ === Person.prototype(因为Doctor.prototype = Object.create(Person.prototype))
        // Doctor.__proto__ === Person(因为Object.setPrototypeOf(Doctor, Person))
        _inherits(Doctor, _Person);
    
        function Doctor() {
          var _this;
    
          _classCallCheck(this, Doctor);
    
          /**
           * 子类必须在constructor方法中调用super方法,否则新建实例时会报错。
           * 等同于
           * _this = Person.call(this, age) ?Person.call(this, age)   : this
           * 在单重继承时,Person.call()执行后返回空;多重继承时, Person.call()有值返回
          * **/
          _this = _possibleConstructorReturn(
            this,
            _getPrototypeOf(Doctor).call(this, age)
          );
    
          _this.skill = "shoushu";
          // 返回this。在多重继承中,this是父类的this(即:子类实例的构建,基于父类实例。)
          return _this;
        }
    
        return Doctor;
      })(Person);
    
    var Superman =
    /*#__PURE__*/
    function (_Doctor) {
      _inherits(Superman, _Doctor);
    
      function Superman() {
        _classCallCheck(this, Superman);
    
        /**
          * class有多重继承特征,此时子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,加上子类自己的实例属性和方法。
        **/
        return _possibleConstructorReturn(this, _getPrototypeOf(Superman).apply(this, arguments));
      }
    
      return Superman;
    }(Doctor);
    
    var d = new Doctor(35);
    d.name;
    
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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
编辑 (opens new window)
ES6-模块详解
ES6-ECMAScript特性汇总

← ES6-模块详解 ES6-ECMAScript特性汇总→

最近更新
01
theme-vdoing-blog博客静态编译问题
09-16
02
搜索引擎
07-19
03
友情链接
07-19
更多文章>
Theme by Vdoing | Copyright © 2019-2022 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式