class基本声明
在说class
之前,想必大家肯定会想到constructor function
. 看下面代码:
function Foo(name) {
this.name = name
}
class Bar {
constructor(name){
this.name = name
}
}
f = new Foo('xhs')
b = new Bar('xhs')
两个差不多吧,foo function
是在new
的时候,把this
指向当前的新创建的空对象,并且会把进行属性分配。bar class
是在constructor
里进行接收参数。
但是两个还是 有些不同
class
声明并不像function
声明,他不存在提升。他类似let
声明,存在TDZ(temporal dead zone)
。class
中的代码都会自动的使用严格模式,没办法选择。- 所有的方法都是不可枚举的(
non-enumerable
), 注:非绑定当前对象的方法。 class
内所有方法内部都缺少[[Construct]]
方法,所以如果对这些方法进行new
会出错。- 不携带
new
操作符调用class
会报错。 - 尝试在类的方法中改变类名会出错。
考虑到上面这几点,下面来看一个等价的例子:
class PersonClass {
// equivalent of the PersonType constructor
constructor(name) {
this.name = name;
}
// equivalent of PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
}
上面的代码将等价下面无class
的语法
// direct equivalent of PersonClass
let PersonType2 = (function() {
"use strict";
const PersonType2 = function(name) {
// make sure the function was called with new
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(PersonType2.prototype, "sayName", {
value: function() {
// make sure the method wasn't called with new
if (typeof new.target !== "undefined") {
throw new Error("Method cannot be called with new.");
}
console.log(this.name);
},
enumerable: false,
writable: true,
configurable: true
});
return PersonType2;
}());
我们来分析上面这个无class
语法的代码段。
首先注意到这里有两个PersonType2
的声明(let
声明在作用域外面,const
在IIFE
里),这个就是禁止类方法覆盖类名。
在构造方法里有new.target
来检测确保通过new
调用,与之相对的是对方法的检测,排除new
方法调用的可能,否则抛错。在下面就是enumerable: false
,最后返回这个构造函数.
虽然上面的代码可以实现class
的效果,但是明显,class
更加简洁方便。
类的常量名称。
常量是不可被改变的,否则就会报错。类的名称只是在内部使用const
,这就意味着在内部不可以改变名称,外面却可以。
class Foo {
constructor() {
Foo = "bar"; // 执行的时候报错。
}
}
// 这里不会报错。
Foo = "baz";
class表达式
class
和function
类似,也可以使用表达式。
let PersonClass = class {
// equivalent of the FunctionName constructor
constructor(name) {
this.name = name;
}
// equivalent of FunctionName.prototype.sayName
sayName() {
console.log(this.name);
}
};
可以发现,表达式语法类似,使用class
的表达式还是声明都只是风格的不同,不像构造函数的声明和表达式有着提升的区别。
当然,上面的表达式是一个匿名表达式,我们可以创建一个携带名称的表达式。
let PersonClass = class PersonClass2 {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
};
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass2); // undefined
可以发现上面输出PersonClass2
是未定义,因为他只有存在类定义中, 如需了解,我们做下面的一个转变:
// direct equivalent of PersonClass named class expression
let PersonClass = (function() {
"use strict";
const PersonClass2 = function(name) {
// make sure the function was called with new
if (typeof new.target === "undefined") {
throw new Error("Constructor must be called with new.");
}
this.name = name;
}
Object.defineProperty(PersonClass2.prototype, "sayName", {
value: function() {
// make sure the method wasn't called with new
if (typeof new.target !==