2013-10-18 66 views
0

假設我有這樣的設置。在其中一個屬性中添加對Javascript對象的引用是一個不好的做法嗎?

var Account = function(data) { 
    this.data = data; 
    this.domElement = (function(){ code that generates DOM element that will represent this account })(); 
    this.domElement.objectReference = this; 
} 

Account.prototype = { 
    show: function() { this.domElement.classList.remove('hidden'); }, 
    hide: function() { this.domElement.classList.add('hidden') } 
} 

我的問題是,最後一行:this.domElement.objectReference = this;

這將是一個有用的東西有,因爲這樣我可以添加事件偵聽到我的DOM元素,仍然可以訪問對象本身。例如,我可以添加會影響我的DOM元素的方法,例如hide()和show(),而不必訴諸直接使用CSS修改DOM元素的可見性。

我測試了這段代碼,它的工作方式與我想要的一樣,但我很好奇這是否會導致內存泄漏或其他不愉快,或者是否可以接受?

謝謝! Luka

+5

我看不出這是非常有用的... – elclanrs

+2

循環這樣可能會導致悲痛,如果只有垃圾回收機制是引用計數。但我認爲大多數JS實現比這更復雜。 – Barmar

+1

@elclanrs - 在我看來這很有用,因爲我可以定義與我的特定元素相關的自定義方法,這將導致更簡潔的代碼。我想我可以通過做hide(element)和show(element)來做同樣的事情,但我想嘗試使用原型。 – Lukich

回答

2

我知道這已經被@PaulS回答帳戶實例。已經有了,但我發現答案與直覺相反(從Account構造函數返回一個DOM元素並不期望),也是以DOM爲中心的,但同時實現非常簡單,所以我不知道該怎麼想;)

無論如何,我只是想表現出一種不同的方式。您可以將Account實例存儲在地圖中,併爲它們提供唯一的id(可能它們已經有一個),然後將該id作爲數據屬性存儲在DOM元素上。最後你實現一個getById函數或類似的東西,從偵聽器中檢索id

這幾乎是jQuery的data的工作原理。

下面是一個例子,其中包含您希望從評論中獲得的委託事件。

DEMO

var Account = (function (accounts, id) { 

    function Account(data) { 
     accounts[this._id = ++id] = this; 

     this.el = createEl.call(this); 
    } 

    Account.prototype = { 
     constructor: Account, 
     show: function() { this.el.classList.remove('hidden'); }, 
     hide: function() { this.el.classList.add('hidden'); } 
    }; 

    function createEl() { 
     var el = this.el = document.createElement('div'); 
     el.className = 'account'; 
     el.innerHTML = el.dataset.accountId = this._id; 

     return el; 
    } 

    Account.getById = function (id) { 
     return accounts[id]; 
    }; 

    Account.init = function() { 
     //add delegate listeners 

     document.addEventListener('click', function (e) { 
      var target = e.target, 
       account = Account.getById(target.dataset.accountId); 

      if (!account) return; 

      account.hide(); 
     }); 
    }; 

    return Account; 
})({}, 0); 

//once DOM loaded 
Account.init(); //start listening to events 

var body = document.body; 

body.appendChild(new Account().el); 
body.appendChild(new Account().el); 
+0

謝謝!你每天學習新的東西。 – Lukich

+0

我其實更喜歡這個,我自己的答案,唯一的危險是它似乎從來沒有釋放內存;你需要添加另一個函數來從'accounts'對象中刪除。 –

+0

@PaulS。是的,在示例中,我沒有實現任何允許釋放內存的API,但是在真實世界的實現中使用某些東西顯然很重要。 – plalx

0

在我看來,引用對象內部的對象本身並沒有什麼好處。主要原因是複雜性和默默無聞。

如果您想指出在代碼中稍後如何使用此domElement.objectReference,我相信我或其他人能夠在沒有此引用的情況下提供解決方案。

1

爲什麼不從功能domElementvar iable和return呢?爲了保持引用您的構造的對象(但僅限於按預期this),你可以做一個if (this instanceof Account) domElement.objectReference = this;

你現在已經從循環引用保存自己,並可以同時訪問節點對象。如果您期望失去對實例的直接引用,但希望在「稍後查看」它涉及的節點時需要它,則這樣做會更有幫助。

Code as requested

var Account = function (data) { 
    var domElement; // var it 
    this.data = data; 
    domElement = (function(){/* ... */}()); // use var 
    if (this instanceof Account) 
     domElement.objectReference = this; // assign `this` 
    return domElement; 
}; 
// prototype as before 

返回元件現在是節點,而不是對象;所以你會像這樣訪問

var domElement = new Account(); 
domElement.objectReference.show(); // for example 
+0

太棒了!謝謝,這看起來像我之後的事情。但是,你介意爲我澄清一點嗎?爲什麼我必須執行instanceof檢查?這不會總是在構造函數中的instanceof Account嗎? – Lukich

+0

@Lukich:如果沒有使用'new Account'(即'var x = Account();')調用它,情況就不會如此。 –

+1

@ Qantas94Heavy是的,但在這種情況下,全局命名空間已經被數據屬性污染;''instanceof Account'似乎沒有太大的意義,除非我錯過了某些東西。無論如何,有了像JSHint這樣的工具,就沒有必要進行這種檢查。 – plalx

相關問題