亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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é)往頁(yè)面中添加 img 標(biāo)簽,這也是它最原始的職責(zé)。

myImage 負(fù)責(zé)往頁(yè)面中添加 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è)集合,然后往頁(yè)面中添加一些 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ù),然后在頁(yè)面中渲染節(jié)點(diǎn)。

appendDiv 函數(shù)本來(lái)只是負(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)致不能順利往頁(yè)面中添加 div 節(jié)點(diǎn)。

我們有必要把遍歷 data 的職責(zé)提取出來(lái),這正是迭代器模式的意義,迭代器模式提供了一種方法來(lái)訪問聚合對(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ù)者來(lái)說,會(huì)帶來(lái)一些困難,但對(duì)于 jQuery 的用戶來(lái)說,卻簡(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)文章

  • JavaScript制作簡(jiǎn)單分頁(yè)插件

    JavaScript制作簡(jiǎn)單分頁(yè)插件

    本文給大家分享的是JavaScript制作的一個(gè)兼容IE6+以及主流瀏覽器的分頁(yè)插件,非常的不錯(cuò),有需要的小伙伴可以參考下
    2016-09-09
  • JavaScript隱式類型轉(zhuǎn)換

    JavaScript隱式類型轉(zhuǎn)換

    JavaScript的數(shù)據(jù)類型是非常弱的(不然不會(huì)叫它做弱類型語(yǔ)言了)!在使用算術(shù)運(yùn)算符時(shí),運(yùn)算符兩邊的數(shù)據(jù)類型可以是任意的,比如,一個(gè)字符串可以和數(shù)字相加
    2016-03-03
  • HTML的select控件美化

    HTML的select控件美化

    本文主要介紹了HTML的select控件美化以及js實(shí)現(xiàn)select選擇功能的方法步驟。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-03-03
  • Javascript自定義函數(shù)判斷網(wǎng)站訪問類型是PC還是移動(dòng)終端

    Javascript自定義函數(shù)判斷網(wǎng)站訪問類型是PC還是移動(dòng)終端

    如果,能夠判斷出訪問Web網(wǎng)頁(yè)的類型(PC還是移動(dòng)終端)。就可以解決許多絢麗多彩的 Flash效果出不來(lái)的問題
    2014-01-01
  • UNiAPP中如何使用render.js繪制高德地圖

    UNiAPP中如何使用render.js繪制高德地圖

    這篇文章主要介紹了UNiAPP中如何使用render.js繪制高德地圖,renderjs是一個(gè)運(yùn)行在視圖層的js。它比WXS更加強(qiáng)大。它只支持app-vue和h5,文中給大家提到了renderjs的主要作用,需要的朋友可以參考下
    2022-05-05
  • 使用uniapp實(shí)現(xiàn)發(fā)布朋友圈功能

    使用uniapp實(shí)現(xiàn)發(fā)布朋友圈功能

    這篇文章主要介紹了使用uniapp實(shí)現(xiàn)發(fā)布朋友圈功能,在文章底部給大家介紹了uniapp?微信小程序分享、分享朋友圈功能,通過頁(yè)內(nèi)自定義分享按鈕,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 個(gè)人總結(jié)的一些JavaScript技巧、實(shí)用函數(shù)、簡(jiǎn)潔方法、編程細(xì)節(jié)

    個(gè)人總結(jié)的一些JavaScript技巧、實(shí)用函數(shù)、簡(jiǎn)潔方法、編程細(xì)節(jié)

    這篇文章主要介紹了個(gè)人總結(jié)的一些JavaScript技巧、實(shí)用函數(shù)、簡(jiǎn)潔方法、編程細(xì)節(jié),本文講解了變量轉(zhuǎn)換、取整同時(shí)轉(zhuǎn)換成數(shù)值型、日期轉(zhuǎn)數(shù)值、類數(shù)組對(duì)象轉(zhuǎn)數(shù)組、進(jìn)制之間的轉(zhuǎn)換等方法技巧,需要的朋友可以參考下
    2015-06-06
  • JavaScript函數(shù)之call、apply以及bind方法案例詳解

    JavaScript函數(shù)之call、apply以及bind方法案例詳解

    這篇文章主要介紹了JavaScript函數(shù)之call、apply以及bind方法案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • JS生成隨機(jī)打亂數(shù)組的方法示例

    JS生成隨機(jī)打亂數(shù)組的方法示例

    這篇文章主要介紹了JS生成隨機(jī)打亂數(shù)組的方法,涉及javascript數(shù)組隨機(jī)排序的相關(guān)操作技巧,需要的朋友可以參考下
    2017-12-12
  • JavaScript使用cookie

    JavaScript使用cookie

    JavaScript使用cookie...
    2007-02-02

最新評(píng)論