ES6中的类的特别之处
前言
我在牛客的面经上经常看到面试官问ES6中的类和ES5中的类有什么不同?我查看了不少人给出的答案,但我觉得他们的答案都不是很全,而且一些核心的点都没有提到,故在此写下我的理解,希望能帮助大家,o( ̄▽ ̄)ブ!
ES6的类与ES5的类的区别
首先我要强调的是javascript
中并不存在类,ES6引入类只是为了让那些习惯使用java,C++这些语言的开发者更容易使用javascript。ES6中的class
只是一个语法糖,它本质上还是基于原型来实现的。下面进入正题。Are you Ready?
- 类名不可以重复声明
可以看到错误提示说foo
已经被声明了,其实在babel编译(尽管babel编译后的代码不一定和原来的等价)foo
是通过let声明的,它大概是以下的形式:
"use strict";
//...
let Foo = (function() {
function Foo() {
// ... 初始化
}
//... 做某些事情
return Foo;
})()
而在ES5中由于类名是可以重复声明的,这个类名只是被添加入了Object Enviroment Record
中(可能有些人不知道Object Enviroment Record
,可以参考为什么let和const不能够重复声明)。
- ES6中类的声明不会被提升
由上面babel转换后的近似代码,我们知道ES6中的类的声明类似于函数表达式,而函数表达式式不会进行提升的,而ES5中的类是通过构造函数实现的,会存在函数提升。
另外,要注意的是由于类的声明不会提升,所以类也存在暂时性死区,即在类声明之前无法使用该类。
- ES6中类的prototype属性是一个不可配置的,不能枚举的只读属性
可以看到,foo.prototype
是不可配置,不可枚举,不可写的,而在ES5中的类的prototype是可写的。
- ES6的类中的所有代码都会运行在严格模式下
在上面的babel转换的近似代码中可以看到使用了use strict
,我在这里不再多说。
- ES6中的类的方法全部是不可枚举的
可以看到,无论是类的静态方法还是类的原型对象prototype
上的方法,它们的enumerable
都为false
,即都是不可枚举的。
而再ES5的类中需要使用Object.defineProperty
进行手动设置才行。
- ES6类只能用
new
进行调用,不允许使用new
关键字调用类里面的方法
可以看到当我们不使用new
调用类时,浏览器提示需要使用new
进行调用类,而使用new
调用类里面的方法时,浏览器给我们报错说:它不是一个构造函数。
而在ES5中时没有这个限制的。
- 子类的原型
__proto__
被修改为父类
由于子类的原型__proto__
被修改为父类,子类会继承父类的静态方法。
在ES5中,子类的原型__proto__
不会被修改,子类的__proto__
指向的是Function.prototype
。
- 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中的类的不同之处:
- ES6中类名不可以重复声明,而ES5可以
- ES6中类的声明不会提升,ES5中类的声明会提升
- ES6中类的
prototype
属性是一个不可配置的,不能枚举的只读属性,而ES5中类的prototype
属性是可写的。 - ES6的类中的所有代码都会运行在严格模式下
- ES6中的类的方法全部是不可枚举的,而ES5中需要我们使用
Object.defineProperty
手动设置 - ES6类只能用
new
进行调用,不允许使用new
关键字调用类里面的方法,而ES5没有该限制 - ES6中的子类的原型
__proto__
被修改为父类,而ES5中子类的原型__proto__指向Function.prototype
- ES6中的类可以继承内置对象,而ES5不能
以上就是ES6中的类的特别之处,如有错误还请指出。o( ̄▽ ̄)ブ!