最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript單一職責(zé)原則深入分析

 更新時(shí)間:2022年08月09日 14:30:05   作者:夏安  
這篇文章主要介紹了理解JavaScript單一職責(zé)原則,單一職責(zé)原則(SRP:Single?responsibility?principle)又稱單一功能原則,面向?qū)ο笪鍌€(gè)基本原則(SOLID)之一,下文更多相關(guān)介紹感興趣的小伙伴可以參考一下

單一職責(zé)原則

就一個(gè)類而言,應(yīng)該僅有一個(gè)引起它變化的原因。在 JavaScript 中,需要用到類的場(chǎng)景并不太多,單一職責(zé)原則更多地是被運(yùn)用在對(duì)象或者方法級(jí)別上,因此本節(jié)我們的討論大多基于對(duì)象和方法。

單一職責(zé)原則(SRP)的職責(zé)被定義為“引起變化的原因”。如果我們有兩個(gè)動(dòng)機(jī)去改寫一個(gè)方法,那么這個(gè)方法就具有兩個(gè)職責(zé)。每個(gè)職責(zé)都是變化的一個(gè)軸線,如果一個(gè)方法承擔(dān)了過多的職責(zé),那么在需求的變遷過程中,需要改寫這個(gè)方法的可能性就越大。

此時(shí),這個(gè)方法通常是一個(gè)不穩(wěn)定的方法,修改代碼總是一件危險(xiǎn)的事情,特別是當(dāng)兩個(gè)職責(zé)耦合在一起的時(shí)候,一個(gè)職責(zé)發(fā)生變化可能會(huì)影響到其他職責(zé)的實(shí)現(xiàn),造成意想不到的破壞,這種耦合性得到的是低內(nèi)聚和脆弱的設(shè)計(jì)。

因此,SRP 原則體現(xiàn)為:一個(gè)對(duì)象(方法)只做一件事情。

設(shè)計(jì)模式中的SRP原則

SRP 原則在很多設(shè)計(jì)模式中都有著廣泛的運(yùn)用,例如代理模式、迭代器模式、單例模式和裝飾者模式。

代理模式

通過增加虛擬代理的方式,把預(yù)加載圖片的職責(zé)放到代理對(duì)象中,而本體僅僅負(fù)責(zé)往頁面中添加 img 標(biāo)簽,這也是它最原始的職責(zé)。

myImage 負(fù)責(zé)往頁面中添加 img 標(biāo)簽:

const myImage = (function () {
	const imgNode = document.createElement('img');
	document.body.appendChild(imgNode);
	return {
		setSrc: function (src) {
			imgNode.src = src;
		}
	}
})();

proxyImage 負(fù)責(zé)預(yù)加載圖片,并在預(yù)加載完成之后把請(qǐng)求交給本體 myImage

const proxyImage = (function () {
	const img = new Image;
	img.onload = function () {
		myImage.setSrc(this.src);
	}
	return {
		setSrc: function (src) {
			myImage.setSrc('file:// /C:/Users/svenzeng/Desktop/loading.gif');
			img.src = src;
		}
	}
})();
proxyImage.setSrc('http:// imgcache.qq.com/music/photo/000GGDys0yA0Nk.jpg');

把添加 img 標(biāo)簽的功能和預(yù)加載圖片的職責(zé)分開放到兩個(gè)對(duì)象中,這兩個(gè)對(duì)象各自都只有一個(gè)被修改的動(dòng)機(jī)。在它們各自發(fā)生改變的時(shí)候,也不會(huì)影響另外的對(duì)象。

迭代器模式

我們有這樣一段代碼,先遍歷一個(gè)集合,然后往頁面中添加一些 div,這些 divinnerHTML 分別對(duì)應(yīng)集合里的元素:

const appendDiv = function (data) {
	for (let i = 0, l = data.length; i < l; i++) {
		const div = document.createElement('div');
		div.innerHTML = data[i];
		document.body.appendChild(div);
	}
};
appendDiv([1, 2, 3, 4, 5, 6]);

這其實(shí)是一段很常見的代碼,經(jīng)常用于 ajax 請(qǐng)求之后,在回調(diào)函數(shù)中遍歷 ajax 請(qǐng)求返回的數(shù)據(jù),然后在頁面中渲染節(jié)點(diǎn)。

appendDiv 函數(shù)本來只是負(fù)責(zé)渲染數(shù)據(jù),但是在這里它還承擔(dān)了遍歷聚合對(duì)象 data 的職責(zé)。 我們想象一下,如果有一天 api 返回的 data 數(shù)據(jù)格式從 array 變成了 object,那我們遍歷 data 的代碼就會(huì)出現(xiàn)問題,必須改成 for ( let i in data )的方式,這時(shí)候必須去修改 appendDiv 里的代碼,否則因?yàn)楸闅v方式的改變,導(dǎo)致不能順利往頁面中添加 div 節(jié)點(diǎn)。

我們有必要把遍歷 data 的職責(zé)提取出來,這正是迭代器模式的意義,迭代器模式提供了一種方法來訪問聚合對(duì)象,而不用暴露這個(gè)對(duì)象的內(nèi)部表示。

當(dāng)把迭代聚合對(duì)象的職責(zé)單獨(dú)封裝在 each 函數(shù)中后,即使以后還要增加新的迭代方式,我們只需要修改 each 函數(shù)即可,appendDiv 函數(shù)不會(huì)受到牽連,代碼如下:

const each = function (obj, callback) {
	let value,
		i = 0,
		length = obj.length,
		isArray = isArraylike(obj); // isArraylike 函數(shù)這里未實(shí)現(xiàn)
	if (isArray) { // 迭代類數(shù)組
		for (; i < length; i++) {
			callback.call(obj[i], i, obj[i]);
		}
	} else {
		for (i in obj) { // 迭代 object 對(duì)象
			value = callback.call(obj[i], i, obj[i]);
		}
	}
	return obj;
};
const appendDiv = function (data) {
	each(data, function (i, n) {
		const div = document.createElement('div');
		div.innerHTML = n;
		document.body.appendChild(div);
	});
};
appendDiv([1, 2, 3, 4, 5, 6]);
appendDiv({ a: 1, b: 2, c: 3, d: 4 });

單例模式

JavaScript單例模式實(shí)現(xiàn)過一個(gè)惰性單例,最開始的代碼是這樣的:

const createLoginLayer = (function () {
	let div;
	return function () {
		if (!div) {
			div = document.createElement('div');
			div.innerHTML = '我是登錄浮窗';
			div.style.display = 'none';
			document.body.appendChild(div);
		}
		return div;
	}
})();

現(xiàn)在我們把管理單例的職責(zé)和創(chuàng)建登錄浮窗的職責(zé)分別封裝在兩個(gè)方法里,這兩個(gè)方法可以獨(dú)立變化而互不影響,當(dāng)它們連接在一起的時(shí)候,就完成了創(chuàng)建唯一登錄浮窗的功能,下面的代碼顯然是更好的做法:

const getSingle = function (fn) { // 獲取單例
	let result;
	return function () {
		return result || (result = fn.apply(this, arguments));
	}
};
const createLoginLayer = function () { // 創(chuàng)建登錄浮窗
	const div = document.createElement('div');
	div.innerHTML = '我是登錄浮窗';
	document.body.appendChild(div);
	return div;
};
const createSingleLoginLayer = getSingle(createLoginLayer);
const loginLayer1 = createSingleLoginLayer();
const loginLayer2 = createSingleLoginLayer();
alert(loginLayer1 === loginLayer2); // 輸出: true 

何時(shí)應(yīng)該分離職責(zé)

SRP 原則是所有原則中最簡(jiǎn)單也是最難正確運(yùn)用的原則之一。

要明確的是,并不是所有的職責(zé)都應(yīng)該一一分離。

一方面,如果隨著需求的變化,有兩個(gè)職責(zé)總是同時(shí)變化,那就不必分離他們。比如在 ajax 請(qǐng)求的時(shí)候,創(chuàng)建 xhr 對(duì)象和發(fā)送 xhr 請(qǐng)求幾乎總是在一起的,那么創(chuàng)建 xhr 對(duì)象的職責(zé)和發(fā)送 xhr 請(qǐng)求的職責(zé)就沒有必要分開。

另一方面,職責(zé)的變化軸線僅當(dāng)它們確定會(huì)發(fā)生變化時(shí)才具有意義,即使兩個(gè)職責(zé)已經(jīng)被耦合在一起,但它們還沒有發(fā)生改變的征兆,那么也許沒有必要主動(dòng)分離它們,在代碼需要重構(gòu)的時(shí)候再進(jìn)行分離也不遲。

違反 SRP 原則

在人的常規(guī)思維中,總是習(xí)慣性地把一組相關(guān)的行為放到一起,如何正確地分離職責(zé)不是一件容易的事情。

一方面,我們受設(shè)計(jì)原則的指導(dǎo),另一方面,我們未必要在任何時(shí)候都一成不變地遵守原則。在實(shí)際開發(fā)中,因?yàn)榉N種原因違反 SRP 的情況并不少見。比如 jQueryattr 等方法,就是明顯違反 SRP 原則的做法。jQueryattr 是個(gè)非常龐大的方法,既負(fù)責(zé)賦值,又負(fù)責(zé)取值,這對(duì)于 jQuery 的維護(hù)者來說,會(huì)帶來一些困難,但對(duì)于 jQuery 的用戶來說,卻簡(jiǎn)化了用戶的使用。

在方便性與穩(wěn)定性之間要有一些取舍。具體是選擇方便性還是穩(wěn)定性,并沒有標(biāo)準(zhǔn)答案,而是要取決于具體的應(yīng)用環(huán)境。

SRP 原則的優(yōu)缺點(diǎn)

SRP 原則的優(yōu)點(diǎn)是降低了單個(gè)類或者對(duì)象的復(fù)雜度,按照職責(zé)把對(duì)象分解成更小的粒度,這有助于代碼的復(fù)用,也有利于進(jìn)行單元測(cè)試。當(dāng)一個(gè)職責(zé)需要變更的時(shí)候,不會(huì)影響到其他的職責(zé)。

但 SRP 原則也有一些缺點(diǎn),最明顯的是會(huì)增加編寫代碼的復(fù)雜度。當(dāng)我們按照職責(zé)把對(duì)象分解成更小的粒度之后,實(shí)際上也增大了這些對(duì)象之間相互聯(lián)系的難度。

到此這篇關(guān)于JavaScript單一職責(zé)原則深入分析的文章就介紹到這了,更多相關(guān)JS單一職責(zé)原則內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

改则县| 宜川县| 扬中市| 昂仁县| 无锡市| 调兵山市| 墨竹工卡县| 东山县| 罗甸县| 股票| 黔南| 雅安市| 永平县| 洛隆县| 秦安县| 麻江县| 射洪县| 虹口区| 富宁县| 秭归县| 视频| 建始县| 宽甸| 临沧市| 盖州市| 建始县| 中江县| 泽库县| 新野县| 安阳市| 绥阳县| 新源县| 盐边县| 和田县| 合阳县| 梨树县| 涡阳县| 博爱县| 茌平县| 兰溪市| 湖北省|