ES6中的类与ES5中的类的区别

ES6中的类的特别之处

前言

我在牛客的面经上经常看到面试官问ES6中的类和ES5中的类有什么不同?我查看了不少人给出的答案,但我觉得他们的答案都不是很全,而且一些核心的点都没有提到,故在此写下我的理解,希望能帮助大家,o( ̄▽ ̄)ブ!

ES6的类与ES5的类的区别

首先我要强调的是javascript中并不存在类,ES6引入类只是为了让那些习惯使用java,C++这些语言的开发者更容易使用javascript。ES6中的class只是一个语法糖,它本质上还是基于原型来实现的。下面进入正题。Are you Ready?

  1. 类名不可以重复声明
    ES6中的类与ES5中的类的区别

可以看到错误提示说foo已经被声明了,其实在babel编译(尽管babel编译后的代码不一定和原来的等价)foo是通过let声明的,它大概是以下的形式:

    "use strict";
    //... 
    let Foo = (function() {
      function Foo() {
        // ... 初始化
      }

      //...   做某些事情

      return Foo;
    })()

而在ES5中由于类名是可以重复声明的,这个类名只是被添加入了Object Enviroment Record中(可能有些人不知道Object Enviroment Record,可以参考为什么let和const不能够重复声明)。

  1. ES6中类的声明不会被提升

由上面babel转换后的近似代码,我们知道ES6中的类的声明类似于函数表达式,而函数表达式式不会进行提升的,而ES5中的类是通过构造函数实现的,会存在函数提升。

另外,要注意的是由于类的声明不会提升,所以类也存在暂时性死区,即在类声明之前无法使用该类。

  1. ES6中类的prototype属性是一个不可配置的,不能枚举的只读属性

ES6中的类与ES5中的类的区别

ES6中的类与ES5中的类的区别

可以看到,foo.prototype是不可配置,不可枚举,不可写的,而在ES5中的类的prototype是可写的。

  1. ES6的类中的所有代码都会运行在严格模式下

在上面的babel转换的近似代码中可以看到使用了use strict,我在这里不再多说。

  1. ES6中的类的方法全部是不可枚举的
    ES6中的类与ES5中的类的区别

可以看到,无论是类的静态方法还是类的原型对象prototype上的方法,它们的enumerable都为false,即都是不可枚举的。

ES6中的类与ES5中的类的区别
而再ES5的类中需要使用Object.defineProperty进行手动设置才行。

  1. ES6类只能用new进行调用,不允许使用new关键字调用类里面的方法
    ES6中的类与ES5中的类的区别

可以看到当我们不使用new调用类时,浏览器提示需要使用new进行调用类,而使用new调用类里面的方法时,浏览器给我们报错说:它不是一个构造函数。

而在ES5中时没有这个限制的。

  1. 子类的原型__proto__被修改为父类

ES6中的类与ES5中的类的区别

由于子类的原型__proto__被修改为父类,子类会继承父类的静态方法。

在ES5中,子类的原型__proto__不会被修改,子类的__proto__指向的是Function.prototype

  1. ES6中的类可以继承内置对象

在ES5尝试继承内置对象:

function MyArray() {
  Array.call(this,...arguments);
}

MyArray.prototype = Object.create(Array.prototype,{
  constructor: {
    value: MyArray,
    writable: true,
    configurable: true,
    enumerable: true
  }
})

var colors = new MyArray();
colors[0] = "blue";
console.log(colors.length);   // 0 

colors.length = 0;
console.log(colors[0])        //blue

明显看到console.log的输出与结果不符,这是因为在ES5传统的继承方式中,先由派生类型创建了this,然后调用基类型的构造函数。这意味着this的指向先是指向MyArray,接着又被来自Array的其他属性修饰了。

而在ES6中继承与ES5中刚好相反,先是通过基类(Array)创建this的值,接着派生类修改了this。所以ES6中类能够继承内置对象。

class MyArray extends Array{
}

var colors = new MyArray();
colors[0] = "blue";
console.log(colors.length);   // 1

colors.length = 0;
console.log(colors[0])        //undefined

总结

ES6的类与ES5中的类的不同之处:

  1. ES6中类名不可以重复声明,而ES5可以
  2. ES6中类的声明不会提升,ES5中类的声明会提升
  3. ES6中类的prototype属性是一个不可配置的,不能枚举的只读属性,而ES5中类的prototype属性是可写的。
  4. ES6的类中的所有代码都会运行在严格模式下
  5. ES6中的类的方法全部是不可枚举的,而ES5中需要我们使用Object.defineProperty手动设置
  6. ES6类只能用new进行调用,不允许使用new关键字调用类里面的方法,而ES5没有该限制
  7. ES6中的子类的原型__proto__被修改为父类,而ES5中子类的原型__proto__指向Function.prototype
  8. ES6中的类可以继承内置对象,而ES5不能

以上就是ES6中的类的特别之处,如有错误还请指出。o( ̄▽ ̄)ブ!

上一篇:垂直布局


下一篇:Flutter_03_画一个按钮和一根线