ES6之类
和大多数面向对象的语言(object-oriented programming language)不同,JavaScript 在诞生之初并不支持使用类和传统的类继承并作为主要的定义方式来创建相似或关联的对象。
react中的组件就是用se6的类。
这很令开发者困惑,而且在早于 ECMAScript 1 到 ECMAScript 5 这段时期,很多库都创建了一些实用工具(utility)来让 JavaScript 从表层上支持类。
尽管一些 JavaScript 开发者强烈主张该语言不需要类,但由于大量的库都对类做了实现,ECMAScript 6 也顺势将其引入。
1 ES5之前的模拟的类
在 ECMAScript 5 或更早的版本中,JavaScript 没有类。和类这个概念及行为最接近的是创建一个构造函数并在构造函数的原型上添加方法,这种实现也被称为自定义的类型创建,例如:
function PersonType(name) {
this.name = name;
}
PersonType.prototype.sayName = function() {
console.log(this.name);
};
let person = new PersonType("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonType); // true
console.log(person instanceof Object); // true
说明:
前面的PersonType我们以前一直叫做构造函数,其实他就是一个类型,因为他确实表示了一种类型。
2 ES6中基本的类声明
在ES6直接借鉴其他语言,引入了类的概念。所以再实现上面那种模拟 的类就容易了很多。
//class关键字必须是小写。 后面就是跟的类名
class PersonClass {
// 等效于 PersonType 构造函数。
constructor(name) { //这个表示类的构造函数。constuctor也是关键字必须小写。
this.name = name; //创建属性。 也叫当前类型的自有属性。
}
// 等效于 PersonType.prototype.sayName. 这里的sayName使用了我们前面的简写的方式。
sayName() {
console.log(this.name);
}
}
let person = new PersonClass("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
说明:
- 自有属性:属性只出现在实例而不是原型上,而且只能由构造函数和方法来创建。在本例中,name 就是自有属性。我建议 尽可能的将所有自有属性创建在构造函数中,这样当查找属性时可以做到一目了然。
- 类声明只是上例中自定义类型的语法糖。PersonClass 声明实际上创建了一个行为和 constructor 方法相同的构造函数,这也是 typeof PersonClass 返回 "function" 的原因。sayName() 在本例中作为 PersonClass.prototype 的方法,和上个示例中 sayName() 和 PersonType.prototype 关系一致。这些相似度允许你混合使用自定义类型和类而不需要纠结使用方式。
虽然类和以前的使用构造函数+原型的方式很像,但是还是有一些不太相同的地方,而且要牢记
- 类声明和函数定义不同,类的声明是不会被提升的。类声明的行为和 let 比较相似,所以当执行流作用到类声明之前类会存在于暂存性死区(temporal dead zone)内。
- 类声明中的代码自动运行在严格模式下,同时没有任何办法可以手动切换到非严格模式。
- 所有的方法都是不可枚举的(non-enumerable),这和自定义类型相比是个显著的差异,因为后者需要使用 Object.defineProperty() 才能定义不可枚举的方法。
- 所有的方法都不能使用 new 来调用,因为它们没有内部方法 [[Construct]]。
- 不使用 new 来调用类构造函数会抛出错误。也就是 必须使用new 类() 的方式使用
- 试图在类的方法内部重写类名的行为会抛出错误。(因为在类的内部,类名是作为一个常量存在的)
3 匿名类表达式
函数有函数表达式,类也有类表达式。
类表达式的功能和前面的类的声明是一样的。
let PersonClass = class {
// 等效于 PersonType 构造函数
constructor(name) {
this.name = name;
}
// 等效于 PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
};
let person = new PersonClass("Nicholas");
person.sayName(); // 输出 "Nicholas"
console.log(person instanceof PersonClass); // true
console.log(person instanceof Object); // true
console.log(typeof PersonClass); // "function"
console.log(typeof PersonClass.prototype.sayName); // "function"
4 作为一等公民的类型
在JavaScript中,函数是作为一等公民存在的。(也叫一等函数)。
类也是一等公民。
- 类可以作为参数传递
function createObject(classDef) {
return new classDef();
}
let obj = createObject(class {
constructor() {
}
sayHi() {
console.log("Hi!");
}
});
obj.sayHi(); // "Hi!"
- 立即调用类构造函数,创建单例
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}("Nicholas");
person.sayName(); // "Nicholas"
5 动态计算类成员的命名
类的成员,可以使用[ ] 来计算
let methodName = "sayName";
class PersonClass {
constructor(name) {
this.name = name;
}
[methodName]() {
console.log(this.name);
}
}
let me = new PersonClass("Nicholas");
me.sayName(); // "Nicholas"
6 静态成员
在ES5中,我们可以直接给构造函数添加属性或方法来模拟静态成员。
function PersonType(name) {
this.name = name;
}
// 静态方法。 直接添加到构造方法上。 (其实是把构造函数当做一个普通的对象来用。)
PersonType.create = function(name) {
return new PersonType(name);
};
// 实例方法
PersonType.prototype.sayName = function() {
console.log(this.name);
};
var person = PersonType.create("Nicholas");
在上面的create方法在其他语言中一般都是作为静态方法来使用的。
注意:
ECMAScript 6 的类通过在方法之前使用正式的 static 关键字简化了静态方法的创建。例如,下例中的类和上例相比是等效的:
class PersonClass {
// 等效于 PersonType 构造函数
constructor(name) {
this.name = name;
}
// 等效于 PersonType.prototype.sayName
sayName() {
console.log(this.name);
}
// 等效于 PersonType.create。
static create(name) {
return new PersonClass(name);
}
}
let person = PersonClass.create("Nicholas");
注意:静态成员通过实例对象不能访问,只能通过类名访问!!!
通过和ES5模拟静态方法的例子你应该知道为啥了吧
如果看完这篇文章对大家有所帮助,对前端知识有兴趣的可以加企鹅群:673883249,还有免费公开课!