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 相关文章推荐
阻止子元素继承父元素事件具体思路及实现
May 02 Javascript
使用JavaScript实现旋转的彩圈特效
Jun 23 Javascript
安装使用Mongoose配合Node.js操作MongoDB的基础教程
Mar 01 Javascript
node.js cookie-parser 中间件介绍
Jun 06 Javascript
JS封装通过className获取元素的函数示例
Dec 20 Javascript
JavaScript的for循环中嵌套一个点击事件的问题解决
Mar 03 Javascript
ThinkPHP+jquery实现“加载更多”功能代码
Mar 11 Javascript
angularjs中$http异步上传Excel文件方法
Feb 23 Javascript
解决vue select当前value没有更新到vue对象属性的问题
Aug 30 Javascript
vue项目前端埋点的实现
Mar 06 Javascript
bootstrap中的导航条实例代码详解
May 20 Javascript
Javascript基于OOP实实现探测器功能代码实例
Aug 26 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实现文件安全下载
2006/10/09 PHP
JoshChen_php新手进阶高手不可或缺的规范介绍
2013/08/16 PHP
TP5框架页面跳转样式操作示例
2020/04/05 PHP
静态的动态续篇之来点XML
2006/08/15 Javascript
Javascript算符的优先级介绍
2013/03/20 Javascript
node.js中watch机制详解
2014/11/17 Javascript
jQuery Ajax()方法使用指南
2014/11/19 Javascript
JS动态插入并立即执行回调函数的方法
2016/04/21 Javascript
jquery attr()设置和获取属性值实例教程
2016/09/25 Javascript
JS实现点击网页判断是否安装app并打开否则跳转app store
2016/11/18 Javascript
详解vue-cli中的ESlint配置文件eslintrc.js
2017/09/25 Javascript
jQuery实现切换隐藏与显示同时切换图标功能
2017/10/29 jQuery
JavaScript比较同一天的时间大小实例代码
2018/02/09 Javascript
解决easyui日期时间框ie的兼容的问题
2018/03/01 Javascript
详解react内联样式使用webpack将px转rem
2018/09/13 Javascript
JavaScript检查数据中是否存在相同的元素(两种方法)
2018/10/07 Javascript
使用webpack打包后的vue项目如何正确运行(express)
2018/10/26 Javascript
jQuery移动端跑马灯抽奖特效升级版(抽奖概率固定)实现方法
2019/01/18 jQuery
[02:49]DAC2018决赛日TOP5 LGD开启黑暗之门绝杀VP
2018/04/08 DOTA
Python的迭代器和生成器使用实例
2015/01/14 Python
python中map、any、all函数用法分析
2015/04/21 Python
在Python中使用判断语句和循环的教程
2015/04/25 Python
在Python中使用HTMLParser解析HTML的教程
2015/04/29 Python
python通过定义一个类实例作为ftp回调方法
2015/05/04 Python
Python排序搜索基本算法之归并排序实例分析
2017/12/08 Python
Numpy中矩阵matrix读取一列的方法及数组和矩阵的相互转换实例
2018/07/02 Python
解决Shell执行python文件,传参空格引起的问题
2018/10/30 Python
Python 2/3下处理cjk编码的zip文件的方法
2019/04/26 Python
Python3如何在服务器打印资产信息
2020/08/27 Python
使用phonegap检测网络状态的方法
2017/03/30 HTML / CSS
合作协议书模板2014
2014/09/26 职场文书
政风行风整改方案
2014/10/25 职场文书
防暑降温通知书
2015/04/27 职场文书
先进基层党组织主要事迹材料
2015/11/03 职场文书
MYSQL 表的全面总结
2021/11/11 MySQL
mysql查看表结构的三种方法总结
2022/07/07 MySQL