ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本了)。上一次标准的制订还是2009年出台的ES5。目前ES6的标准化工作正在进行中,预计会在14年12月份放出正式敲定的版本。但大部分标准已经就绪,且各浏览器对ES6的支持也正在实现中。
ES6中定义类的方式, 就是ES3和ES5中定义类的语法糖,虽然也有些区别,但是整体定义类的方式更加简洁,类的继承更加方便, 如果想对ES6中的继承更加熟悉, 最好了解ES5中原型继承的方式, 博客园中说JS继承的文章很多, 想要深入了解的同学自己去搜;
定义一个class:
每一个使用class方式定义的类默认都有一个constructor函数, 这个函数是构造函数的主函数, 该函数体内部的this指向生成的实例,say() {}为原型上的方法, 我们定义一个简单的类 :
运行下面代码
输出say hi
注意: ES6中声明的类不存在函数声明提前的问题, 类必须先声明再使用,否则会出现异常 , 我们只是把上面Demo中的代码位置一改, 立马报错, (如果用ES5中的思维去理解的话, 声明的类没有声明提前, 有关声明提前的知识点, 通过class 类名{} 声明的类,就是var 类名 = function(){});
运行下面代码
如果定义函数的时候, 大括号内部, 函数名前声明了static, 那么这个函数就为静态函数, 就为静态方法, 和原型没啥关系:
运行下面代码
定义原型方法:
定义原型方法,直接这样声明: 函数名 () {} 即可, 小括号内部为参数列表, 大括号内部为代码块,ES5中要定义原型方法是通过: 构造函数.prototype.原型方法名() {},这种书写形式很繁琐, 使用ES6定义原型的方式有点像java和C#了, 这些都是比较高级语言的特征:
运行下面代码
输出 :say hi
new Person().sing(); //
输出 :lalalalala
只能在类定义完毕以后再定义静态属性,有点坑爹, 语言作者实现这种方式可能是为了避免代码的混乱, 所有的静态属性在同一个地方定义, 代码回更加规范?
运行下面代码
原型上面也不能定义属性了, 我们只能在原型上定义set和get, 取值和设值器, 要注意取值器和设值器是在原型上....:
运行下面代码
输出:heheda
console.log(p._name); //
输出:heheda
如果要定义原型属性的话, 直接把属性定义在constructor内部即可, 如果是继承的话, 子类也会继承父类的这个属性:
运行下面代码
类的继承extends:
ES5已经有继承, 但是这种继承经常绕来绕去的, ES6的继承也只是基于原型继承的封装(语法糖), 虽然的确简洁了不少, 还是java的继承比较好学啊, 下面Demo的例子中的SMan是超人的意思,别想歪了;
运行下面代码
输出: pee say hi Clark
如果要使用继承的话, 在子类中必须执行super()调用父类, 否者编译器会抛错, 在子类中的super有三种作用, 第一是作为构造函数直接调用,第二种是作为父类实例, 第三种是在子类中的静态方法中调用父类的静态方法;
ES6继承的和ES5继承的主要区别, ES5中常用的继承是把子类的原型设置为父类的实例, 子类自然就有了父类的所有方法和属性:
运行下面代码
而在ES6中实现的继承更加精巧, 不会有受到父类的干扰, 这种继承是结合了apply继承和原型继承实现的组合继承:
运行下面代码
属性和
方法;
};
Sub.__proto__ = Sup; //继承Sup静态
属性;
Sub.prototype = Object.create( Sup.prototype,{constructor : { value: Sub,enumerable: false,writable: true,configurable: true }}); //继承原型
属性,并覆写constructor;
用图片可以比较容易看出两者区别, 图示ES5和ES6继承的区别: ;
ES5模拟ES6的继承:
因为有了转码器babel , 我们能通过ES5的代码, 去窥探ES6的继承到底是怎么实现, ES6的继承:
运行下面代码
使用babel转化为ES5以后, 代码变成这样了,我自己加了一点注释, 原谅我放荡不羁爱自由..:
运行下面代码
属性
if (staticProps) defineProperties(Constructor,staticProps);
return Constructor;
};
}();
function _classCallCheck(instance,Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
function _possibleConstructorReturn(self,call) {
if (!self) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return call && (typeof call === "object" || typeof call === "function") ? call : self;
}
//下面是ES6继承使用ES5表达出来的
代码,_inherits实现的是原型的继承和
父类状态
属性的继承:
function _inherits(subClass,superClass) {
if (typeof superClass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function,not " + typeof superClass);
}
//继承
父类的原型,并修正constructor为子类;
subClass.prototype = Object.create(superClass && superClass.prototype,{ constructor: { value: subClass,configurable: true } });
//又给子类这个对象定义__proto__ 为
父类, 这样能够实现静态
属性继承;
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass,superClass) : subClass.__proto__ = superClass;
//最后的如果开发者:new 子类, 实际的状态为: 对象{__proto__:
父类,constuctor:子类}
};
/*
var Sup = function() {};
var Sub = function() {};
_inherits(Sub,Sup);
//这个继承实现的意思; 作为对象的子类继承
父类, 作为构造
函数的话,子类继承
Sub.prototype.__proto__ === Sup.prototype //true
Sub.prototype.constructor === Sub;//true
Sub.__proto__ === Sup;//true
*/
var Person = function () {
function Person(name) {
_classCallCheck(this,Person);
this.name = name;
}
_createClass(Person,[{
key: "say",value: function say() {
console.log("say hi");
return this;
}
}]);
return Person;
}();
;
var SMan = function (_Person) {
_inherits(SMan,_Person);
function SMan(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: function show() {
console.log(this.superPower);
return this;
}
}]);
return SMan;
}(Person);
console.log(new SMan("Clark","pee").show().say().name);
多重继承:
使用mix-in, 实现多重继承, 书写方式为:class Sub extends mix(obj0,obj1,obj2),mix只是一个方法 ,这个方法我们要自己去定义:
运行下面代码