实例化
在JS中,生成实例对象的传统方法是通过构造函数,例如:
function Point(x,y){
this.x=x;
this.y=y;
}
Point.prototype.toString=function(){
return this.x+' '+this.y;
}
var p=new Point(1,2);
console.log( p.toString() );//1 2
而ES6则引入了类的概念,作为对象的模板,通过class关键字,可以定义类。
我们使用ES6的方法将上面的例子改写一下。
//定义类
class Point {
constructor(x,y){
this.x=x;
this.y=y;
}
toString(){
return this.x+'+'+this.y;
}
}
var b=new Point(1,2);
console.log( b.toString() );//1 + 2
习惯于JS的同学,可能不太理解这种做法。其实本质上是一样的,只要你理解了JS中原型对象的原理。
从上面例子中,我们可以看到定义了一个Point的类,类里面有一个constructor的方法,这就是构造方法,而this关键字则代表实例对象,实例化的时候this指向实例对象。
Point类除了构造方法以外,还定义了一个toString方法,注意,定义类的时候,不需要加上function这个关键字,方法之间也不需要逗号分隔,加了会报错。
console.log(typeof Point);//function
Point===Point.prototype.constructor;//true
从上面代码中我们可以看出,实例化的时候本质都没有变,构造函数以及原型对象,只是换了种形式。使用的时候也是直接new构造函数,该传参的传参。
事实上,类的所有方法都是定义在类的prototype属性上。
let p1=new Point(1,2);
p1.constructor===Point.prototype.constructor;//true
上面代码中p1是Point的实例,p1.constructor方法就是Point类原型的方法,由于类的的方法动定义在prototype对象上,所以可以利用Object.assign方法给原型对象添加新方法。
Object.assign(Point.prototype,{
toString(){},
toValue(){}
});
注意,ES6中,类的内部所有定义的方法都是不可枚举的,而ES5中是可以枚举的。
constructor构造函数
constructor方法是类的默认方法,通过new命令生成实例对象时,自动调用该方法。一个类必须有constructor方法,如果没有显示定义,则会默认的添加一个空的构造函数,这在ES5中是一样的。
constructor方法默认返回实例对象,同时也可以指定返回另一个对象。
class Foo {
constructor(){
return Object.create(null);
//返回一个新的null对象
}
}
所以:
var b=new Foo();
console.log(b.constructor);//undfined
console.log(b instanceof Foo);//false
注:构造函数一定要new,不然会报错。
类的实例对象
与ES5一样,实例的属性除非显示定义在其本身(即显示定义在this对象上),否则都是定义在原型上(即定义在class上);
var point = new Point(2, 3);
console.log( point.toString() )// (2, 3)
console.log( point.hasOwnProperty('x') ) // true
console.log( point.hasOwnProperty('y') )// true
console.log( point.hasOwnProperty('toString') ) // false
console.log( point.__proto__.hasOwnProperty('toString') )// true
注:谨慎使用实例的__proto__
属性修改原型对象,原理同ES5一样,会导致同样继承与原型对象的实例发现变化。
不存在变量提升
new Foo();
class Foo{}
Foo类使用在前,定义在后,会报错。
但是:
{
let Foo = class {};
class Bar extends Foo {}
}
这个是可以的,因为在第一步已将一个类赋给一个变量Foo。
Class表达式
跟函数一样,类也可以使用表达式的形式定义
const MyClass=class Me{
getClassName(){
return Me.name;
}
}
let lg=new MyClass();
console.log( lg.getClassName() );//Me
console.log( Me.name );//报错
这个类的名字是MyClass而不是Me,Me只在Class内部代码中可用,指代当前类。
如果class内部没有用到的话,可用省略Me.
let MyClass=class{}
采用Class表达式,可用写出立即执行的Class
let person=new class{
private name;
constructor(name){
this.name=name;
}
sayName(){
console.log( this.name );
}
}('张三');
person.sayName();//张三
上面代码中,person是一个立即执行的类的实例。可以参考ES5中匿名函数立即执行。
本文参考ES6标准入门