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 相关文章推荐
CSS和JS标签style属性对照表(方便js开发的朋友)
Nov 11 Javascript
打印json对象的内容及JSON.stringify函数应用
Mar 29 Javascript
js用正则表达式来验证表单(比较齐全的资源)
Nov 17 Javascript
深入理解关于javascript中apply()和call()方法的区别
Apr 12 Javascript
详谈JS中实现种子随机数及作用
Jul 19 Javascript
实例解析jQuery中如何取消后续执行内容
Dec 01 Javascript
javascript事件的绑定基础实例讲解(34)
Feb 14 Javascript
vue2.0 与 bootstrap datetimepicker的结合使用实例
May 22 Javascript
jQuery 实现双击编辑表格功能
Jun 19 jQuery
微信小程序自定义带价格显示日历效果
Dec 29 Javascript
详解vue使用插槽分发内容slot的用法
Mar 28 Javascript
js实现轮播图特效
May 28 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入门的学习方法
2007/01/02 PHP
php批量缩放图片的代码[ini参数控制]
2011/02/11 PHP
ThinkPHP利用PHPMailer实现邮件发送实现代码
2013/09/26 PHP
php mail to 配置详解
2014/01/16 PHP
php实现生成验证码实例分享
2016/04/10 PHP
验证坐标在某坐标区域内php代码
2016/10/08 PHP
php修改数组键名的方法示例
2017/04/15 PHP
php数值转换时间及时间转换数值用法示例
2017/05/18 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
Nigma vs Alliance BO5 第三场2.14
2021/03/10 DOTA
jquery实现兼容浏览器的图片上传本地预览功能
2013/10/14 Javascript
按下回车键指向下一个位置的一个函数代码
2014/03/10 Javascript
用jquery写的菜单从左往右滑动出现
2014/04/11 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
jQuery源码分析之jQuery中的循环技巧详解
2014/09/06 Javascript
Vue.js基础知识汇总
2016/04/27 Javascript
noty ? jQuery通知插件全面解析
2016/05/18 Javascript
js改变style样式和css样式的简单实例
2016/06/28 Javascript
angularjs ocLazyLoad分步加载js文件实例
2017/01/17 Javascript
async/await与promise(nodejs中的异步操作问题)
2017/03/03 NodeJs
VueJs组件prop验证简单介绍
2017/09/12 Javascript
javascript实现切割轮播效果
2019/11/28 Javascript
原生javascript的ajax请求及后台PHP响应操作示例
2020/02/24 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
python中wx将图标显示在右下角的脚本代码
2013/03/08 Python
Flask实现图片的上传、下载及展示示例代码
2018/08/03 Python
python中二分查找法的实现方法
2020/12/06 Python
Python tkinter之Bind(绑定事件)的使用示例
2021/02/05 Python
使用jTopo给Html5 Canva中绘制的元素添加鼠标事件
2014/05/15 HTML / CSS
Myprotein比利时官方网站:欧洲第一运动营养品牌
2020/10/04 全球购物
DOM和JQuery对象有什么区别
2016/11/11 面试题
运动会入场解说词
2014/02/07 职场文书
畜牧兽医本科生的自我评价
2014/03/03 职场文书
法人授权委托书
2014/04/03 职场文书
2015年推普周活动总结
2015/03/27 职场文书
python 中yaml文件用法大全
2021/07/04 Python