使用ES6中的class创建对象
ES6引入了 Class(类)这个概念,作为创建对象的模板。
在创建对象之构造函数那篇手记中(JavaScript创建对象之构造函数),我们知道创建对象的最佳方式就是组合使用构造函数和原型,其实,ES6 的class可以看作构造函数+原型创建对象的另一种写法,除了写法更符合面向对象编程的语法之外,并没有实质性的改变。
例子:
构造函数+原型
//构造函数
function Obj(name, age) {
this.name = name;
this.age = age;
//原型对象
if (typeof(this.getName) != "function") {
Obj.prototype.getName = function() {
return this.name;
}
} else if (typeof(this.job) != "string") {
Obj.prototype.iob = "IT";
}
}
//实例
var p1 = new Obj("Tom", 20);
//测试
console.log(p1.age);
console.log(p1.getName());
//输出:20,Tom
ES6 的 class
//构造函数
class Obj {
//原型对象上的方法
constructor(name, age) {
this.name = name;
this.age = age;
}
job() {
return "IT";
}
getName() {
return this.name;
}
}
//实例
var p1 = new Obj("Tom", 20);
//测试
console.log(p1.age);
console.log(p1.getName());
console.log(typeof(Obj));
//constructor属性指向其构造函数
console.log(p1.constructor == Obj);
//__proto__属性指向其原型
console.log(p1.__proto__ == Obj.prototype);
//输出:20,Tom,function,true,true
重点解析之使用表达式定义Class
从上面的代码测试中可以看到:ES6中的class的数据类型是函数(构造函数也是函数),因此与函数一样,class也可以使用表达式的形式定义。
例子:
var Obj = class {
constructor(name, age) {
this.name = name;
this.age = age;
}
job() {
return "IT";
}
getName() {
return this.name;
}
}
//实例
var p1 = new Obj("Tom", 20);
//测试
console.log(p1.age);
console.log(p1.getName());
console.log(typeof(Obj));
//输出:20,Tom,function
class表达式的变量名与class的类名可以同时存在,但此时class的类名只在class的内部代码可用,指代当前class;而class表达式的变量名可以在创建实例的时候调用,指代当前class。
例子:
var MyObj = class Obj {
constructor(name, age) {
this.name = name;
this.age = age;
}
job() {
return "IT";
}
getName() {
return this.name;
}
getClassName() {
//注意这里用的是Obj而不是MyObj
return Obj.name;
}
}
//实例:注意这里用的是MyObj而不是Obj
var p1 = new MyObj("Tom", 20);
//测试
console.log(p1.getClassName());
console.log(MyObj.name);
//输出:Obj,Obj
如果class的内部没用到class的类名的话,可以省略class的类名。采用class表达式这种写法,可以写出立即执行的class。
例子:
//实例
var p1 = new class {
constructor(name, age) {
this.name = name;
this.age = age;
}
job() {
return "IT";
}
getName() {
return this.name;
}
}("Tom", 20)
//测试
console.log(p1.age);
console.log(p1.getName());
//输出:20,Tom
重点解析之Constructor方法
在创建class的同时,也会默认为这个class创建constructor方法。这个方法就算没有显式定义,一个空的constructor方法也会被默认添加。constructor方法默认返回实例对象的属性(写在this上的属性),与写在构造函数里面的this属性有相同效果。
例子:
//实例
var p1 = new class {
constructor(name, age) {
this.name = name;
this.age = age;
}
job() {
return "IT";
}
getName() {
return this.name;
}
}("Tom", 20)
//测试
//hasOwnProperty()方法用于检测实例对象的属性是写在实例上(返回true),还是继承自原型上(返回false)
console.log(p1.hasOwnProperty("name"));
console.log(p1.hasOwnProperty("constructor"));
console.log(p1.hasOwnProperty("job"));
console.log(p1.hasOwnProperty("getName"));
//输出:true,false,false,false
通过上面例子的测试,可以发现:class内部的方法都是定义在原型对象上面,而constructor方法也同样如此,但是它返回的是实例对象的属性。既然class的所有方法都默认定义在class的原型属性上面,那我们就可以使用Object.assign方法一次性向class添加多个方法。
例子:
class Obj {
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Object.assign(Obj.prototype, {
job() {
return "IT";
},
getName() {
return this.name;
}
});
//实例
var p1 = new Obj("Tom", 20);
//测试
console.log(p1.job());
console.log(p1.getName());
//输出:IT,Tom
class中定义的所有方法,都会被实例继承。但是如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是只能通过class来调用,这称之为“静态方法”。静态方法中的this关键字指向class本身,而不是实例。另外,class内部只有静态方法,没有静态属性。
例子:
class Obj {
constructor(name, age) {
this.name = name;
this.age = age;
}
static job() {
return "IT";
}
static getName() {
return this.name;
}
}
//实例
var p1 = new Obj("Tom", 20);
//测试
console.log(p1.age);
console.log(Obj.getName());
//输出:20,Obj
最后,class必须使用new调用,否则会报错。
class与对象字面量的相似之处
class与字面量的相似之处不仅仅定义class的语法类似于对象字面量的简写形式,class还有以下两点与对象字面量类似。
1、class也支持定义访问器属性
例子:
let person = new class {
constructor(name, age) {
this.name = name;
this.age = age;
this._family = "mama";
}
get family() {
return this._family;
}
set family(v) {
this._family = v;
}
getName() {
return this.name;
}
}("Tom", 19);
console.log(person.family); //输出:mama
person.family = "baba";
console.log(person.family); //输出:baba
console.log(Object.keys(person)); // 输出:["name", "age", "_family"]
*class中所有方法默认都是不可枚举的,因此使用get和set关键字定义的属性也是不可枚举的。
2、class也支持用表达式定义或访问属性
例子:
let fn = "getName";
let person = new class {
constructor(name, age) {
this.name = name;
this.age = age;
}
[fn]() {
return this.name;
}
}("Tom", 19);
console.log(person[fn]()); //输出:Tom
console.log(person["getName"]()); //输出:Tom
文中的代码部分,带有“例子”和“测试代码”字样的,只是用来学习或测试某一功能用的代码,不可以直接用于项目的开发中。带有“代码如下”字样的,都是经过本人测试,简单修改即可用于项目开发中的代码,如有错误,欢迎指出。