js更优雅的兼容_javascript技巧
问题种种做底层接口兼容,无非就是利用if,判断客户端支持哪个接口的问题。最著名的例子就是事件:
var addEvent = function(e, what, how) {
if (e.addEventListener) e.addEventListener(what, how, false)
else if (e.attachEvent) e.attachEvent('on' + what, how)
}
这里考虑了给元素绑定事件时可能遇到的两种状况——标准的W3C DOM接口以及DHTML提供的接口。当然这个例子还很粗糙,但足够说明问题了。
原先的方法是在兼容层调用有现场判断并进入相应的if分支。很显然,这种“现场判断”的方法效率并不高。后来,人们采用这样的办法:
if (MSIE) {
addEvent = function(e, what, how) {
e.attachEvent('on' + what, how);
}
} else {
addEvent = function(e, what, how) {
e.addEventListener(what, how);
}
}
在一次判断后给addEvent绑定不同的代码,从而免去了运行时的分支判断。
很可惜,这个问题也不小。首先把“采用attachEvent”和“客户端是MSIE”绑定在一起是个很过时的想法。假如微软哪天良心发现了怎么办?这事情现在就发生了——IE9明确支持了DOM接口,甚至DOM3都支持。结果,就这个“良心发现”的举动会毁掉许多前端库,他们必须被迫修改代码(如同IE8来时那样)。况且这种做法没有考虑“未知的客户端”——据我所知,Google发布Chrome后也导致不少类库重写代码。
特性检测那究竟该怎么做?特性检测就可以最大限度地避免“新客户端”带来的麻烦——通过一组在类库初始化时定义的代码来检测客户端拥有的特性,并利用这一组检测值绑定类库代码:
var supportsAddEventListener = !!(checkerElement.addEventListener);
if (supportsAddEventListener) {
addEvent = function(e, what, how) {
e.addEventListener(what, how);
}
} else if (supportsAttachEvent) {
addEvent = function(e, what, how) {
e.attachEvent('on' + what, how);
}
}
特性检测实际上是将“使用某个客户端”和“支持某个特性”进行解耦——让if分支直接针对“特性有无”(接口是否一致)判断,从而消除客户端制造商“良心发现”造成的“好心办坏事”。事实上这么做也是符合历史潮流之选——当标准接口逐渐普及,客户端之间渐渐“表征一致”时,为什么不做个一致的兼容层接口呢?
跌落让我们重新看看这些代码。通常,一条利用特性检测进行兼容的代码往往是这样:
if (new_interface_detected) {
comp = function() {uses_new_interface};
} else if (old_interface_detected) {
comp = function() {uses_old_interface};
} else {
throw new Error('Unadaptable!')
}
换言之,过程是:
如果客户端支持新接口,就将兼容层绑定到新接口上
否则,如果客户端支持老接口/不一致接口,就将兼容层绑定到老接口上
否则,如果可以的话,给出错误回馈
亦即,兼容层程序是从高空“掉”下来,如果客户端支持“高级”特性(新接口、标准接口)就将它“接住”——兼容层就有了归宿;否则继续向下掉——哦,老接口接住了,就用老接口;如果一直没人接住,于是——啪——摔倒了地上,并且用最后一口气喊一声:“你用的客户端太小众,我拿你没办法了!”
这和什么比较像?事实上,如果你了解JavaScript对象系统的机理,你就可以类比:这不就是原型嘛!原型系统就是利用了这种跌落——寻找某个成员,如果它在这个对象里定义了,就返回之;否则沿着原型链向上搜(没错,这次是向上的),如此重复,直到真的连原型链都到头的时候,返回个undefined。
说做就做!这里同样用addEvent为例。首先,我们定义一个空驱动,它里面什么都不包含:
var nullDriver = {}然后,就是创建个对象,并且把原型链指向它。在ECMA V5时代,我们可以用Object.create,可惜,现在还有N多老客户端(否则做什么兼容啊),所以自己craft个函数:
var derive = Object.create ? Object.create: function() {
var T = function() {};
return function(obj) {
T.prototype = obj;
return new T
}
}()
这个用法你可能会觉得很诡异,但它工作起来一点问题没有,速度也不慢——能达到Object.create的一半。我们就用这个derive开动:
var dhtmlDriver = derive(nullDriver);
var dhtmlDriverBugfix = derive(dhtmlDriver);这里的bugfix是针对一些“bug”和特殊情况定义的特别Driver。这里你可以忽略它。好了,DHTML里面addEvent是什么来着?
if (supportsAttachEvent) {
dhtmlDriver.addEvent = function(e, what, how) {
e.attachEvent('on' + what, how)
}
}
然后呢?位于原型链最前端的应该是W3C的标准驱动啊,写上!
var w3cDriver = derive(dhtmlDriverBugfix);
var w3cDriverBugfix = derive(w3cDriver);
if (supportsAddEventListener) {
w3cDriver.addEvent = function(e, what, how) {
e.addEventListener(what, how)
}
}
最后,我们就放个东西上去做最后调用的接口。(因为w3cDriverBugfix太难看……)
var driver = derive(w3cDriverBugfix);
然后就调用好了。看,这就让那些长得吓人的分支判断变得简单有效,但不失fallback本色:在支持addEventListener上调用addEvent等价于调用w3cDriver.addEvent,而在不支持addEventListener的客户端上就会跌落到底下,比如调用dhtmlDriver.addEvent。另外,进行bugfix也很容易——可以在专门的“bugfix”层进行hook,而原有层丝毫不受影响。
等等,继承这么多层会很慢么?诚然,那么深的原型链肯定会慢,不过我有办法。还记得给对象的属性写入时会发生什么事情吗?
var ego = function(x) {return x}
for (var each in driver) {
if (! (each in nullDriver)) {
driver[each] = ego(driver[each])
}
}
没错,原来高企在原型链上面的方法会“哗”的一下掉到最下面!这回不用沿着原型链向上搜了,直接从最底端获取属性即可。这里用ego函数的原因是防止一些浏览器“优化掉”这里的代码。
总结虽然这里谈兼容,可是,它的精华却在语言特性上——利用原型继承,我们可以很优雅地完成这个令人头疼的操作。是的,框架的美感不应该只在外表,其内部——即使是最最令人烦的内部——也同样要优雅。
这里的技术可以在dess中找到。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

很多用戶都會遇到在操作電腦的時候卡頓或者是藍屏,這個時候我們就需要找一個最為穩定的win10版本來進行操作,整體都是非常的好用的,可以讓你日常使用更為流暢。史上最穩定的win10版本1、win10正版原廠系統在這裡用戶可以使用簡單的操作,系統經過優化,具有很強的穩定性、安全性、兼容性,用戶可以按照步驟實現完美機器2、俄羅斯大神精簡版win10經過嚴格的精簡操作,刪除了許多不必要的功能和服務。精簡後,系統的CPU和記憶體佔用率更低,運作速度更快。 3.win10精簡版1909安裝多台不同硬體型號的電腦

眾所周知,win11一大特色就是自備安卓子系統,讓我們不需要用模擬器就可以安裝安卓軟體,但也存在win11安卓應用卡頓的問題,這該怎麼解決呢。 win11不相容動態桌布麼:答:win11能相容動態壁紙,如果用不了可能是軟體或系統版本落後。如果是剛更新,可能是被系統桌布覆蓋了。 1.如果是系統或軟體版本落後,那麼更新一下系統和動態桌布軟體即可。 2.如果是被系統桌布覆蓋了,可以嘗試開啟「設定」3、接著進入「個人化」下的「背景」設定。 4.然後將個人化設定背景改為「圖」5、修改完成後就能正常設定動態桌布

Switch2是任天堂在2023年科隆遊戲展公佈的新機型,一些玩家擔心新出來的機型與之前版本的機型卡帶會不會存在兼容性問題,下面我們一起來看看吧。 switch2相容於switch卡帶嗎答:switch2不相容switch卡帶。 Switch2卡帶的介紹根據任天堂的生產鏈公司的消息稱,Switch2可能會使用64GB的卡帶。它由於性能更好,支撐更多的3A遊戲大作的原因,需要更大卡帶容量。因為很多的遊戲作品需要閹割和壓縮,才能塞進一張遊戲卡帶裡面。而且Switch的卡帶容易被複製遊戲內容,所以更換新卡帶

近年來,Android系統在行動裝置領域的普及率迅速增長,許多人開始關注在其他平台上是否也能運行安卓應用程式。 Linux作為常見的作業系統,受到不少人的青睞,那麼問題來了,Linux系統是否相容於安卓軟體呢?首先要明確的是,Linux系統與Android系統在核心上有一定的相似性,都是基於Linux核心的作業系統,因此從理論上來講,Linux系統是可以運行

d3dx9_43.dll不相容怎麼解決近年來,電腦和遊戲的快速發展使得我們享受了更多的娛樂和便利。然而,有時在安裝或執行某些程式時,我們可能會遇到一些錯誤訊息,例如「d3dx9_43.dll不相容」。在這種情況下,我們該如何解決這個問題?首先,讓我們來了解一下這個錯誤訊息的含義。 d3dx9_43.dll是DirectX的一個系統文件,它是用於在操作系

有不少網站用戶們在瀏覽的時候都會需要使用舊版本的瀏覽器才能夠使用,而新版本的需要添加兼容網點才可以進行使用,所以今天就給你們帶來了win11添加兼容網點詳細教程,來學習一下。 win11如何新增相容網點1、先開啟系統中的IE瀏覽器,點選瀏覽器右上角小齒輪進入「設定」。 2、然後在開啟的設定選單中,開啟「相容性視圖設定」。 3、在新增此網站下的編輯框中輸入要新增的網址,然後點選「新增」。 4.最後在下方就可以看到新增網址的網域名稱了,關閉視窗即可直接存取。

很多朋友目前還在選擇win7系統而不是win10系統的原因就是害怕其相容性不好。其實,現在win10系統已經可以設定win7的相容模式了,只需要在屬性中就可以更改設置,下面就一起來看一下吧。 win10怎麼相容於win71、首先右鍵點擊我們需要在win7系統下運行的程序,然後打開“屬性”2、然後點擊上方的“相容性”,進入相容性選項卡。 3.在相容模式下勾選「以相容模式執行這個程式」4、然後就可以在下方的下拉式選單中選擇「windows7」5、完了之後只需要點擊「應用」或點選「確定」就可以了。

遇到Eclipse版本不相容怎麼辦? 【引言】Eclipse作為一款廣受歡迎的開發工具,不僅提供了強大的功能和豐富的插件,還兼具跨平台的特性。然而,在使用Eclipse過程中,有時可能會遇到版本不相容的問題,這可能導致程式無法正常運作或編譯錯誤。本文將介紹如何應對Eclipse版本不相容的情況,並提供一些程式碼範例來解決常見的兼容性問題。 【解決方案】更新Ecl
