《前端實戰總結》之迭代器模式的N+1種應用場景
眼看12月就來了,抓住今年的尾巴,好好總結一下前端的不足與收穫。這篇文章是筆者寫設計模式專題的第二篇文章,也是基於工作中的總結和提煉,在實際應用場景中都會大量使用,至於為什麼要寫設計模式,主要是為了提高團隊程式碼質量和可維護性,後續會繼續推出設計模式相關的文章,供大家參考和學習。
你將學到
- 迭代器模式的含義
- 實現一個陣列迭代器
- 實現一個物件迭代器
- 實現路徑查詢/賦值迭代器
- 如何用迭代器的思想解決分支迴圈巢狀問題
- 實現一個圖片播放器
正文
1.迭代器的含義
迭代器模式主要的思想就是在不暴露物件內部結構的同時可以按照一定順序訪問物件內部的元素。
其實javascript中的很多方法都運用了迭代器的思想,比如陣列的forEach,every,find,some,map,entries等等,這些操作極大的簡化了我們的邏輯操作,接下來我們就來看看它的具體應用吧。
2.實現一個陣列迭代器
我們都知道javascript中陣列的forEach方法,那麼不用這個方法,我們能自己實現一個嗎?
// 陣列迭代器
let eachArr = function(arr, fn) {
let i = 0,
len = arr.length;
for(; i < len; i++) {
if(fn.call(arr[i], i, arr[i]) === false) {
break;
}
}
}
// 使用
eachArr([1,2,3,4], (index, value) => { console.log(index, value) })
3.實現一個物件迭代器
物件迭代器和陣列迭代器類似, 只是傳參不同,如下:
// 物件迭代器
let eachObj = function(obj, fn) {
for(let key in obj) {
if(fn.call(obj[key], key, obj[key]) === false) {
break;
}
}
}
// 使用
eachObj({a: 11, b: 12}, (key, value) => { console.log(key, value) })
4.實現路徑查詢/賦值迭代器
有時候我們操作物件的某些屬性時,我們不知道伺服器端是否將該屬性或者該屬性的上級屬性正確的返回給我們,這個時候我們直接透過點語法或者[]語法直接訪問會導致程式碼報錯,因此需要我們每一層操作都要做安全校驗,這樣會產生大量臃腫程式碼,比如:
let obj = {};
// 獲取 obj.num.titNum
let titNum = obj.num.titNum; // 報錯
let titNum = obj && obj.num && obj.num.titNum; // 正確
我們透過迭代器可以極大的減少這種校驗,實現更健壯的程式碼模式:
let findObjAttr = function(obj, key){
if(!obj || !key) {
return undefined
}
let result = obj;
key = key.split('.');
for(let i =0; len = key.length; i< len; i++) {
if(result[key[i]] !== undefined) {
result = result[key[i]]
}else {
return undefined
}
}
return result
}
// 使用
let a = { b: { c: { d: 1 } } };
findObjAttr(a, 'a.b.c.d') // 1
這種方式是不是有點類似於lodash的物件/陣列查詢器呢?同理,我們也可以實現路徑賦值器,如下所示:
let setObjAttr = function(obj, key, value){
if(!obj) {
return false
}
let result = obj,
key = key.split('.');
for(let i =0, len = key.length; i< len - 1; i++){
if(result[key[i]] === undefined) {
result[key[i]] = {};
}
if(!(result[key[i]] instanceof Object)){
// 如果第i層對應的不是一個物件,則剖出錯誤
throw new Error('is not Object')
return false
}
result = result[key[i]]
}
return result[key[i]] = val
}
// 使用
setObjAttr(obj, 'a.b.c.d', 'xuxi')
5.如何用迭代器的思想解決分支迴圈巢狀問題
分支迴圈巢狀的問題主要是指在迴圈體中還需要進行額外的判斷,如果判斷條件變多,將會造成嚴重的效能開銷問題,如下面的例子:
// 資料分組
function group(name, num) {
let data = [];
for(let i = 0; i < num; i++){
switch(name) {
case 'header':
data[i][0] = 0;
data[i][1] = 1;
break;
case 'content':
data[i][0] = 2;
data[i][1] = 3;
break;
case 'footer':
data[i][0] = 4;
data[i][1] = 532;
break;
default:
break;
}
}
return data
}
由以上分析可知,上面的程式碼還有很多最佳化空間,因為每一次遍歷都要進行一次分支判斷,那麼如果num變成100000,且name的種類有100種,那麼我們就要做100000*100種無用的分支判斷,這樣無疑會讓你的程式碼在大資料下卡死。不過我們可以透過以下這種方式最佳化它:
// 資料分組
function group(name, num) {
let data = [];
let strategy = function() {
let deal = {
'default': function(i){
return
},
'header': function(i){
data[i][0] = 0;
data[i][1] = 1;
},
'content': function(i){
data[i][0] = 2;
data[i][1] = 3;
},
//...
}
return function(name) {
return deal[name] || deal['default']
}
}();
// 迭代器處理資料
function _each(fn) {
for(let i = 0; i < num; i++){
fn(i)
}
}
_each(strategy(name))
return data
}
這樣我們就能避免分支判斷,極大的提高了程式碼效率和效能。
6.實現一個圖片播放器
圖片播放器主要有以上幾個功能,上一頁,下一頁,首頁,尾頁,自動播放按鈕,停止按鈕。具體元件的設計機構可以參考我寫的demo:
// 圖片播放器
let imgPlayer = function(imgData, box) {
let container = box && document.querySelector(box) || document,
img = container.querySelector('img'),
// 獲取圖片長度
len = imgData.length,
// 當前索引值
index = 0;
// 初始化圖片
img.src = imgData[0];
var timer = null;
return {
// 獲取第一個圖片
first: function() {
index = 0
img.src = imgData[index]
},
// 獲取最後一個圖片
last: function() {
index = len - 1
img.src = imgData[index]
},
// 切換到前一張圖片
pre: function() {
if(--index > 0) {
img.src = imgData[index]
}else {
index = 0
img.src = imgData[index]
}
},
// 切換到後一張圖片
next: function() {
if(++index < len) {
img.src = imgData[index]
}else {
index = len - 1
img.src = imgData[index]
}
},
// 自動播放圖片
play: function() {
timer = setInterval(() => {
if(index > len - 1) {
index = 0
}
img.src = imgData[index]
index++
}, 5000)
},
// 停止播放圖片
stop: function() {
clearInterval(timer)
}
}
}
// 使用
let player = new imgPlayer(imgData, '#box')
總之,迭代器思想和其他設計模式的組合,可以設計出各種各樣高度配置的元件,所以說學好並理解javascript設計模式的精髓,決定了我們的高度和態度。
最後
如果想了解更多webpack,node,gulp,css3,javascript,nodeJS,canvas等前端知識和實戰,歡迎在《趣談前端》一起學習討論,共同探索前端的邊界。
更多推薦
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4606/viewspace-2824390/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 23種設計模式之迭代器模式設計模式
- SpringBoot整合RabbitMQ之典型應用場景實戰二Spring BootMQ
- SpringBoot整合RabbitMQ之典型應用場景實戰一Spring BootMQ
- Flutter - IOT領域應用場景實戰Flutter
- 單例模式應用場景:單例模式
- 重學 Java 設計模式:實戰迭代器模式「模擬公司組織架構樹結構關係,深度迭代遍歷人員資訊輸出場景」Java設計模式架構
- Redis 應用場景彙總Redis
- 迭代器總結
- linux實用命令以及實用場景總結Linux
- 大資料應用場景之戰-行業篇大資料行業
- 【實操】小程式的應用場景分析——線下場景應用
- Android之什麼場景該使用單例模式總結Android單例模式
- Redis最常見的5種應用場景Redis
- Spring Boot之輸入Bean驗證@Valid應用場景總結Spring BootBean
- 單例模式的常見應用場景單例模式
- DATAGUARD實際的應用場景
- Tomcat高階配置(應用場景總結及示例)Tomcat
- 設計模式之迭代器模式設計模式
- 前端兩種路由實現和使用場景前端路由
- js代理模式理解和應用場景JS模式
- 觀察者模式應用場景例項模式
- android 啟動模式應用場景Android模式
- Redis實際應用場景Redis
- Redis的11種Web應用場景簡介RedisWeb
- 【Mysql】mysqldump 匯出各種場景的應用MySql
- Redis系列之(二)——應用場景Redis
- 無服務計算應用場景探討及 FaaS 應用實戰
- JS 裝飾器(Decorator)場景實戰JS
- golang設計模式之迭代器模式Golang設計模式
- Javascript設計模式之迭代器模式JavaScript設計模式
- 總結一些開發語言對應的技術應用場景
- js--迭代器總結JS
- 設計模式應用場景之Model設計中可以用到的設計模式設計模式
- 設計模式 - 迭代器模式詳解及其在ArrayList中的應用設計模式
- node實戰前端快取總結前端快取
- Redis 常見 7 種使用場景 (PHP 實戰)RedisPHP
- 閉包實際場景應用
- nodejs實際應用場景NodeJS