2016-08-03 35 views
3

我有這個對象,第三方跟蹤工具類似於谷歌分析。我想用我自己的「緩存」功能擴展它,以便保存之前跟蹤調用的數據,以便我可以根據需要在下一個跟蹤調用中引用相關內容。JavaScript引用動態父對象

這是我迄今爲止,它的工作原理:

// Current 3rd party tool, can't really mess with this. 
// It is loaded from an external script 
window.someTool={/* stuff */}; 

// my code 
someTool._cache=someTool._cache||{}; 
someTool._cache._get=function(variabl) { 
    var length,index,variabl=(variabl||'').split('.'), 
     cache=someTool&&someTool._cache&&someTool._cache._dataLayer||{}; 
    for (index=0,length=var.length;index<length;index++){ 
    cache=cache[variabl[index]]; 
    if (!cache) break; 
    } 
    return cache; 
}; 

所以後來我/請執行下列操作

// data layer output on initial page that gets wiped later 
var dataLayer = { 
    'page' : { 
    'name' : 'foo', 
    'lang' : 'en' 
    }, 
    'events' : { 
    'pageView' : true, 
    'search' : true 
    } 
} 

// I grab the initial data layer and save it here 
someTool._cache._dataLayer = dataLayer; 

然後,這可以讓我做的東西一樣

someTool._cache._get('page'); // returns {'page':{'name':'foo','lang':'en'} 
someTool._cache._get('page')['name']; // returns 'foo' 
someTool._cache._get('page.lang'); // returns 'en' 

So th對我來說很有用,但這裏提出了一個問題/目標:我想改善我的_get功能。也就是說,我不喜歡我必須硬編碼someTool,或甚至_cache,如果我可以以某種方式擺動它,_dataLayer

在理想情況下,我想的someTool._cache._dataLayer傳遞,這樣,如果someTool_cache,或_dataLayer要改變的命名空間,我沒有更新_get參照/暴露於_get(例如parent類型參考)。 但我不知道該怎麼做。

這是我到目前爲止有:

(function(tool, cache, dataLayer) { 
    var tool = tool || {}, 
     cache = cache || '_cache', 
     dataLayer = dataLayer || '_dataLayer'; 

    dataLayer = tool[cache][dataLayer] || {}; 

    tool[cache]._get = function(property) { 
    var length, index, property = (property || '').split('.'); 

    for (index = 0, length = property.length; index < length; index++) { 
     dataLayer = dataLayer[property[index]]; 
     if (!dataLayer) break; 
    } 

    return dataLayer; 
    }; 
})(someTool, '_cache', '_dataLayer'); 

這似乎是工作的第一一次我稱呼它,例如

someTool._cache._get('page')['name']; //返回「富」

但在那之後,我得到一個錯誤:

TypeError: someTool._cache._get(...) is undefined

我覺得它是與dataLayer失去其參考什麼的,我不知道(雖然我不確定它是如何第一次工作的..)。我所做的甚至是可能的,如果是的話,我會在哪裏出錯?或者是我最初能做的最好的事情?

+1

一個友好的建議。您應該使用更多描述性變量名稱和更清晰的格式,尤其是當您要求其他人閱讀您的代碼時 – nem035

+0

@ nem035好的,我確定使用擴展變量名更新了我的代碼,謝謝 – slinkhi

+0

實際上,空格和格式化將幫助更多擁擠的名字:)。只需使用'tidy'選項作爲代碼片段,這就是我對我的編輯所做的事情,它爲您做了格式化。 – nem035

回答

1

I feel like it has something to do with dataLayer losing its reference or something, I dunno (though I'm not sure how it's working first time around..).

出現這種情況的原因是因爲你使用你的_get關閉初始化相同dataLayer

  • 存儲信息,並
  • 作爲臨時循環變量使用

如果你看看你的代碼:

(function(tool, cache, dataLayer) { 
    // ... 

    // Here you are initializing (or looking up) the dataLayer 
    dataLayer = tool[cache][dataLayer] || {}; 

    tool[cache]._get = function(property) { 
    // ... 

    for (index = 0, length = property.length; index < length; index++) { 
     // here you are overwriting the same dataLayer 
     dataLayer = dataLayer[property[index]]; 
     if (!dataLayer) break; 
    } 

    return dataLayer; 
    }; 
})(someTool, '_cache', '_dataLayer'); 

你可以看到你的循環將在每次迭代中覆蓋dataLayer,這意味着在第一次迭代之後的每次查找很可能是錯誤的。

最後,dataLayer將被覆蓋undefined,然後任何進一步的查找現在將破壞代碼。

你可以做的是使用另一個變量的循環迭代:

var temp; 
for (index = 0, length = property.length; index < length; index++) { 
    temp = dataLayer[property[index]]; 
    if (!temp) break; 
} 

return temp; 

這將使你的dataLayer對象不變。

+0

是的,它做到了。非常感謝:) – slinkhi

+0

沒問題,很高興幫助:) – nem035

1

儘管您的代碼如此混亂(單字符變量名稱,濫用逗號運算符等),難以確定,但似乎需要在繼續之前修復一些問題。以下劃線前綴

  1. 屬性意味着是私人。他們可能會發生變化,並且我的意思是您的應用程序會隨機破壞。 使用公共API

  2. 用手解析字符串是很多工作,看起來收效甚微。 get('page.id')超過get('page').id的用例是否真的如此引人注目?

  3. 你的代碼是不可理解的。這就是人們期望的縮小器的輸出:它使得很難理解它應該做什麼/ 。

  4. 除非第三方API對您的應用程序是如此不可或缺,否則無論什麼(例如谷歌地圖)或其他衆所周知的它有很多克隆(jQuery),它都需要重寫,它通常是打包第三方庫調用的好主意,以便以後可以更改庫。

我知道這並不能回答你的問題,但它太長了評論,這將是我的疏忽不點出鮮紅的目標(複數)你畫你的腳前拋光你的槍支。

至於你的實際問題(後編輯),你是在正確的軌道上。但我會讓它成爲一個curried函數,這樣你就可以動態地訪問不同的屬性。我們要忽略一分鐘了巨大的錯誤正在訪問私有財產只是爲了讓整個點:如果你需要其他的東西

function accessDataCache(cache) { 
    return function(dataLayer) { 
    return function(namespaceObj) { 
     return function(property) { 
     return namespaceObj[cache][dataLayer][property]; 
     }; 
    }; 
    }; 
}; 

var getFn = accessDataCache('_cache')('_dataLayer')(someTool); 
getFn('page'); 

現在你也可以混合和匹配:

var getSomeOtherCachedThing = accessDataCache('_cache')('_someOtherThing')(someTool); 

所有的那是相當繁瑣的手工寫出來的,所以我建議使用類似lodash或Ramda和.curry達到的效果:

var accessCacheData = R.curry(function(cache, dataLayer, namespaceObj, property) { 
    return namespaceObj[cache][dataLayer][property]; 
}); 
+0

感謝您的意見。我理解這些問題,並不(不一定)不同意他們。但是,我忽略了很多背景/設置,以關注實際的問題。你的許多觀點與我的情況無關。如果我想寫一本關於它的小說,或許你會更加寬容你的注意事項;) – slinkhi

+0

btw關於第二點我實際上並不需要*'_get('page.id')'功能。我只是使用答案[這裏](http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string)作爲參考,我不是一些超級js忍者足以無視這種效果。但我想也許它可能派上用場,如果某個緩存屬性是某個回調函數最終返回一個值或某物。我不知道。 – slinkhi

+1

@slinkhi關於你的第一點,我相當公平,我只是要小心你如何發佈問題,讓人們不會錯誤的想法,你真正想要的人的類型*從一般的答案不會讓這樣的東西通過沒有評論(nem035和我自己就是個例子)。至於你的第二個評論,這是一個YAGNI,它增加了複雜性和失敗情況,否則僅僅是爲了投機益處。按照字符串名稱調用函數無論如何都有點異味,這意味着你可能沒有很好地構建代碼。 –