class转换成ES5的语法是什么意思?

224 阅读4分钟

参考文章:深入理解JS中的对象(三):class 的工作原理
学习交流,如有错漏,敬请指摘,共同学习!!

通过在线工具 ES6 to ES5 来分析 class 背后真正的实现

// ES6
class People

等同于

// ES5

"use strict";

1.     function _instanceof(instance, Constructor) {
2.         if (
3.             Constructor != null 
4.             && typeof Symbol !== "undefined" 
5.             && Constructor[Symbol.hasInstance]
6.         ) { 
7.             return !!Constructor[Symbol.hasInstance](instance); 
8.         } else { 
9.             return instance instanceof Constructor; 
10.         } 
11.     }
12. 
13.     function _classCallCheck(instance, Constructor) { 
14.         if (!_instanceof(instance, Constructor)) { 
15.             throw new TypeError("Cannot call a class as a function(不能将类作为函数调用)"); 
16.         } 
17.     }
18. 
19.     var People = function People() {
20.       _classCallCheck(this, People);
21.     };

先说结论:
总的来说class做了这么几件事:
定义一个函数,确定这个函数是不是用new关键字创造出来的
确定这个函数是构造函数(我认为本质上仍然判断是不是new创造出来的)
下面详解一下代码

解析一下这个代码,我们可以看到:

一、(19-21行)
定义了一个变量People
函数People赋值给变量People,即People为函数。
People函数中调用了一个函数:_classCallCheck(this, People)

二、(13-17行)
_classCallCheck(this, People)函数的参数一个是this,一个是People函数。
_classCallCheck(this, People)函数中,通过自定义的函数_instanceof判断传进来的this的原型对象prototype是否在People的原型链上出现。
翻译成人话就是,他判断这个People是否是通过关键字new出来的
这也是必须通过new创建class的原因
如果不是通过new创建的,则直接抛出异常

三、(1-11行)
我们回看_instanceof这个函数
它在if中连用三个条件同时成立,我刚开始看的时候根本看不懂,于是去知乎提问:
这里给大家po一下知乎大佬的回答,因为不能转载,所以大家直接过去看,是真的厉害!!!
大佬说这三个条件都是一种防御性条件判断上古时期面对鱼龙混则的JavaScript就是这么写的

接着说,判断完该有的工具都有,我们就可以在这个里面
这个对象是不是new出来的
Constructor[Symbol.hasInstance](instance)
这句
首先说一下它的形式:
即取一个对象的属性,括号中是它的参数,示例如下

let obj = {
    a:function(a){console.log(a)}
}

obj["a"](1)  // 1
Constructor :Constructor构造函数属于被实例化的特定类对象 。
                构造函数初始化这个对象,并提供可以访问其私有信息的方法。
Symbol.hasInstance用于判断某对象是否为某构造器的实例。

上面那一句话就是判断People是否为Constructor的实例。

补充说明一下中括号的用法:

// 中括号。对象[属性]
var obj= {name:'jack'};
obj['2a'] = 'test';  // 创建对象属性
obj['name']; // -->jack  获取对象属性
obj['2a']; // --> test (不能经过obj.2a获取)  通过中括号创建的对象的属性只能通过中括号获取。

此文顶部的参考文章中有提到两个问题:

1-不能直接像函数调用一样调用类People(),必须通过 new 调用类,如 new People()

这是因为

 如果直接调用 People(),
 由于是严格模式下执行`(使用class关键字,必然导致其所在js为严格模式)`,
 此时的 thisundefined`
 (非严格模式中,直接调用,函数中this指向全局;如果是严格模式,则是undefined)`,
 调用 _instanceof 函数检查继承关系其返回值必然为 false,
 所以必然会抛出 TypeError 错误。

2-不会声明提前

是因为

 class 声明的类转化为的是一个函数表达式,并且用变量 People 保存函数表达式的值
 
 而 函数表达式 只能在代码执行阶段创建而且不存在于变量对象中
 所以如果在 class 声明类之前使用,就相当于在给变量 People 赋值之前使用
 此时使用是没有意义的,因为其值为 undefined,直接使用反而会报错
 所以 ES6 就规定了在类声明之前访问类会抛出 ReferenceError 错误(类没有定义)。