JavaScript ES6的新特性使用新方法定義Class
ES6(ECMAScript 6)是即將到來的新版本JavaScript語言的標(biāo)準(zhǔn),代號(hào)harmony(和諧之意,顯然沒有跟上我國(guó)的步伐,我們已經(jīng)進(jìn)入中國(guó)夢(mèng)版本了)。上一次標(biāo)準(zhǔn)的制訂還是2009年出臺(tái)的ES5。目前ES6的標(biāo)準(zhǔn)化工作正在進(jìn)行中,預(yù)計(jì)會(huì)在14年12月份放出正式敲定的版本。但大部分標(biāo)準(zhǔn)已經(jīng)就緒,且各瀏覽器對(duì)ES6的支持也正在實(shí)現(xiàn)中。
ES6中定義類的方式, 就是ES3和ES5中定義類的語法糖,雖然也有些區(qū)別,但是整體定義類的方式更加簡(jiǎn)潔,類的繼承更加方便, 如果想對(duì)ES6中的繼承更加熟悉, 最好了解ES5中原型繼承的方式, 博客園中說JS繼承的文章很多, 想要深入了解的同學(xué)自己去搜;
定義一個(gè)class:
每一個(gè)使用class方式定義的類默認(rèn)都有一個(gè)constructor函數(shù), 這個(gè)函數(shù)是構(gòu)造函數(shù)的主函數(shù), 該函數(shù)體內(nèi)部的this指向生成的實(shí)例, say() {}為原型上的方法, 我們定義一個(gè)簡(jiǎn)單的類 :
運(yùn)行下面代碼
"use strict"; class Person { constructor(name) { this.name = name; } say () { console.log("say hi"); } }; new Person().say(); //控制臺(tái)會(huì)輸出say hi
注意: ES6中聲明的類不存在函數(shù)聲明提前的問題, 類必須先聲明再使用,否則會(huì)出現(xiàn)異常 , 我們只是把上面Demo中的代碼位置一改, 立馬報(bào)錯(cuò), (如果用ES5中的思維去理解的話, 聲明的類沒有聲明提前, 有關(guān)聲明提前的知識(shí)點(diǎn), 通過class 類名{} 聲明的類,就是var 類名 = function(){});
運(yùn)行下面代碼
"use strict"; new Person().say(); class Person { constructor(name) { this.name = name; } say () { console.log("say hi"); } };
定義函數(shù)的靜態(tài)方法:
如果定義函數(shù)的時(shí)候, 大括號(hào)內(nèi)部, 函數(shù)名前聲明了static, 那么這個(gè)函數(shù)就為靜態(tài)函數(shù), 就為靜態(tài)方法, 和原型沒啥關(guān)系:
運(yùn)行下面代碼
"use strict"; class Person { constructor(name) { this.name = name; } static say () { console.log("say hi"); } }; Person.say();
定義原型方法:
定義原型方法,直接這樣聲明: 函數(shù)名 () {} 即可, 小括號(hào)內(nèi)部為參數(shù)列表, 大括號(hào)內(nèi)部為代碼塊, ES5中要定義原型方法是通過: 構(gòu)造函數(shù).prototype.原型方法名() {} , 這種書寫形式很繁瑣, 使用ES6定義原型的方式有點(diǎn)像java和C#了, 這些都是比較高級(jí)語言的特征:
運(yùn)行下面代碼
"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
靜態(tài)屬性和原型屬性:
只能在類定義完畢以后再定義靜態(tài)屬性,有點(diǎn)坑爹, 語言作者實(shí)現(xiàn)這種方式可能是為了避免代碼的混亂, 所有的靜態(tài)屬性在同一個(gè)地方定義, 代碼回更加規(guī)范?
運(yùn)行下面代碼
"use strict"; class Person { constructor(name) { this.name = name; } }; Person.hands = 2; console.log(Person.hands);
原型上面也不能定義屬性了, 我們只能在原型上定義set和get, 取值和設(shè)值器, 要注意取值器和設(shè)值器是在原型上....:
運(yùn)行下面代碼
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內(nèi)部即可, 如果是繼承的話, 子類也會(huì)繼承父類的這個(gè)屬性:
運(yùn)行下面代碼
class Person { constructor() { this.name = "default"; } } class Man extends Person{ constructor() { super(); } } console.log( new Man().name );
類的繼承extends:
ES5已經(jīng)有繼承, 但是這種繼承經(jīng)常繞來繞去的, ES6的繼承也只是基于原型繼承的封裝(語法糖), 雖然的確簡(jiǎn)潔了不少, 還是java的繼承比較好學(xué)啊, 下面Demo的例子中的SMan是超人的意思,別想歪了;
運(yùn)行下面代碼
"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
如果要使用繼承的話, 在子類中必須執(zhí)行super()調(diào)用父類, 否者編譯器會(huì)拋錯(cuò), 在子類中的super有三種作用, 第一是作為構(gòu)造函數(shù)直接調(diào)用,第二種是作為父類實(shí)例, 第三種是在子類中的靜態(tài)方法中調(diào)用父類的靜態(tài)方法;
ES6繼承的和ES5繼承的主要區(qū)別, ES5中常用的繼承是把子類的原型設(shè)置為父類的實(shí)例, 子類自然就有了父類的所有方法和屬性:
運(yùn)行下面代碼
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中實(shí)現(xiàn)的繼承更加精巧, 不會(huì)有受到父類的干擾, 這種繼承是結(jié)合了apply繼承和原型繼承實(shí)現(xiàn)的組合繼承:
運(yùn)行下面代碼
var Sup = function() { this.sub = true; }; var Sub = function() { this.sup = true; Sup.apply(this); //繼承this的屬性和方法; }; Sub.__proto__ = Sup; //繼承Sup靜態(tài)屬性; Sub.prototype = Object.create( Sup.prototype, {constructor : { value: Sub, enumerable: false, writable: true, configurable: true }}); //繼承原型屬性,并覆寫constructor;
用圖片可以比較容易看出兩者區(qū)別, 圖示ES5和ES6繼承的區(qū)別:http://keenwon.com/1524.html ;
ES5模擬ES6的繼承:
因?yàn)橛辛宿D(zhuǎn)碼器babel , 我們能通過ES5的代碼, 去窺探ES6的繼承到底是怎么實(shí)現(xiàn), ES6的繼承:
運(yùn)行下面代碼
"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轉(zhuǎn)化為ES5以后, 代碼變成這樣了, 我自己加了一點(diǎn)注釋, 原諒我放蕩不羈愛自由..:
運(yùn)行下面代碼
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) { //復(fù)制原型 if (protoProps) defineProperties(Constructor.prototype, protoProps); //復(fù)制屬性 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表達(dá)出來的代碼,_inherits實(shí)現(xiàn)的是原型的繼承和父類狀態(tài)屬性的繼承: 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 } }); //又給子類這個(gè)對(duì)象定義__proto__ 為父類, 這樣能夠?qū)崿F(xiàn)靜態(tài)屬性繼承; if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; //最后的如果開發(fā)者:new 子類, 實(shí)際的狀態(tài)為: 對(duì)象{__proto__:父類,constuctor:子類} }; /* var Sup = function() {}; var Sub = function() {}; _inherits(Sub, Sup); //這個(gè)繼承實(shí)現(xiàn)的意思; 作為對(duì)象的子類繼承父類, 作為構(gòu)造函數(shù)的話,子類繼承 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) { //此時(shí)的this.__proto__已經(jīng)指向 構(gòu)造函數(shù)的prototyp了 _classCallCheck(this, SMan); //這句話相當(dāng)于是ES6中的super(), 把父類的屬性通過call, 執(zhí)行繼承; var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(SMan).call(this, name)); _this.superPower = power; //動(dòng)態(tài)返回_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, 實(shí)現(xiàn)多重繼承, 書寫方式為:class Sub extends mix(obj0, obj1, obj2) , mix只是一個(gè)方法 ,這個(gè)方法我們要自己去定義:
運(yùn)行下面代碼
<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(); //實(shí)際上它們不存在繼承關(guān)系, 只是把屬性復(fù)制到子類上; console.log(sm instanceof Man); console.log(sm instanceof Woman); </script> </body> </html>
以上所述是小編給大家介紹的JavaScript ES6的新特性使用新方法定義Class的相關(guān)知識(shí),希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- ES6中非常實(shí)用的新特性介紹
- JavaScript中的Reflect對(duì)象詳解(ES6新特性)
- 深入淺出ES6新特性之函數(shù)默認(rèn)參數(shù)和箭頭函數(shù)
- 簡(jiǎn)單談?wù)凟S6的六個(gè)小特性
- ES6新特性之Symbol類型用法分析
- ES6(ECMAScript 6)新特性之模板字符串用法分析
- ES6新特性之變量和字符串用法示例
- ES6新特性之模塊Module用法詳解
- ES6新特性之字符串的擴(kuò)展實(shí)例分析
- ES6新特性二:Iterator(遍歷器)和for-of循環(huán)詳解
- ES6新特性六:promise對(duì)象實(shí)例詳解
- ES6新特性七:數(shù)組的擴(kuò)充詳解
- ES6新特性八:async函數(shù)用法實(shí)例詳解
- ES6新特性之類(Class)和繼承(Extends)相關(guān)概念與用法分析
- 讓微信小程序支持ES6中Promise特性的方法詳解
- ES6新特性:使用export和import實(shí)現(xiàn)模塊化詳解
- es6新特性之 class 基本用法解析
- ES6 13個(gè)新特性總結(jié)
相關(guān)文章
通過繼承IHttpHandle實(shí)現(xiàn)JS插件的組織與管理
最近,項(xiàng)目中的用到的Js插件越來越多,有的是用原生javascript寫的,有的是調(diào)用的jquery插件,頁面上Js和Css文件的引用也越來越混亂,而且Js文件之間還有引用先后的依賴關(guān)系2010-07-07JavaScript中關(guān)于遞歸與回溯的實(shí)例詳解
這篇文章主要將為大家介紹一下JavaScript中遞歸與回溯的原理及使用,文中通過一些例題進(jìn)行了詳細(xì)介紹,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-07-07swiper 解決動(dòng)態(tài)加載數(shù)據(jù)滑動(dòng)失效的問題
下面小編就為大家分享一篇swiper 解決動(dòng)態(tài)加載數(shù)據(jù)滑動(dòng)失效的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-02-02使用KrpanoToolJS在瀏覽器切圖的實(shí)例詳解
這篇文章主要介紹了使用KrpanoToolJS在瀏覽器切圖的實(shí)例詳解,大概是需要在瀏覽器中將全景圖轉(zhuǎn)為立方體圖、多層級(jí)瓦片圖,通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-10-10JavaScript事件學(xué)習(xí)小結(jié)(一)事件流
這篇文章主要介紹了JavaScript事件學(xué)習(xí)小結(jié)(一)事件流的相關(guān)資料,需要的朋友可以參考下2016-06-06javascript的trim,ltrim,rtrim自定義函數(shù)
今天用到j(luò)avascript去掉一個(gè)文本框中字符串兩端的空格,開始還以為有trim,ltrim,rtrim函數(shù)(asp中有這三個(gè)函數(shù),弄混了),結(jié)果找半天,沒有找到。最后找到用正則實(shí)現(xiàn)這樣功能的自定義函數(shù)。2008-09-09