ES6新特性:使用新方法定义javascript的Class
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 = ;
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 = ; 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>
参考:
图示ES5和ES6继承的区别:http://keenwon.com/1524.html
MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
caibaojian:http://caibaojian.com/es6.html
作者: NONO
出处:http://www.cnblogs.com/diligenceday/
QQ:287101329
微信:18101055830
ES6新特性:使用新方法定义javascript的Class的更多相关文章
- Java8新特性系列-默认方法
Java8 Interface Default and Static Methods 原文连接:Java8新特性系列-默认方法 – 微爱博客 在 Java 8 之前,接口只能有公共抽象方法. 如果不强 ...
- JDK1.8新特性——使用新的方式遍历集合
JDK1.8新特性——使用新的方式遍历集合 摘要:本文主要学习了在JDK1.8中新增的遍历集合的方式. 遍历List 方法: default void forEach(Consumer<? su ...
- JDK1.8之后的新特性和新接口
接口的旧特性: 就特性下接口中只有: 常量(必须赋值) 抽象方法abstract(和final static private三个关键字冲突) interface Inter { //int a ; / ...
- C# 7.0 新特性:本地方法
C# 7.0:本地方法 VS 2017 的 C# 7.0 中引入了本地方法,本地方法是一种语法糖,允许我们在方法内定义本地方法.更加类似于函数式语言,但是,本质上还是基于面向对象实现的. 1. 本地方 ...
- 乐字节-Java8新特性-接口默认方法之Stream流(下)
接上一篇:<Java8新特性之stream>,下面继续接着讲Stream 5.流的中间操作 常见的流的中间操作,归为以下三大类:筛选和切片流操作.元素映射操作.元素排序操作: 操作 描述 ...
- 乐字节-Java8新特性-接口默认方法
总概 JAVA8 已经发布很久,而且毫无疑问,java8是自java5(2004年发布)之后的最重要的版本.其中包括语言.编译器.库.工具和JVM等诸多方面的新特性. Java8 新特性列表如下: 接 ...
- 009-jdk1.8版本新特性一-展方法,Lambda表达式,函数式接口、方法引用构造引用
一.JDK1.8 名称:Spider(蜘蛛) 发布日期:2014-03-18 新特性: 1.1.扩展方法[接口的默认方法] Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 defaul ...
- [PHP7.0-PHP7.2]的新特性和新变更
php7发布已经升级到7.2.里面发生了很多的变化.本文整理php7.0至php7.2的新特性和一些变化. 参考资料: http://php.net/manual/zh/migration70.new ...
- 再来看看Java的新特性——其他新特性
关于剩余Java8新特性知识点总结,包含:默认方法.Optional.CompletableFuture.时间相关. 默认方法 默认方法皆在帮助Java新功能可以兼容低版本JDK已开发的程序. 比如说 ...
- HTML5 的新特性以及新标签的浏览器兼容问题
新特性: HTML5 现在已经不是 SGML 的子集,主要是关于图像,位置,存储,多任务等功能的增加. 1) 拖拽释放(Drag and drop) API 2) 语义化更好的内容标签(heade ...
随机推荐
- [Android]官网《UI/Application Exerciser Monkey》中文翻译
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5049041.html 翻译自 Android Develope ...
- Activity详解四 activity四种加载模式
先看效果图: 1概述 Activity启动方式有四种,分别是: standard singleTop singleTask singleInstance 可以根据实际的需求为Activity设置对应的 ...
- # iOS 10 适配 # 适配刷新控件 以MJRefresh 为例
在iOS10中ScrollView 添加了一个refreshControl的东西 - - 不知道水果公司做了什么 导致原有的刷新控件类刷新后frame.y 向下偏移了20 起初以为是水果调整了sta ...
- AndroidStudio配置gradle,让App自动签名
最近开发关于微信一系列功能,发现分享.支付必须要打包签名才能测试,太耽误事了,耗时耗力...在网上扒拉扒拉资料,发现有很多前辈都处理过类似问题,非常感谢大家的分享,参考链接:http://blog.c ...
- IOS网络请求的一些需要记录的info设置
info.plist文件: <key>NSExceptionDomains</key> <dict> <key>appapi.700bike.com&l ...
- 敏捷开发与jira
项目背景 项目是基于一套公司自主研发的平台做企业信息化的项目管理业务,经过两个里程碑的交付,已经在客户现场使用,每次版本都能按期交付,延迟较少,客户满意度也高. 项目开发过程采用的敏捷的方法,用类Sc ...
- Play Framework 完整实现一个APP(三)
1.添加Post类 package models; import java.util.*; import javax.persistence.*; import play.db.jpa.*; @Ent ...
- Xamarin For Visual Studio 3.0.54.0 完整离线破解版(C# 开发Android、IOS工具 吾乐吧软件站分享)
Xamarin For Visual Studio就是原本的Xamarin For Android 以及 Xamarin For iOS,最新版的已经把两个独立的插件合并为一个exe安装包了.为了区分 ...
- winform窗体(二)——控件
一.窗体的事件 每一个窗体都有一个事件,这个窗体加载完成之后执行哪一段代码 位置:1)右键属性→事件→load 双击进入 2)双击窗体任意一个位置进入 删除事件:先将事件页面里面的挂好的事件删除,再删 ...
- VS 中關於附加到進程中調試 的問題。
在使用Vs 2012 時,項目發佈到Local IIS 中,如果在調試某個頁面中時,都要F5--> Login --> Debug 很繁瑣,下列有一種較快捷的方式,能夠更快的調試代碼. 1 ...