javascript prototype 與 constrctor 的區別
我們的設計人員愛用冗餘欄位, 我數了數當前正在處理的這個功能的子表的欄位數: 103個 不是我反對冗餘,冗餘是塊好鋼,但是要用到刀刃上.目前這種情況讓我很頭疼: 1,有很多冗餘欄位都是必填的, 如果只是對著原型做,可以很方便的分清哪些是從介面傳到背景;哪些是要從後台關聯取出來的. 但是假如這個業務公布成一個WCF介面, 用介面開發的開發人員怎麼能知道哪些是必須傳入的? 重新寫一套邏輯? 2,手累啊!100多個欄位在後台一個一個敲出來,要時間啊! 3,我趨向在後台從記憶體或資料庫等 不可能被篡改 的地方取出這些冗餘資料, 但是取這些資料也是蛋疼的事啊! 我們的設計人員說很簡單:從HTML傳過來就是了!可是互連網是洪水猛獸啊!怎麼能相信從前台傳來的值? 頁面要收集資料很多,主從表,3級/4級甚至5級聯動的情況都有.沒用 knockoutjs 之前,我都是寫一堆模板, 然後 clone , 改 name, 改 value, js 寫的一大堆.現在用 knockoutjs ,也是一大堆,但是優雅了許多. knockoutjs 就三個字:可觀察如果對象不是可觀察的,前台的修改反映不到 js 對象上, js對象上的修改也無法反應到前台頁面上. 所以,不是簡單的 json 就能滿足的, 特別是還要用到 observableArray. 這個 array 裡存的 每個對象 的 每個屬性 還 必須是可觀察的! 上面說了有100多個欄位,用到的有三四十個,我不可能把每個欄位都在 js 給寫一遍.怎麼辦呢? 我的方法: 先把 表 對應的 業務實體 序例化 成一個 json, 輸出到頁面, 賦予一個 js 變數, 然後迴圈這個 json 裡的每個 key , 通過 prototype 擴充 js 裡的"類". 這樣就省事了很多. 代始如下: 複製代碼 1 _.ExtendTypeFromJson = function (json, type, propertyWrap) { 2 for (var item in json) { 3 var value = json[item]; 4 5 if (typeof (propertyWrap) == "function") 6 type.prototype[item] = propertyWrap(value); 7 else 8 type.prototype[item] = value; 9 }10 }複製代碼 使用: 1 var tplData = @Html.Raw(JsonConvert.SerializeObject(tpl)) ;2 var Port = function(){3 this.IsCurrent = ko.observable(false);4 }5 ExtendTypeFromJson(tplData, Port); 其實,這樣寫是有問題的. 很多頁面中, 都沒有用 propertywrap 這個參數, 導致問題沒有暴露出來. 今天在使用的時候,想把每個屬性都擴充成可觀察的,於是我這樣寫: 1 ExtendTypeFromJson(tplData, Port, function(v){2 return ko.observable(v);3 }) 問題出來了, 聲明的所有 Port 的執行個體,除 IsCurrent 外, 改動 任何一個執行個體 的 屬性 的 值 , 所有執行個體 的 對應屬性的 值都是一樣的! 糾結了一會,沒想通, 只知道問題出在 prototype 上.於是換了一種實現方式: 複製代碼 1 _.ExtendConstrctorFromJson = function (json, type, propertyWrap) { 2 3 var __type = type; 4 type = function () { 5 __type.call(this); 6 7 8 for (var item in json) { 9 var value = json[item];10 11 if (typeof (propertyWrap) == "function")12 this[item] = propertyWrap(value);13 else14 this[item] = value;15 }16 }17 18 return type;19 }複製代碼使用,注意是有傳回值的: 1 Port = ExtendConstrctorFromJson(tplData, Port, function(v){2 return ko.observable(v);3 });