JavaScript ES6的新特性使用新方法定义Class


Posted in Javascript onJune 28, 2016

ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony(和谐之意,显然没有跟上我国的步伐,我们已经进入中国梦版本了)。上一次标准的制订还是2009年出台的ES5。目前ES6的标准化工作正在进行中,预计会在14年12月份放出正式敲定的版本。但大部分标准已经就绪,且各浏览器对ES6的支持也正在实现中。

ES6中定义类的方式, 就是ES3和ES5中定义类的语法糖,虽然也有些区别,但是整体定义类的方式更加简洁,类的继承更加方便, 如果想对ES6中的继承更加熟悉, 最好了解ES5中原型继承的方式, 博客园中说JS继承的文章很多, 想要深入了解的同学自己去搜;

定义一个class:

 

每一个使用class方式定义的类默认都有一个constructor函数, 这个函数是构造函数的主函数, 该函数体内部的this指向生成的实例, say() {}为原型上的方法, 我们定义一个简单的类 : 

运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
 say () {
  console.log("say hi");
 }
};
new Person().say(); //控制台会输出say hi

 

注意: ES6中声明的类不存在函数声明提前的问题, 类必须先声明再使用,否则会出现异常 , 我们只是把上面Demo中的代码位置一改, 立马报错, (如果用ES5中的思维去理解的话, 声明的类没有声明提前, 有关声明提前的知识点, 通过class 类名{} 声明的类,就是var 类名 = function(){});

 运行下面代码

"use strict";
new Person().say();
class Person {
 constructor(name) {
  this.name = name;
 }
 say () {
  console.log("say hi");
 }
};

定义函数的静态方法:

如果定义函数的时候, 大括号内部, 函数名前声明了static, 那么这个函数就为静态函数, 就为静态方法, 和原型没啥关系:

运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
 static say () {
  console.log("say hi");
 }
};
Person.say();

  定义原型方法:

定义原型方法,直接这样声明: 函数名 () {} 即可, 小括号内部为参数列表, 大括号内部为代码块,  ES5中要定义原型方法是通过: 构造函数.prototype.原型方法名() {} , 这种书写形式很繁琐, 使用ES6定义原型的方式有点像java和C#了, 这些都是比较高级语言的特征:

 运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
 say () {
  console.log("say hi");
 }
 sing () {
  console.log("lalalalala");
 }
};
new Person().say(); //输出 :say hi
new Person().sing(); //输出 :lalalalala

静态属性和原型属性:

只能在类定义完毕以后再定义静态属性,有点坑爹, 语言作者实现这种方式可能是为了避免代码的混乱, 所有的静态属性在同一个地方定义, 代码回更加规范?

运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
};
Person.hands = 2;
console.log(Person.hands);

原型上面也不能定义属性了, 我们只能在原型上定义set和get, 取值和设值器, 要注意取值器和设值器是在原型上....:

运行下面代码

class Person {
 constructor(_name) {
  this._name = _name;
 }
 get name() {
  return this._name;
 }
 set name(_name) {
  this._name = _name;
 }
}
var p = new Person();
p.name = "heheda";
console.log(p.name); //输出:heheda
console.log(p._name); //输出:heheda

如果要定义原型属性的话, 直接把属性定义在constructor内部即可, 如果是继承的话, 子类也会继承父类的这个属性:

运行下面代码

class Person {
 constructor() {
  this.name = "default";
 }
}
class Man extends Person{
 constructor() {
  super();
 }
}
console.log( new Man().name );

类的继承extends:

ES5已经有继承, 但是这种继承经常绕来绕去的, ES6的继承也只是基于原型继承的封装(语法糖), 虽然的确简洁了不少, 还是java的继承比较好学啊, 下面Demo的例子中的SMan是超人的意思,别想歪了;

运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
 say () {
  console.log("say hi");
  return this;
 }
};
class SMan extends Person {
 constructor (name, power) {
  super(name);
  this.superPower = power;
 }
 show () {
  console.log(this.superPower);
  return this;
 }
}
console.log( new SMan("Clark", "pee").show().say().name ); //输出: pee say hi Clark

如果要使用继承的话, 在子类中必须执行super()调用父类, 否者编译器会抛错,  在子类中的super有三种作用, 第一是作为构造函数直接调用,第二种是作为父类实例, 第三种是在子类中的静态方法中调用父类的静态方法;

ES6继承的和ES5继承的主要区别, ES5中常用的继承是把子类的原型设置为父类的实例, 子类自然就有了父类的所有方法和属性:

运行下面代码

var Sup = function() {
 this.sub = true;
};
Sup.prototype.protoSup = {sup:"sup"};
var Sub = function() {
 this.sub = true;
};
Sub.prototype = new Sup(); //继承原型;
Sub.prototype.constructor = Sub; //修正constructor;

而在ES6中实现的继承更加精巧, 不会有受到父类的干扰, 这种继承是结合了apply继承和原型继承实现的组合继承:

运行下面代码

var Sup = function() {
 this.sub = true;
};
var Sub = 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的继承:

运行下面代码

"use strict";
class Person {
 constructor(name) {
  this.name = name;
 }
 say () {
  console.log("say hi");
  return this;
 }
};
class SMan extends Person {
 constructor (name, power) {
  super(name);
  this.superPower = power;
 }
 show () {
  console.log(this.superPower);
  return this;
 }
}
console.log( new SMan("Clark", "pee").show().say().name );

使用babel转化为ES5以后, 代码变成这样了, 我自己加了一点注释, 原谅我放荡不羁爱自由..:

运行下面代码

var _createClass = function () {
  function defineProperties(target, props) {
   for (var i = 0; i < props.length; i++) {
    var descriptor = props[i];
    descriptor.enumerable = descriptor.enumerable || false;
    descriptor.configurable = true;
    if ("value" in descriptor) descriptor.writable = true;
    Object.defineProperty(target, descriptor.key, descriptor);
   }
  }
  return function (Constructor, protoProps, staticProps) {
   //复制原型
   if (protoProps) defineProperties(Constructor.prototype, protoProps);
   //复制属性
   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, enumerable: false, writable: true, 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只是一个方法 ,这个方法我们要自己去定义:

运行下面代码

<html>
<head>
 <meta charset="utf-8">
</head>
<body>
<script>
 "use strict";
 function mix(...mixins) {
  class Mix {}
  for (let mixin of mixins) {
   copyProperties(Mix, mixin);
   copyProperties(Mix.prototype, mixin.prototype);
  }
  return Mix;
 }
 function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
   if ( key !== "constructor"
     && key !== "prototype"
     && key !== "name"
     ) {
    let desc = Object.getOwnPropertyDescriptor(source, key);
    Object.defineProperty(target, key, desc);
   }
  }
 }
 class Man{
  work () {
   console.log("working");
  }
 }
 class Woman{
  say () {
   console.log("saying");
  }
 }
 class SuperMan extends mix(Man, Woman) {
  constructor () {
   super();
  }
 }
 var sm = new SuperMan();
 sm.work();
 sm.say();
 //实际上它们不存在继承关系, 只是把属性复制到子类上;
 console.log(sm instanceof Man);
 console.log(sm instanceof Woman);
</script>
</body>
</html>

以上所述是小编给大家介绍的JavaScript ES6的新特性使用新方法定义Class的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
(转载)JavaScript中匿名函数,函数直接量和闭包
May 08 Javascript
js监听滚动条滚动事件使得某个标签内容始终位于同一位置
Jan 24 Javascript
jQuery中empty()方法用法实例
Jan 16 Javascript
基于jQuery实现响应式圆形图片轮播特效
Nov 25 Javascript
通过点击jqgrid表格弹出需要的表格数据
Dec 02 Javascript
ArtEditor富文本编辑器增加表单提交功能
Apr 18 Javascript
js多个物体运动功能实例分析
Dec 20 Javascript
jQuery插件zTree实现的基本树与节点获取操作示例
Mar 08 Javascript
详解vue-router2.0动态路由获取参数
Jun 14 Javascript
详解vue2.0 资源文件assets和static的区别
Nov 27 Javascript
vue 弹窗时 监听手机返回键关闭弹窗功能(页面不跳转)
May 10 Javascript
vue自定义表单生成器form-create使用详解
Jul 19 Javascript
javascript 常用验证函数总结
Jun 28 #Javascript
JS传递对象数组为参数给后端,后端获取的实例代码
Jun 28 #Javascript
JavaScript ES5标准中新增的Array方法
Jun 28 #Javascript
jQuery 中ajax异步调用的四种方式
Jun 28 #Javascript
jQuery 调用WebService 实例讲解
Jun 28 #Javascript
关于在Servelet中如何获取当前时间的操作方法
Jun 28 #Javascript
关于JS 预解释的相关理解
Jun 28 #Javascript
You might like
福利彩票幸运号码自动生成器
2006/10/09 PHP
php中判断一个字符串包含另一个字符串的方法
2007/03/19 PHP
php实例分享之mysql数据备份
2014/05/19 PHP
php面向对象中static静态属性和静态方法的调用
2015/02/08 PHP
PHP面向对象继承用法详解(优化与减少代码重复)
2016/12/02 PHP
效率高的Javscript字符串替换函数的benchmark
2008/08/02 Javascript
很可爱的输入框
2008/08/03 Javascript
利用javascript/jquery对上传文件格式过滤的方法
2009/07/25 Javascript
Javascript 获取滚动条位置等信息的函数
2009/09/08 Javascript
jQuery Deferred和Promise创建响应式应用程序详细介绍
2013/03/05 Javascript
JQuery实现用户名无刷新验证的小例子
2013/03/22 Javascript
ajax请求get与post的区别总结
2013/11/04 Javascript
JavaScript将一个数组插入到另一个数组的方法
2015/03/19 Javascript
JS两个数组比较,删除重复值的巧妙方法(推荐)
2016/06/03 Javascript
jquery引入外部CDN 加载失败则引入本地jq库
2018/05/23 jQuery
微信小程序异步API为Promise简化异步编程的操作方法
2018/08/14 Javascript
如何在Angular应用中创建包含组件方法示例
2019/03/23 Javascript
Python入门篇之条件、循环
2014/10/17 Python
Python实现删除Android工程中的冗余字符串
2015/01/19 Python
Python3简单实例计算同花的概率代码
2017/12/06 Python
在Python中使用gRPC的方法示例
2018/08/08 Python
Python3中bytes类型转换为str类型
2018/09/27 Python
在Python 不同级目录之间模块的调用方法
2019/01/19 Python
雷曼兄弟的五金店:Lehman’s Hardware Store
2019/04/10 全球购物
Why we need EJB
2016/10/20 面试题
毕业生多媒体设计求职信
2013/10/12 职场文书
应届生人事助理求职信
2013/11/09 职场文书
大学生职业生涯规划范文
2014/01/22 职场文书
新闻编辑专业自荐信
2014/07/02 职场文书
大专毕业生自我鉴定范文(2篇)
2014/09/27 职场文书
护理实习生带教计划
2015/01/16 职场文书
单位领导婚礼致辞
2015/07/28 职场文书
老乡会致辞
2015/07/28 职场文书
CSS实现漂亮的时钟动画效果的实例代码
2021/03/30 HTML / CSS
python数据可视化使用pyfinance分析证券收益示例详解
2021/11/20 Python
MyBatis核心源码深度剖析SQL语句执行过程
2022/05/20 Java/Android