JavaScript ES6的新特性使用新方法定义Class
ES6(ECMAScript6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本了)。上一次标准的制订还是2009年出台的ES5。目前ES6的标准化工作正在进行中,预计会在14年12月份放出正式敲定的版本。但大部分标准已经就绪,且各浏览器对ES6的支持也正在实现中。
ES6中定义类的方式,就是ES3和ES5中定义类的语法糖,虽然也有些区别,但是整体定义类的方式更加简洁,类的继承更加方便,如果想对ES6中的继承更加熟悉,最好了解ES5中原型继承的方式,博客园中说JS继承的文章很多,想要深入了解的同学自己去搜;
定义一个class:
每一个使用class方式定义的类默认都有一个constructor函数,这个函数是构造函数的主函数,该函数体内部的this指向生成的实例,say(){}为原型上的方法,我们定义一个简单的类:
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
say(){
console.log("sayhi");
}
};
newPerson().say();//控制台会输出sayhi
注意:ES6中声明的类不存在函数声明提前的问题,类必须先声明再使用,否则会出现异常,我们只是把上面Demo中的代码位置一改,立马报错,(如果用ES5中的思维去理解的话,声明的类没有声明提前,有关声明提前的知识点,通过class类名{}声明的类,就是var类名=function(){});
运行下面代码
"usestrict";
newPerson().say();
classPerson{
constructor(name){
this.name=name;
}
say(){
console.log("sayhi");
}
};
定义函数的静态方法:
如果定义函数的时候,大括号内部,函数名前声明了static,那么这个函数就为静态函数,就为静态方法,和原型没啥关系:
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
staticsay(){
console.log("sayhi");
}
};
Person.say();
定义原型方法:
定义原型方法,直接这样声明:函数名(){}即可,小括号内部为参数列表,大括号内部为代码块, ES5中要定义原型方法是通过:构造函数.prototype.原型方法名(){},这种书写形式很繁琐,使用ES6定义原型的方式有点像java和C#了,这些都是比较高级语言的特征:
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
say(){
console.log("sayhi");
}
sing(){
console.log("lalalalala");
}
};
newPerson().say();//输出:sayhi
newPerson().sing();//输出:lalalalala
静态属性和原型属性:
只能在类定义完毕以后再定义静态属性,有点坑爹,语言作者实现这种方式可能是为了避免代码的混乱,所有的静态属性在同一个地方定义,代码回更加规范?
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
};
Person.hands=2;
console.log(Person.hands);
原型上面也不能定义属性了,我们只能在原型上定义set和get,取值和设值器,要注意取值器和设值器是在原型上....:
运行下面代码
classPerson{
constructor(_name){
this._name=_name;
}
getname(){
returnthis._name;
}
setname(_name){
this._name=_name;
}
}
varp=newPerson();
p.name="heheda";
console.log(p.name);//输出:heheda
console.log(p._name);//输出:heheda
如果要定义原型属性的话,直接把属性定义在constructor内部即可,如果是继承的话,子类也会继承父类的这个属性:
运行下面代码
classPerson{
constructor(){
this.name="default";
}
}
classManextendsPerson{
constructor(){
super();
}
}
console.log(newMan().name);
类的继承extends:
ES5已经有继承,但是这种继承经常绕来绕去的,ES6的继承也只是基于原型继承的封装(语法糖),虽然的确简洁了不少,还是java的继承比较好学啊,下面Demo的例子中的SMan是超人的意思,别想歪了;
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
say(){
console.log("sayhi");
returnthis;
}
};
classSManextendsPerson{
constructor(name,power){
super(name);
this.superPower=power;
}
show(){
console.log(this.superPower);
returnthis;
}
}
console.log(newSMan("Clark","pee").show().say().name);//输出:peesayhiClark
如果要使用继承的话,在子类中必须执行super()调用父类,否者编译器会抛错, 在子类中的super有三种作用,第一是作为构造函数直接调用,第二种是作为父类实例,第三种是在子类中的静态方法中调用父类的静态方法;
ES6继承的和ES5继承的主要区别,ES5中常用的继承是把子类的原型设置为父类的实例,子类自然就有了父类的所有方法和属性:
运行下面代码
varSup=function(){
this.sub=true;
};
Sup.prototype.protoSup={sup:"sup"};
varSub=function(){
this.sub=true;
};
Sub.prototype=newSup();//继承原型;
Sub.prototype.constructor=Sub;//修正constructor;
而在ES6中实现的继承更加精巧,不会有受到父类的干扰,这种继承是结合了apply继承和原型继承实现的组合继承:
运行下面代码
varSup=function(){
this.sub=true;
};
varSub=function(){
this.sup=true;
Sup.apply(this);//继承this的属性和方法;
};
Sub.__proto__=Sup;//继承Sup静态属性;
Sub.prototype=Object.create(Sup.prototype,{constructor:{value:Sub,enumerable:false,writable:true,configurable:true}});//继承原型属性,并覆写constructor;
用图片可以比较容易看出两者区别,图示ES5和ES6继承的区别:http://keenwon.com/1524.html;
ES5模拟ES6的继承:
因为有了转码器babel,我们能通过ES5的代码,去窥探ES6的继承到底是怎么实现,ES6的继承:
运行下面代码
"usestrict";
classPerson{
constructor(name){
this.name=name;
}
say(){
console.log("sayhi");
returnthis;
}
};
classSManextendsPerson{
constructor(name,power){
super(name);
this.superPower=power;
}
show(){
console.log(this.superPower);
returnthis;
}
}
console.log(newSMan("Clark","pee").show().say().name);
使用babel转化为ES5以后,代码变成这样了,我自己加了一点注释,原谅我放荡不羁爱自由..:
运行下面代码
var_createClass=function(){
functiondefineProperties(target,props){
for(vari=0;i<props.length;i++){
vardescriptor=props[i];
descriptor.enumerable=descriptor.enumerable||false;
descriptor.configurable=true;
if("value"indescriptor)descriptor.writable=true;
Object.defineProperty(target,descriptor.key,descriptor);
}
}
returnfunction(Constructor,protoProps,staticProps){
//复制原型
if(protoProps)defineProperties(Constructor.prototype,protoProps);
//复制属性
if(staticProps)defineProperties(Constructor,staticProps);
returnConstructor;
};
}();
function_classCallCheck(instance,Constructor){
if(!(instanceinstanceofConstructor)){
thrownewTypeError("Cannotcallaclassasafunction");
}
}
function_possibleConstructorReturn(self,call){
if(!self){
thrownewReferenceError("thishasn'tbeeninitialised-super()hasn'tbeencalled");
}
returncall&&(typeofcall==="object"||typeofcall==="function")?call:self;
}
//下面是ES6继承使用ES5表达出来的代码,_inherits实现的是原型的继承和父类状态属性的继承:
function_inherits(subClass,superClass){
if(typeofsuperClass!=="function"&&superClass!==null){
thrownewTypeError("Superexpressionmusteitherbenullorafunction,not"+typeofsuperClass);
}
//继承父类的原型,并修正constructor为子类;
subClass.prototype=Object.create(superClass&&superClass.prototype,{constructor:{value:subClass,enumerable:false,writable:true,configurable:true}});
//又给子类这个对象定义__proto__为父类,这样能够实现静态属性继承;
if(superClass)Object.setPrototypeOf?Object.setPrototypeOf(subClass,superClass):subClass.__proto__=superClass;
//最后的如果开发者:new子类,实际的状态为:对象{__proto__:父类,constuctor:子类}
};
/*
varSup=function(){};
varSub=function(){};
_inherits(Sub,Sup);
//这个继承实现的意思;作为对象的子类继承父类,作为构造函数的话,子类继承
Sub.prototype.__proto__===Sup.prototype//true
Sub.prototype.constructor===Sub;//true
Sub.__proto__===Sup;//true
*/
varPerson=function(){
functionPerson(name){
_classCallCheck(this,Person);
this.name=name;
}
_createClass(Person,[{
key:"say",
value:functionsay(){
console.log("sayhi");
returnthis;
}
}]);
returnPerson;
}();
;
varSMan=function(_Person){
_inherits(SMan,_Person);
functionSMan(name,power){
//此时的this.__proto__已经指向构造函数的prototyp了
_classCallCheck(this,SMan);
//这句话相当于是ES6中的super(),把父类的属性通过call,执行继承;
var_this=_possibleConstructorReturn(this,Object.getPrototypeOf(SMan).call(this,name));
_this.superPower=power;
//动态返回_this;
return_this;
}
_createClass(SMan,[{
key:"show",
value:functionshow(){
console.log(this.superPower);
returnthis;
}
}]);
returnSMan;
}(Person);
console.log(newSMan("Clark","pee").show().say().name);
多重继承:
使用mix-in,实现多重继承, 书写方式为:classSubextendsmix(obj0,obj1,obj2) ,mix只是一个方法,这个方法我们要自己去定义:
运行下面代码
<html>
<head>
<metacharset="utf-8">
</head>
<body>
<script>
"usestrict";
functionmix(...mixins){
classMix{}
for(letmixinofmixins){
copyProperties(Mix,mixin);
copyProperties(Mix.prototype,mixin.prototype);
}
returnMix;
}
functioncopyProperties(target,source){
for(letkeyofReflect.ownKeys(source)){
if(key!=="constructor"
&&key!=="prototype"
&&key!=="name"
){
letdesc=Object.getOwnPropertyDescriptor(source,key);
Object.defineProperty(target,key,desc);
}
}
}
classMan{
work(){
console.log("working");
}
}
classWoman{
say(){
console.log("saying");
}
}
classSuperManextendsmix(Man,Woman){
constructor(){
super();
}
}
varsm=newSuperMan();
sm.work();
sm.say();
//实际上它们不存在继承关系,只是把属性复制到子类上;
console.log(sminstanceofMan);
console.log(sminstanceofWoman);
</script>
</body>
</html>
以上所述是小编给大家介绍的JavaScriptES6的新特性使用新方法定义Class的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!