摘要:是基于原型鏈繼承的,但是其詭異的寫法可能讓好多初學(xué)者望而卻步。在我們有和,很容易切換上下文,將各種互不相干糅合,達(dá)到的目的。最近在讀這本書,有一些好的內(nèi)容,正好可以跟大家分享,但并不是全部,有興趣的同學(xué)也可以自己讀一下,請支持正版。
剛開始,代碼只是代碼而已。當(dāng)代碼多了,我們發(fā)明了函數(shù),以便代碼可以重用。到后來,我們的函數(shù)也越來越多,所以我們又發(fā)明了別的一些編程概念。但是當(dāng)我們沉迷于這些新概念的同時(shí),我們可能就錯(cuò)過了一些近在眼前的美麗事物……
類繼承類概念主要存在于面向?qū)ο缶幊讨械?,可能大家上學(xué)時(shí)都學(xué)過,比如Java、C#、Objective-C等面向?qū)ο笳Z言。每個(gè)實(shí)體都需要先要有一個(gè)類,這個(gè)類對于我們來說是比較抽象的(不是說abstract class哦),然后子類還可以繼承父類。
這感覺似乎有點(diǎn)亞里士多德形而上學(xué)和分類法的味道,但簡單來說這就是面向?qū)ο蟮幕A(chǔ),在寫出實(shí)際代碼之前,你得先寫出一些類、接口,然后類繼承類、類實(shí)現(xiàn)接口……
實(shí)際上我們?nèi)祟惒⒉皇欠浅I瞄L分類,打個(gè)比方,一個(gè)按鈕(Button),它應(yīng)該是一個(gè)矩形(Rectangle),還是一個(gè)控件(Control)呢?我們可以讓Button繼承Rectangle,讓Rectangle繼承Control……等等,是不是有什么不對?
所以,面向?qū)ο蟮母拍羁赡軙陧?xiàng)目剛開始時(shí)就把你壓垮,但這并不是說面向?qū)ο缶筒缓茫皇怯袝r(shí)候并不適合你的項(xiàng)目。
原型鏈繼承可能大家都知道,JavaScript是不支持class關(guān)鍵字的,因?yàn)镴avaScript本身就不作為一個(gè)面向?qū)ο笳Z言來設(shè)計(jì),但并不妨礙大家想出各種招來實(shí)現(xiàn)class。
JavaScript是基于原型鏈(Prototype)繼承的,但是其詭異的寫法可能讓好多初學(xué)者望而卻步。
function Circle() { this.radius = 7; } Circle.prototype = { area: function () { return Math.PI * this.radius * this.radius; }, grow: function () { this.radius++; }, shrink: function () { this.radius--; } };
在ES5之后,我們有了Object.create方法,好理解了一些。
var circle = Object.create({ area: function () { return Math.PI * this.radius * this.radius; }, grow: function () { this.radius++; }, shrink: function () { this.radius--; } }, { radius: { writable: true, configurable: true, value: 7 } });
只是第二參數(shù)用起來有點(diǎn)復(fù)雜,其實(shí)就是跟Object.defineProperties()的參數(shù)一樣,但是我們現(xiàn)在又有了ES6呀:
class Cicle { constructor() { this.radius = 7; } area() { return Math.PI * this.radius * this.radius; } grow() { this.radius++; } shrink() { this.radius--; } }
這都是一些使用JavaScript實(shí)現(xiàn)class的例子,實(shí)際上,JavaScript還可以有另外一種重用代碼的方式——Mixins。
Mixins這就是我們今天的主題,近在眼前的美麗事物,但可不是什么新概念,用過Ruby或Python的同學(xué),可能有所耳目,Mixins的字面意思就是把東西摻合在一起。
在JavaScript我們有call和apply,很容易切換上下文,將各種互不相干糅合,達(dá)到Mixins的目的。
假設(shè)我們要做一個(gè)圓形按鈕(RoundButton),它有兩個(gè)特性:
是圓的
可點(diǎn)擊
我們可以把這兩個(gè)特性分別寫做2個(gè)函數(shù):
// 是圓的 var withCircle = function () { this.area = function () { return Math.PI * this.radius * this.radius; }; this.grow = function () { this.radius++; }; this.shrink = function () { this.radius--; } } // 可點(diǎn)擊 var withClickable = function () { this.hover = function () { console.log("hovering"); }; this.press = function () { console.log("button pressed"); }; this.release = function () { console.log("button released"); }; this.fire = function () { this.action.fire(); }; }
這是我們的圓形按鈕:
var RoundButton = function(radius, label, action) { this.radius = radius; this.label = label; this.action = action; };
現(xiàn)在我們要讓給這個(gè)圓形按鈕附上那兩個(gè)特性:
withCircle.call(RoundButton.prototype); withClickable.call(RoundButton.prototype); var button = new RoundButton(4, "yes!", function() { return "you said yes!" }); button1.fire(); // 輸出 "you said yes!"
這樣寫,是不是瞬間顯得既簡潔又自然?讓人一眼看懂代碼在做什么。
當(dāng)然這些附加特性的函數(shù)用的多了,也就創(chuàng)建了許多函數(shù),這里可以簡單的用一個(gè)立即執(zhí)行函數(shù)(Immediately Invoked Function Expression)的閉包來對其進(jìn)行優(yōu)化一下,以withCircle為例:
var withCircle = (function () { function area() { return Math.PI * this.radius * this.radius; } function grow() { this.radius++; } function shrink() { this.radius--; } return function () { this.area = area; this.grow = grow; this.shrink = shrink; }; })();
這樣就不需要每次使用都新建函數(shù)了,從而節(jié)省更多的資源。
Advice有時(shí)候,你無法確保某些函數(shù)可能會覆蓋原有的功能,例如以下例子:
Button.prototype.press = function() { console.log("pressed"); }; // 這時(shí)再用我們的 withClickable,就會覆蓋掉 press withClickable.call(Button.prototype);
這時(shí)候我們應(yīng)該采用Advice,Twitter的Flight框架已經(jīng)提供了此功能:
var withClickable = function () { this.after("press", function () { console.log("press again."); }); }; withAdvice.call(Button.prototype); withClickable.call(Button.prototype); var button = new Button(); button.press(); // 輸出 "pressed", "press again."
兩個(gè)press并不會互相沖突,而是有先后順序的執(zhí)行,就類似通過addEventListener添加了多個(gè)事件而不是直接修改onclick一樣,具體細(xì)節(jié)可以參考Flight的API。
小結(jié)作為一名程序員,我們或許在上學(xué)時(shí)就被灌輸了面向?qū)ο蟮墓逃兴枷?,畢竟面向?qū)ο髲纳鲜兰o(jì)90年代到現(xiàn)在,經(jīng)久不衰,自由它的優(yōu)勢。但是在JavaScript中,如果你并不善于面向?qū)ο蟮某橄笏季S,何不嘗試一下Mixins呢?而且Mixins與類繼承相比,還能更好的解耦合,可以用于任何Object之上,正好用上了JavaScript若類型的優(yōu)勢。
最近在讀《Beautiful JavaScript》這本書,有一些好的內(nèi)容,正好可以跟大家分享,但并不是全部,有興趣的同學(xué)也可以自己讀一下,請支持正版。
原文鏈接:http://t.cn/RteECIF
微信號:程序員晉級之路『code-learning』
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/80185.html
摘要:月日,谷歌正式發(fā)布了的。到底能不能成為跨平臺開發(fā)終極之選是基于前端誕生的,但是對前端開發(fā)來說,的環(huán)境配置很麻煩,需要原生的平臺知識,還要擔(dān)心遇上網(wǎng)絡(luò)問題?,F(xiàn)在已經(jīng)不是曾經(jīng)的小眾框架,這兩年里它已經(jīng)逐步成長為主流的跨平臺開發(fā)框架之一。 ...
摘要:混合中的鉤子函數(shù)同名鉤子函數(shù)都會執(zhí)行如果組件中存在鉤子函數(shù),混合中也存在相同的鉤子函數(shù),那么兩個(gè)鉤子函數(shù)都會執(zhí)行。最終的執(zhí)行結(jié)果多個(gè)混合的鉤子函數(shù)多個(gè)混合的鉤子函數(shù),會根據(jù)混合使用的順序來執(zhí)行。 1.認(rèn)識混合 混合(mixins)是一種分發(fā)Vue組件中可復(fù)用功能的非常靈活的方式 混合的作用:抽取多個(gè)組件的共同部分,增強(qiáng)組件的可復(fù)用性 混合的實(shí)質(zhì):混合對象類似一個(gè)Vue實(shí)例,可以包含V...
摘要:的語言的動(dòng)態(tài)性意味著我們可以使用以上種數(shù)據(jù)類型表示變換過渡動(dòng)畫實(shí)現(xiàn)案例前端掘金以下所有效果的實(shí)現(xiàn)方式均為個(gè)人見解,如有不對的地方還請一一指出。 讀 zepto 源碼之工具函數(shù) - 掘金Zepto 提供了豐富的工具函數(shù),下面來一一解讀。 源碼版本 本文閱讀的源碼為 zepto1.2.0 $.extend $.extend 方法可以用來擴(kuò)展目標(biāo)對象的屬性。目標(biāo)對象的同名屬性會被源對象的屬性...
摘要:本文最早為雙十一而作,原標(biāo)題雙大前端工程師讀書清單,以付費(fèi)的形式發(fā)布在上。發(fā)布完本次預(yù)告后,捕捉到了一個(gè)友善的吐槽讀書清單也要收費(fèi)。這本書便從的異步編程講起,幫助我們設(shè)計(jì)快速響應(yīng)的網(wǎng)絡(luò)應(yīng)用,而非簡單的頁面。 本文最早為雙十一而作,原標(biāo)題雙 11 大前端工程師讀書清單,以付費(fèi)的形式發(fā)布在 GitChat 上。發(fā)布之后在讀者圈群聊中和讀者進(jìn)行了深入的交流,現(xiàn)免費(fèi)分享到這里,不足之處歡迎指教...
摘要:本文最早為雙十一而作,原標(biāo)題雙大前端工程師讀書清單,以付費(fèi)的形式發(fā)布在上。發(fā)布完本次預(yù)告后,捕捉到了一個(gè)友善的吐槽讀書清單也要收費(fèi)。這本書便從的異步編程講起,幫助我們設(shè)計(jì)快速響應(yīng)的網(wǎng)絡(luò)應(yīng)用,而非簡單的頁面。 本文最早為雙十一而作,原標(biāo)題雙 11 大前端工程師讀書清單,以付費(fèi)的形式發(fā)布在 GitChat 上。發(fā)布之后在讀者圈群聊中和讀者進(jìn)行了深入的交流,現(xiàn)免費(fèi)分享到這里,不足之處歡迎指教...
閱讀 1466·2019-08-29 17:14
閱讀 1657·2019-08-29 12:12
閱讀 739·2019-08-29 11:33
閱讀 3275·2019-08-28 18:27
閱讀 1454·2019-08-26 10:19
閱讀 914·2019-08-23 18:18
閱讀 3537·2019-08-23 16:15
閱讀 2551·2019-08-23 14:14