CTRL + C and CTRL + V bring us a lot of convenience, but they also make us lazy and unwilling to think.

1. Introduction

I believe that many people are like me, when developing projects, because of the project rush, or temporarily unexpected reasons. The frequent use of CTRL + C and CTRL + V results in a lot of repetitive code. These days, I also looked at the code I wrote before, and briefly explored it. I selected several examples to share how to improve code reuse under the premise of ensuring code quality in specific scenarios.

Improve code reusability, should be different scenarios, different solutions. Also, make sure your code is good. It is not recommended to increase code reusability by force. If you increase code reusability, it will greatly reduce the readability and maintainability of the code, which may not be worth the loss.

2.HTML+CSS

When working on a project, I believe there will always be many similar buttons on the page. For example, there are several similar buttons on the project. Faced with such a requirement, the previous was to write three buttons directly

<button type="button" class='u-btn-yes-samll'</button> <buttontype="button" class='u-btn-yes'</button> <buttontype="button" class='u-btn-yes-big'> confirm < / button >Copy the code

css

button{
	border:none;
	font-family:Microsoft Yahei; 
}
.u-btn-yes{
	width:80px;
	height:36px;
	font-size:14px;
	color:#fff;
	border-radius:10px;
	background:#09f;
}
.u-btn-yes-samll{
	width:60px;
	height:30px;
	font-size:12px;
	color:#fff;
	border-radius:10px;
	background:#09f;
}
.u-btn-yes-big{
	width:100px;
	height:40px;
	font-size:16px;
	color:#fff;
	border-radius:10px;
	background:#09f;
}
Copy the code

This is equivalent to adding several lines of CSS code for each new button that actually changes only the width, height, and font-size properties.

You can actually reuse code based on size.

.u-btn-yes{
	width:80px;
	height:36px;
	font-size:14px;
	color:#fff;
	border-radius:10px;
	background:#09f;
}
.u-btn-yes.u-btn-samll{
	width:60px;
	height:30px;
	font-size:12px;
}
.u-btn-yes.u-btn-big{
	width:100px;
	height:40px;
	font-size:16px;
}
Copy the code

Page calls

<button type="button" class='u-btn-yes u-btn-samll'</button> <buttontype="button" class='u-btn-yes'</button> <buttontype="button" class='u-btn-yes u-btn-big'> confirm < / button >Copy the code

There may be many similar buttons on the page, but different colors (as shown below) can also be handled flexibly, so that they can be combined freely. This is also the approach used by many UI libraries in the community.

.u-btn{
	width:80px;
	height:36px;
	font-size:14px;
	color:#fff;
	border-radius:10px;
	background:#09f;
}
.u-btn-samll{
	width:60px;
	height:30px;
	font-size:12px;
}
.u-btn-big{
	width:100px;
	height:40px;
	font-size:16px;
}
.u-btn-red{
	background:#f33;
}
.u-btn-yellow{
    background:#f90;
}
Copy the code

html

<button type="button" class='u-btn u-btn-samll'</button> <buttontype="button" class='u-btn u-btn-red'</button> <buttontype="button" class='u-btn u-btn-big u-btn-yellow'> confirm < / button >Copy the code

For these buttons, it is not recommended to set margin, positon and other styles, because these attributes are basically different for different buttons in different places.

3.JavaScript

There are no obvious advantages to improving code reuse in the HTML+CSS example above, but there are obvious advantages to improving code reuse in JS. Here are a few examples.

3-1. Encapsulate common functions

In the last company’s project, there is such a code, the purpose is also obvious, that is, when the user fills in the form, has not completed the submission, the front here needs to give a simple prompt.

// A layer. Alert ('Please check if the information is complete',{
    title:'tip',
    icon:2
})  
Copy the code

Based on layer, an open source library, the code looks extremely simple. However, as the project develops and the user fills out the form in multiple places, the code above will be copied in multiple places, which will inevitably become a bit redundant.

Also, one of the biggest problems with this is that if the code above is used in 20 places on the project, one day the requirements change and the title property value changes from ‘prompt’ to ‘warning’. That’s a problem. You have to find 20 places, and even if the editor has global replacement, it’s more likely that something will go wrong. In the face of this situation. The previous approach is to encapsulate this popover in a simple and crude way for easy reuse.

function openTips(){// A layer.alert() will pop up when the information is not complete'Please check if the information is complete',{
        title:'tip',
        icon:2
    });
}
Copy the code

Just call it where you need it and when you need it, so you can write a lot less code! When you modify it, you only need to modify openTips.

openTips();
Copy the code

3-2. Use policy mode instead of Switch

Let’s look at another example. I borrowed the code from the group.

Simulated data

let listWarnConf = [
    {
    	warnType: 1,
    	warnCondition: 220,
    },
    {
    	warnType: 2,
    	warnCondition: 36,
    },
    {
    	warnType: 3,
    	warnCondition: 45,
    },
    {
    	warnType: 4,
    	warnCondition: 110,
    },
    {
    	warnType: 5,
    	warnCondition: 380,
    }
]
Copy the code

Business logic code

listWarnConf.forEach(item => {
    switch(item.warnType) {
    	case 1:
    		item.warnTypeText = 'the overpressure'; Item. warnConditionText = 'Voltage is higher than${item.warnCondition}V`
    		break;
    	case 2:
    		item.warnTypeText = 'under-voltage'; Item. warnConditionText = 'Voltage is below${item.warnCondition}V`
    		break
    	case 3:
    		item.warnTypeText = 'overload'; Item. warnConditionText = 'Current higher than${item.warnCondition}A`
    		break
    	case 4:
    		item.warnTypeText = 'Voltage unbalance'; Item. warnConditionText = 'Voltage imbalance higher than${item.warnCondition}% `break
    	case 5:
    		item.warnTypeText = 'Current imbalance'; Item. warnConditionText = 'Current imbalance${item.warnCondition}% `break}})Copy the code

It’s okay to look at the result that way, but look at so many cases where you’re doing assignments. And the biggest problem is the same as above. If you use it in multiple places and the requirements change, you still have to modify so many places. Let’s optimize the code to improve the reusability.

// Set the configuration datalet warnConfig={
	1:{
		warnTypeText:'the overpressure',
		warnConditionText:'Voltage higher than replaceTextV'
	},
	2:{
		warnTypeText:'under-voltage',
		warnConditionText:'Voltage below replaceTextV'
	},
	3:{
		warnTypeText:'overload',
		warnConditionText:'Current higher than replaceTextV'
	},
	4:{
		warnTypeText:'Voltage unbalance',
		warnConditionText:'Voltage imbalance higher than replaceText%'
	},
	5:{
		warnTypeText:'Current imbalance',
		warnConditionText:'Current imbalance higher than replaceText%'}} / / business logic, according to the configuration data set warnTypeText and warnConditionText listWarnConf. ForEach (item = > { item.warnTypeText=warnConfig[item.warnType].warnTypeText; item.warnConditionText=warnConfig[item.warnType].warnConditionText.replace('replaceText',item.warnCondition);
})
Copy the code

This change code is not reduced, the readability is worse than switch, but can be read. However, in this way, there is less duplicate code and the configuration data and business logic are separated. If you need to change the configuration data or business logic later, you can change either of them without affecting each other. Pull the configuration data out for public use, so you can change it when you need to.

In terms of improving code reusability, or reducing duplicate code, I think we can work towards the goal of not changing the same code twice when requirements change.

3-3. Keep functions single and flexible

Keeping functions to a single responsibility and ensuring that a function performs only one action, each of which does not affect each other, can be freely combined to improve code reuse.

For example, in the following code, the order data is requested from the server as follows, and the following processing is required: 1. The corresponding value is displayed according to status (0- in progress, 1- completed, 2- Abnormal order) 2. Display startTime as YYYY-MM-DD 3 by timestamp. If the field value is an empty string, set the field value to ‘–‘

let orderList=[
    {
        id:1,
        status:0,
        startTime:1538323200000,
    },
    {
        id:2,
        status:2,
        startTime:1538523200000,
    },
    {
        id:3,
        status:1,
        startTime:1538723200000,
    },
    {
        id:4,
        status:' ',
        startTime:' ',},];Copy the code

The requirements seem simple and the code is minimal

let _status={
	0:'in progress',
	1:'Done',
	2:'Abnormal order'} orderList.foreach (item=>{// set the status item.status= item.status.tostring ()? _status[item.status]:' '; Item.starttime = item.starttime.tostring ()? new Date(item.startTime).toLocaleDateString().replace(/\//g,The '-') :' '; / / set -for(let key in item){
        if(item[key]===' '){
            item[key]=The '-'; }}})Copy the code

For example, another group of user data requested by the server does not have two fields: status and startTime, and the user identity (0-ordinary user, 1-VIP, 2-super VIP) needs to be displayed according to type.

let userList=[
	{
		id:1,
		name:'wait'.type:0
	},
	{
		id:2,
		name:'All over the world'.type:1
	},
	{
		id:3,
		name:'once'.type: 2}]Copy the code

When the need arises, the code written before cannot be reused, but must be copied and modified.

let _type={
	0:'Ordinary user',
	1:'vip',
	2:'super VIP'} userlist. forEach(item=>{// settypeitem.type=item.type.toString()? _type[item.type]:' '; / / set -for(let key in item){
        if(item[key]===' '){
            item[key]=The '-'; }}})Copy the code

It turns out to be fine, and I think you’ve already seen the problem, because the code is a little bit redundant. Now modify the action function using the single responsibility principle, setting status, startTime, type, –. I’m going to break it down into four functions.

let handleFn={
	setStatus(list){
		let _status={
			0:'in progress',
			1:'Done',
			2:'Abnormal order'} list.forEach(item=>{ item.status=item.status.toString()? _status[item.status]:' ';
		})
		return list
	},
	setStartTime(list){ list.forEach(item=>{ item.startTime=item.startTime.toString()? new Date(item.startTime).toLocaleDateString().replace(/\//g,The '-') :' ';
		})
		return list;
	},
	setInfo(list){
		list.forEach(item=>{
			for(let key in item){
		        if(item[key]===' '){
		            item[key]=The '-'; }}})return list;
	},
	setType(list){
		let _type={
			0:'Ordinary user',
			1:'vip',
			2:'super VIP'} list.forEach(item=>{ item.type=item.type.toString()? _type[item.type]:' ';
		})
		returnlist; }}Copy the code

So let’s just call the function

OrderList = handlefn.setStatus (orderList); orderList=handleFn.setStartTime(orderList); orderList=handleFn.setInfo(orderList); console.log(orderList); // Handle user data userList= handlefn.setType (userList); userList=handleFn.setInfo(userList); console.log(userList);Copy the code

The operation results are also normal

If you don’t like the hassle of continuous assignment, you can borrow the jQuery idea and make chain calls.

let ec=(function () {
    let handle=function(obj) {// Deep copy object this.obj= json.parse (json.stringify (obj)); }; Prototype ={/** * @description set confidential information */setInfo(){
            this.obj.map(item=>{
                for(let key in item){
                    if(item[key]===' '){
                        item[key]=The '-'; }}});returnthis; }, /** * @description set state */setStatus() {let _status={
       			0:'in progress',
       			1:'Done',
       			2:'Abnormal order'} this.obj.forEach(item=>{ item.status=item.status.toString()? _status[item.status]:' '
            });
            returnthis; }, /** * @description set time */setStartTime(){ this.obj.forEach(item=>{ item.startTime=item.startTime.toString()? new Date(item.startTime).toLocaleDateString().replace(/\//g,The '-') :' ';
            });
            returnthis; }, /** * @description Settingstype* /setType() {let _type={
				0:'Ordinary user',
				1:'vip',
				2:'super VIP'} this.obj.forEach(item=>{ item.type=item.type.toString()? _type[item.type]:' ';
			})
			returnthis; }, /** * @description returns the result * @return {Array|*}
         */
        end() {returnthis.obj; }} // Expose the constructor interfacereturn function (obj) {
        return new handle(obj);
    }
})();
Copy the code

So you can chain it

OrderList =ec(orderList).setStatus().setStartTime().setInfo().end(); console.log(orderList); UserList =ec(userList).setType().end(); console.log(userList);Copy the code

So with that out of the way, I think you’ve noticed a very serious problem is that the number of cycles has increased. Before optimization, you could just loop once, set the state, set the time, set — all of that, but now setStatus().setStartTime().setinfo (), this code here, every time it executes a function, it’s iterating through the array, so you need to optimize this. The way to do that is to record what is being processed in each function, but not processed, and then processed at end and returned.

let ec=(function () {
    let handle=function(obj) {// Deep copy object this.obj= json.parse (json.stringify (obj)); This.handlefnlist =[]; }; HandleSetInfo (item){handleSetInfo(item);for(let key in item){
                if(item[key]===' '){
                    item[key]=The '-'; }}return this;
        },
        setInfo(){
			this.handleFnList.push('handleSetInfo');
			returnthis; }, /** * @description set status */ handleSetStatus(item){let _status={
       			0:'in progress',
       			1:'Done',
       			2:'Abnormal order'} item.status=item.status.toString()? _status[item.status]:' '
            return item;
       	},
       	setStatus(){
			this.handleFnList.push('handleSetStatus');
			returnthis; }, /** * @description set time */ handleSetStartTime(item){item.startTime= item.starttime.tostring ()? new Date(item.startTime).toLocaleDateString().replace(/\//g,The '-') :' ';
            return item;
       	},
       	setStartTime(){
			this.handleFnList.push('handleSetStartTime');
			returnthis; }, /** * @description Settingstype
         */
       	handleSetType(item){
			let _type={
				0:'Ordinary user',
				1:'vip',
				2:'super VIP'} item.type=item.type.toString()? _type[item.type]:' ';
			return item;
		},
		setType(){
			this.handleFnList.push('handleSetType');
			returnthis; }, /** * @description returns the result * @return {Array|*}
         */
        end() {/ / unified handling this operation. The obj. ForEach (item = > {this. HandleFnList. ForEach (fn = > {item = this [fn] (item); })})returnthis.obj; }} // Expose the constructor interfacereturn function (obj) {
        return new handle(obj);
    }
})();
Copy the code

This way, the previous call does not need to change, and then the result is correct

You might think it’s a simple requirement, but it’s complicated. If so, it is correct, because it is indeed complicated and not readable, but the project encountered more data processing, such as the format display of the amount, various status code parsing display of other data, bank card number divided by four digits, phone number display and so on. So just encapsulate it and use it when you use it. I don’t know if it counts as sweet after bitter? If the requirements are simple, there may be no need for such encapsulation.

4. Summary

That’s about it. There are some examples, but I’ve written about them before and I won’t mention them again. Improving code reuse is a big topic, if you have any good suggestions, examples, welcome to share.

— — — — — — — — — — — — — — — — — — — — — — — — — gorgeous line — — — — — — — — — — — — — — — — — — — —

If you want to know more, communicate with me and promote your position, please add me on wechat. Or follow my wechat public number: Waiting book Pavilion