您的位置:首頁>正文

JavaScript 函數用作物件的隱藏問題

使用者回饋

@消失的鍵盤 在論壇回饋了一個問題, 在 AppBoxMvc 中的 Title 模型中, 如果將 Name 屬性改名為小寫的 name 屬性, 就會報錯:

因為這是一個 ASP.NET MVC 的專案, 而這個屬性是通過 TextBoxFor 渲染到頁面上的, 因此 name 會生成為 DOM 節點的 id 屬性:

F.SimpleForm .ID("SimpleForm1") .ShowBorder(false) .ShowHeader(false) .BodyPadding(10) .Items( F.TextBoxFor(m => m.name), F.TextAreaFor(m => m.Remark) )

按道理說這也沒什麼, 雖然有點彆扭, 但是也沒有規定說name字串不能作為id屬性的值。

並且從另一個方面講, name 也不是 JavaScript 的關鍵字, 不可能衝突阿。

分析問題

還是從代碼入手, 經過簡單的調試, 發現 id=name 的這個文本輸入框物件居然找不到, 而這個物件是保存在 F.ui 上面的。

首先我們看下 F.ui 的定義:

F.ui = function(item) { var itemType = F.getType(item.type || 'component'); return new itemType(item); };

為了方便用戶書寫代碼, FineUIMvc中 F.ui 其實有兩個用途:

1. 用作函數:創建控制項, 可以在JS中通過 F.ui 來創建一個控制項:

F.ui({ type: 'button', renderTo: document.body, text: '按鈕', id:'button1', listeners: { click: function (event) { F.alert('你點擊了按鈕'); } } });

2. 用作對象:保存控制項, 可以在JS中通過 F.ui 來引用一個控制項(比如上面創建的按鈕):

F.ui.button1

這樣一分析問題就來了, 因為本身JS函數是有屬性的, 這裡由於 F.ui 是個匿名函數, 所以 F.ui.name == '' (這個函數的 name 屬性為空字串)

對於一個普通的函數, 這個name屬性就是函數名稱, 如下所示:

function test1 { } console.log(test1.name) // "test1"

其實JavaScript 函數不僅有 name 屬性, 還是 length , caller, arguments, toString .... 等很多屬性, 在Chrome的調試工具中可以方便的查看:

所以, 當我們試圖將名為 name 的文本輸入框物件保存到 F.ui 上時, 其實是不成功的, 此時 F.ui.name 依然為空字串。

解決問題

由於 F.ui 的兩個作用已經被網友所熟知, 並且已經應用到很多項目中了, 不能因為幾個特殊屬性的衝突就廢棄這種做法。 那麼怎麼規避這個問題呢?

我們使用了一個內部變數來保存頁面上的控制項實例:

F._fjs_objects = {};

同時為了相容之前的代碼, F.ui 函數仍然用來保存控制項實例, 只不過在保存之前要先進行判斷, 如果傳入的名稱是函數屬性名的話, 就不要保存:

function nameIsPropertyOfFunction(name) { return $.inArray(name, ['arguments', 'caller', 'length', 'name']) >=0 || $.isFunction(F.ui[name]); } F._fjs_addToFObjects = function(objId, obj) { F._fjs_objects[objId] = obj; if(!nameIsPropertyOfFunction(objId)) { F.ui[objId] = obj; } };

優化後, 之前的所有代碼都不用改動, 你仍然可以通過兩種方式獲取控制項實例:

1. F('controlid')2. F.ui.controlid

而對於非常特殊的情況, 控制項ID為 name, length, toString (當然我們極力不推薦你用這樣的名稱來命名控制項ID!!)時,

頁面也不會出錯, 只不過你不能再通過F.ui.name 來獲取控制項了, 只能通過 F('name') 來獲取控制項物件。

同類文章
Next Article
喜欢就按个赞吧!!!
点击关闭提示