【翻译】理念:无冲突的扩展本地DOM原型
菜鳥翻譯,望大家多多指正哈
原文:http://lea.verou.me/2015/04/idea-extending-native-dom-prototypes-without-collisions/
理念:無沖突的擴(kuò)展本地DOM原型
正如我昨天在博文中指出,我不喜歡使用jQuery的原因之一是因?yàn)樗陌b對(duì)象。對(duì)于jQuery來說,這是一個(gè)明智的決定:早在2006年它被第一次開發(fā)出來的時(shí)候,IE有一個(gè)非常討厭的內(nèi)存泄漏bug,當(dāng)我們給一個(gè)元素添加屬性時(shí)它便很容易被引發(fā)出來。哦,那時(shí)我們還沒有在IE瀏覽器訪問元素的原型,所以我們必須手動(dòng)在每個(gè)元素上添加這些屬性。Prototype.js試圖走這條路但結(jié)果卻是一團(tuán)糟:他們打算改變他們之前在Prototype2.0版和依附包裝對(duì)象的決定。有人曾寫過很長的文章來批判企圖擴(kuò)展本地DOM元素是多么典型的錯(cuò)誤想法。
??第一個(gè)暴露元素原型的IE瀏覽器是IE8:我們可以訪問Node.prototype,Element.prototype和其他幾種原型。有些是多變的,有些則不是。在IE9,我們得到了全部,包括HTMLElement.prototype及其后代節(jié)點(diǎn),比如HTMLParagraphElement。內(nèi)存泄漏bug在IE8時(shí)得到了改善,到IE9時(shí)則得到了修復(fù)。但我們還是不要擴(kuò)展原生的DOM元素,理由很充分:有沖突的風(fēng)險(xiǎn)。沒有哪個(gè)函數(shù)庫想在元素上添加一堆方法,這種方式很糟糕, 就像被邀請(qǐng)到別人家做客,結(jié)果卻把人家家里弄的一團(tuán)亂。
??但是,如果我們可在避免沖突的條件下對(duì)元素添加方法呢?(好吧,從技術(shù)上講,可能性很小)。我們只能對(duì)元素添加一個(gè)屬性,然后把我們所有的方法都附著上去。例如:如果我們的函數(shù)庫為yolo并有兩個(gè)方法:foo()和bar(),就像這樣:
var element = document.querySelector(".someclass"); element.yolo.foo(); element.yolo.bar(); //你甚至可以鏈?zhǔn)椒祷厮麄兊脑?/span> element.yolo.foo().yolo.bar();可以肯定,這比包裝對(duì)象更別扭,但是我認(rèn)為使用本地DOM元素所帶來的好處要大于它。當(dāng)然,你可能不這么認(rèn)為。
??這基本上同我們做全局是完全一樣的:我們都知道,添加大量的全局變量是不可取的做法,所以每一個(gè)函數(shù)庫都只創(chuàng)建一個(gè)全局變量并把所有方法屬性都附著在這個(gè)全局上。? 然而,如果我們?cè)噲D以這種天真的方式來實(shí)施,我們會(huì)發(fā)現(xiàn) 用我們的命名空間函數(shù)來引用元素是有些難度的:
Element.prototype.yolo = {foo: function () {console.log(this); },bar: function () { /* ... */ }}; someElement.yolo.foo(); // Object {foo: function, bar: function}這里發(fā)生了什么?函數(shù)中的this指向的調(diào)用他們的對(duì)象,而不是對(duì)象所附著的那個(gè)元素,想要避開這個(gè)問題我們需要更聰明點(diǎn)。
??記住:Yolo里的this?指向我們?cè)噲D掛載方法的元素,但是我們沒有運(yùn)行任何代碼,所以我們沒有利用它。除非我們能夠得到一個(gè)引用該對(duì)象的上下文。然而,運(yùn)行一個(gè)function (例如element.yolo(). foo())會(huì)毀壞我們良好的API。
??稍等一下,我們可以通過ES5獲得權(quán)限!我們這樣做:
Object.defineProperty(Element.prototype, "yolo", {get: function () {return {element: this,foo: function() {console.log(this.element);}, bar: function() { /* ... */ }}},configurable: true,writeable: false}); someElement.yolo.foo(); // It works! (打印出該元素)這個(gè)方法奏效,但是這里有一個(gè)相當(dāng)惱人的問題:我們每次生成該對(duì)象和重新定義函數(shù)都要調(diào)用該屬性。這是一個(gè)很壞的想法。理想情況下,我們需要生成該對(duì)象,然后返回生成的對(duì)象。我們也不想讓每個(gè)元素都有自己完全獨(dú)立的實(shí)例,我們想在原型上定義這些函數(shù),并且用JS完美的繼承,因此,我們的庫也是動(dòng)態(tài)可擴(kuò)展的。幸運(yùn)的是,有一種方法可以做到這一切:
var Yolo = function(element) {this.element = element; };Yolo.prototype = {foo: function() {console.log(this.element);},bar: function() { /* ... */ } };Object.defineProperty(Element.prototype, "yolo", {get: function () {Object.defineProperty(this, "yolo", {value: new Yolo(this)});return this.yolo;},configurable: true,writeable: false });someElement.yolo.foo(); // 成功! (打印出元素)// 它也是可以動(dòng)態(tài)擴(kuò)展的 Yolo.prototype.baz = function(color) {this.element.style.background = color; };someElement.yolo.baz("red") // 元素獲得了一個(gè)紅色背景注意,上面我們所提到的getter只執(zhí)行一次。之后它用一個(gè)靜態(tài)值:一個(gè)yolo對(duì)象的實(shí)例重寫了yolo屬性。因?yàn)槲覀冇?到Object.define Property()所以也不會(huì)遇到破壞枚舉的問題(for..in循環(huán)),這些屬性默認(rèn)enumerable: false。這里任然有一個(gè)不足:這些方法需要用this.element來替代this。我們可以通過封裝他們來解決這一問題:
for (let method in Yolo.prototype) {Yolo.prototype[method] = function(){var callback = Yolo.prototype[method];Yolo.prototype[method] = function () {var ret = callback.apply(this.element, arguments);// 可鏈?zhǔn)椒祷卦?return ret === undefined? this.element : ret;}} }然而,現(xiàn)在你不能動(dòng)態(tài)的在Yolo.prototype上添加方法并讓他們像element.yolo里的本地方法那樣自動(dòng)運(yùn)行。所以它是有點(diǎn)痛的可擴(kuò)展性(當(dāng)然,你仍然可以用this.element來添加方法,也是可行的)。?
??你的想法?
?
轉(zhuǎn)載于:https://www.cnblogs.com/chayangge/p/4515088.html
總結(jié)
以上是生活随笔為你收集整理的【翻译】理念:无冲突的扩展本地DOM原型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微软超融合私有云测试11-SCVMM20
- 下一篇: 模糊搜索神器FZF番外篇