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 相关文章推荐
Jquery 绑定时间实现代码
May 03 Javascript
图片延迟加载的实现代码(模仿懒惰)
Mar 29 Javascript
js实现广告漂浮效果的小例子
Jul 02 Javascript
绑定回车enter事件代码
May 18 Javascript
JavaScript中的style.cssText使用教程
Nov 06 Javascript
ztree获取选中节点时不能进入可视区域出现BUG如何解决
Dec 03 Javascript
JS实现的多张图片轮流播放幻灯片效果
Jul 22 Javascript
jQuery利用sort对DOM元素进行排序操作
Nov 07 Javascript
JS中位置与大小的获取方法
Nov 22 Javascript
EsLint入门学习教程
Feb 17 Javascript
深入学习 JavaScript中的函数调用
Mar 23 Javascript
详解ionic本地相册、拍照、裁剪、上传(单图完全版)
Oct 10 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
php下实现一个阿拉伯数字转中文数字的函数
2008/07/10 PHP
PHP中使用foreach和引用导致程序BUG的问题介绍
2012/09/05 PHP
PHP与Ajax相结合实现登录验证小Demo
2016/03/16 PHP
微信自定义分享php代码分析
2016/11/24 PHP
htm调用JS代码
2007/03/15 Javascript
js中查找最近的共有祖先元素的实现代码
2010/12/30 Javascript
用js实现判断当前网址的来路如果不是指定的来路就跳转到指定页面
2011/05/02 Javascript
offsetHeight在OnLoad中获取为0的现象
2013/07/22 Javascript
JavaScript数组深拷贝和浅拷贝的两种方法
2014/04/16 Javascript
JS中attr和prop属性的区别以及优先选择示例介绍
2014/06/30 Javascript
js读取csv文件并使用json显示出来
2015/01/09 Javascript
使用angular写一个hello world
2015/01/23 Javascript
js实现基于正则表达式的轻量提示插件
2015/08/29 Javascript
JS实现的简单鼠标跟随DiV层效果完整实例
2015/10/31 Javascript
js+css简单实现网页换肤效果
2015/12/29 Javascript
jquery遍历table的tr获取td的值实现方法
2016/05/19 Javascript
Vue实现简易翻页效果源码分享
2018/11/08 Javascript
[04:12]第二届DOTA2亚洲邀请赛选手传记-Newbee.Sccc
2017/04/03 DOTA
安装Python的web.py框架并从hello world开始编程
2015/04/25 Python
python字符串连接方法分析
2016/04/12 Python
python 中split 和 strip的实例详解
2017/07/12 Python
python 矩阵增加一行或一列的实例
2018/04/04 Python
Python自动发送邮件的方法实例总结
2018/12/08 Python
Django 1.10以上版本 url 配置注意事项详解
2019/08/05 Python
Python基础教程(一)——Windows搭建开发Python开发环境
2020/07/20 Python
美国购车网站:TrueCar
2016/10/19 全球购物
世界顶级俱乐部的官方球衣和套装:Subside Sports
2018/04/22 全球购物
技术学校毕业生求职信分享
2013/12/02 职场文书
营销总经理岗位职责
2014/02/02 职场文书
工作求职自荐信
2014/06/13 职场文书
民主生活会对照检查材料思想汇报
2014/09/27 职场文书
代办出身证明书
2014/10/21 职场文书
2015年七一建党节活动方案
2015/05/05 职场文书
董事长助理工作总结2015
2015/07/23 职场文书
Python数据类型最全知识总结
2021/05/31 Python
解决Mysql的left join无效及使用的注意事项说明
2021/07/01 MySQL