Js concise code preparation and skills refer to north

If level nesting optimization

The following three layers of if conditions are nested

function froutCheck(fruit, quantity) { const redFruits = ['apple', 'pear', 'cherry', 'banana']; If (redfruits.includes (fruit)) {console.log(' red fruit '); If (quantity > 10) {console.log(' quantity > 10 '); }}} else {throw new Error(' No fruit! '); }}Copy the code

The logic is much clearer and easier to maintain when written with a “deal early, return early” rule

function supply(fruit, quantity) { const redFruits = ['apple', 'pear', 'cherry', 'banana']; if(! Fruit) throw new Error(' No fruit '); // Condition 1: Handle the error if(! redFruits.includes(fruit)) return; // Condition 2: Return console.log(' red fruit ') early if not red fruit; If (quantity > 10) {console.log(' quantity > 10 '); }}Copy the code

An Array of use

Array.includes Determines multiple IF conditions

You can store multiple values in an array, using the array include method.

//Longhand
if (x === 'abc' || x === 'def' || x === 'ghi' || x ==='jkl') {
  //logic
}

//Shorthand
if (['abc', 'def', 'ghi', 'jkl'].includes(x)) {
  //logic
}
Copy the code

Array.find Finds the Array elements that match the criteria

The find method is really useful when we do have an array of objects and we want to look up specific objects based on object properties.

const data = [
  {
    type: 'test1',
    name: 'abc'
  },
  {
    type: 'test2',
    name: 'cde'
  },
  {
    type: 'test1',
    name: 'fgh'
  },
]
function findtest1(name) {
  for (let i = 0; i < data.length; ++i) {
    if (data[i].type === 'test1' && data[i].name === name) {
      return data[i];
    }
  }
}

//Shorthand
filteredData = data.find(data => data.type === 'test1' && data.name === 'fgh');
console.log(filteredData); // { type: 'test1', name: 'fgh' }
Copy the code

All items in the array satisfy some condition:Array.every

Does any of the items in the array satisfy the condition:Array.some

Find, array. slice, array. findIndex, array. reduce, and array. splice can be used as required in actual scenarios.

Short for truth value judgment

// Longhand if (tmp === true) or if (tmp ! == "") or if (tmp ! == null) // Shorthand //it will check empty string,null and undefined too if (test1)Copy the code

Note: this method is mainly used for null or undefined checks, ** especially note that TMP =0 or TMP = ‘0’ ** are false.

The multi-conditional && operator

The && operator can be used if the function is called only if the variable is true.

//Longhand
if (test1) {
 callMethod();
}

//Shorthand
test1 && callMethod();
Copy the code

Ternary operators implement short function calls

We can use ternary operators to implement direct execution of functions.

// Longhand
function test1() {
  console.log('test1');
};
function test2() {
  console.log('test2');
};
var test3 = 1;
if (test3 == 1) {
  test1();
} else {
  test2();
}

// Shorthand
(test3 === 1? test1:test2)();
Copy the code

Short for object property deconstruction

let test1 = 'a';
let test2 = 'b';

//Longhand
let obj = {test1: test1, test2: test2};

//Shorthand
let obj = {test1, test2};
Copy the code

It is better to compare sizes using a – b > 0A > b sometimes makes an error

Error: '20' > '100' // true Expected result '20' - '100' > 0 // falseCopy the code

If, for… In the for… Use of and

1. Use ternary operators whenever possible to reduce if nesting

2. Reduce the redundant condition judgment, query end immediately return ** (early return, return more) **, if the function returns if inside and outside the same data type

3. If… Else if… Else Ends with else when multiple conditions are met because of defensive programming rules

NaN should not be used for comparison.NaN should be used to determine if it is a number

5. The Switch… Case is used when there are at least three judgment values,case cannot be omitted, each case must be broken out

6. The for… Of traverses arrays and strings

7. The for… In traverses the object

The For… The in traversal object includes all inherited properties, so you need to make a judgment call if you only want to use properties of the object itself

8. Declare functions inside a loop with caution, because the call will not execute until the loop completes

9. Don’t write code after Return

If multi-conditional judgment

The “Return early, return often” statement is used to handle exceptions on the main path

Consider the find function below.

function find(predicate, arr) { for (let item of arr) { if (predicate(item)) { return item; }}}Copy the code

In this find function, as soon as we find the object we want to look for, we return it and exit the loop. This makes our code much more efficient.

Switch Statement optimization

Low level: Too easy to forget to write break

let notificationPtrn;
switch (notification.type) {
    case 'citation':
        notificationPtrn = 'You received a citation from {{actingUser}}.';
        break;
    case 'follow':
        notificationPtrn = '{{actingUser}} started following your work';
        break;
    case 'mention':
        notificationPtrn = '{{actingUser}} mentioned you in a post.';
        break;
    default:
        // Well, this should never happen
}
Copy the code

Optimization 1: Use return

function getnotificationPtrn(n) {
        switch (n.type) {
            case 'citation':
                return 'You received a citation from {{actingUser}}.';
            case 'follow':
                return '{{actingUser}} started following your work';
            case 'mention':
                return '{{actingUser}} mentioned you in a post.';
            default:
                throw new Error('You’ve received some sort of notification we don’t know about.';
        }
    }
    let notificationPtrn = getNotificationPtrn(notification);
Copy the code

Optimization 2: Use object dictionaries

function getNotificationPtrn(n) {
    const textOptions = {
        citation: 'You received a citation from {{actingUser}}.',
        follow:   '{{actingUser}} started following your work',
        mention:  '{{actingUser}} mentioned you in a post.',
    }
    return textOptions[n.type];
}
Copy the code

Optimize three (recommended) similar pattern matching methods

const textOptions = {
    citation: 'You received a citation from {{actingUser}}.',
    follow:   '{{actingUser}} started following your work',
    mention:  '{{actingUser}} mentioned you in a post.',
}
function getNotificationPtrn(textOptions, n) {
    return textOptions[n.type];
}
const notificationPtrn = getNotificationPtrn(textOptions, notification);
Copy the code

If unknown processing is involved, we can also take the default information as an argument

ConstdefaultTxt = 'You've received some sort of notification we don't know about.'; / / the default function getNotificationPtrn (defaultTxt textOptions, n) {return textOptions [n.t ype] | | defaultTxt; } const notificationPtrn = getNotificationPtrn(defaultTxt, textOptions, notification.type);Copy the code

Now textOptions is a variable. And the variable is no longer hard-coded. We can either move it to a JSON configuration file or get the variable from the server. Now we can do whatever we want with the textOptions. We can add new options or remove options. We can also combine options from multiple places.

A [0]. B undefined problem

In development, chain value is a very normal operation, such as:

res.data.goods.list[0].price
Copy the code

But for this type of operation, something like Uncaught TypeError is reported: Cannot read property ‘goods’ of undefined. If the res data is self-defined, it is more controllable, but if the data comes from different ends (such as the front and back ends), So this kind of data is not controllable for us, so in order to ensure the normal operation of the program, we need to check it:

If (res.data.goods.list[0] && res.data.goods.list[0].price) {// your code} if (res.data.goods.list[0].price) {// Your code} if (res.data.goods.list[0].price) {// Your code} if (res.data.goods.list[0].price) {// Your code} if (res && res.data && res.data.goods && res.data.goods.list && res.data.goods.list[0] && res.data.goods.list[0].price){  // your code }Copy the code

I can’t imagine what would happen if the data were a little bit more hierarchical, and this implementation would be really inelegant, but what if I could do it elegantly?

Parsing a string using a function (lodash’s _.get method)

We can through the function to parse the string to solve this problem, this implementation is lodash _. The get method (www.lodashjs.com/docs/4.17.5)…

Get (object, path, [defaultValue]) Var object = {a: [{b: {c: 3}}]}; var result = _.get(object, 'a[0].b.c', 1); console.log(result); // output: 3 the source code to implement this method is also very simple, just a simple string parsing: function get (obj, props, def) {if ((obj = = null) | | obj = = null | | typeof props! == 'string') return def; const temp = props.split('.'); const fieldArr = [].concat(temp); temp.forEach((e, i) => { if(/^(\w+)\[(\w+)\]$/.test(e)) { const matchs = e.match(/^(\w+)\[(\w+)\]$/); const field1 = matchs[1]; const field2 = matchs[2]; const index = fieldArr.indexOf(e); fieldArr.splice(index, 1, field1, field2); } }) return fieldArr.reduce((pre, cur) => { const target = pre[cur] || def; if(target instanceof Array) { return [].concat(target); } if(target instanceof Object) { return Object.assign({}, target) } return target; }}, obj) / / using var c = {a: {b: [1, 2, 3]}} _get (c, 'a.') / / [1, 2, 3] _get (c, 'a. [1]') / / 2 _get (c, 'a. d., 12) / / 12Copy the code

In fact, similar problems written in typescript are handled during static checking to avoid such silly errors

Method two, use destruct assignment

Underscore this idea comes from a github repository called you-dont-need-lodash-underscore that I really appreciate

The downside: not very readable

Const obj = {a: {b: [1, 2, 3, 4]}, a1:121, a2: 'name'} let {a: result} = obj / / result: {b: [1, 2, 3, 4]} let {a1: Result} = obj // result: 121 let {b: result} = obj // result: 121 let {b: result} = obj // result: 121 result = 'default'} = obj // result: 'default'Copy the code

Method 3: Use Proxy

function pointer(obj, path = []) { return new Proxy(() => {}, { get (target, property) { return pointer(obj, path.concat(property)) }, apply (target, self, args) { let val = obj; let parent; for(let i = 0; i < path.length; i++) { if(val === null || val === undefined) break; parent = val; val = val[path[i]] } if(val === null || val === undefined) { val = args[0] } return val; }}}) method of use: var c = {a: {b: [1, 2, 3]}} pointer (c) a (); : / / {b} [1, 2, 3] pointer (c). A. (); / / [1, 2, 3] pointer (d) A.B.D (' default value '); // default valueCopy the code

The first argument to new Proxy() is an arrow function, which is mostly an object

YanXun

You don’t understand how Proxy works. If Proxy is an object, the following apply function will not be executed because Proxy needs to perform the behavior of Proxy functions to execute the apply function, so you must pass an arrow function

Type cast

###string cast to a number

You can use *1 (multiplied by 1) to convert to a Number (actually calling the.valueof method) and then use number.isnan to determine if it is a NaN, or use a! == a to determine if it is NaN, because NaN! == NaN

'32' * 1            // 32
'ds' * 1            // NaN
null * 1            // 0
undefined * 1    // NaN
1  * { valueOf: ()=>'3' }        // 3
Copy the code

Common: You can also use + to convert a string to a number

+ '123'            // 123
+ 'ds'               // NaN
+ ''                    // 0
+ null              // 0
+ undefined    // NaN
+ { valueOf: ()=>'3' }    // 3
Copy the code

The “+ -” sign stunt

A numeric string can be converted to a number with +, but it must be combined with isNaN(), which checks to see if its arguments are non-numbers or true if they are not

Basic knowledge of the let a = "2", b = '20', c = 34, d = '2' = 18 c - a - b d = a + b = 32 "220" a + c = "234" isNaN (' AD ') / / true isNaN (' 22 ') / / False SAO operation + (' ab ') / / NaN 22 + + (' 22 ') / / (22) / / 22 let a = 1, B ='2' let c = a + +(b) //3 example // Select the minimum function as follows: areg){ return ! isNaN(val) && ! isNaN(areg) && +(val)>= +(areg) }Copy the code

Use filter to filter all false values in the array

We know that there are some false values in JS: false, null, 0, “”, undefined, NaN. How to filter the false values in array quickly

const compact = arr => arr.filter(Boolean)
compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34])             // [ 1, 2, 3, 'a', 's', 34 ]
​```
Copy the code

Small symbol effect

The two-bit operator ~~ implements round down

You can use the two-bit operator instead of math.floor (). The advantage of the double-negated operator is that it performs the same operation faster.

Math.floor (x) returns the largest integer less than the argument x, which is rounded down on a floating point number

Math. Floor (4.9) = = = 4 / / true / / for short: ~ ~ 4.9 = = = 4 / / true ` ` `Copy the code

Note, however, that for negative numbers ~~ does not give the same result as math.floor () :

` ` ` ~ ~ 4.5 / / 4 math.h floor (4.5) / / 4 ~ ~ 4.5 / / - 4 Math. Floor (4.5) / / - 5 ` ` `Copy the code

Short-circuit operator, &&, | |

| | assign default values

let test1 = null, test2 = test1 || '6'; console.log(test2); // Output "6"Copy the code

We know that logic and && and | or logical | is short-circuit operator, short-circuit operator is from left to right in the operation which meet the requirements, no longer perform the latter; It can be understood as:

  • && for false operation, judging from left to right, if encountered a false value, return false value, no longer execute, otherwise return the last true value
  • | | to take real operations, judging from left to right in turn, if you meet a true value, and then return true, later no longer perform, otherwise returns a false value finally
let param1 = expr1 && expr2
let param2 = expr1 || expr2
​```
Copy the code
The operator The sample instructions
&& expr1&&expr2 Return expr1 if expr1 can be converted to false, expr2 otherwise. Therefore, when used in Boolean environments, it returns true if both operations result in true, and false otherwise.
|| expr1||expr2 Return expr1 if expr1 can be converted to true, expr2 otherwise. Therefore, when used in Boolean environments (in if conditionals), return true as long as either operation is true; Return false if both operations result in false.
! ! expr Return false if a single expression can be converted to true, true otherwise.

It can therefore be used to do many interesting things, such as assigning initial values to variables:

let variable1
let variable2 = variable1  || 'foo'
Copy the code

If variable1 is true, it returns directly, and subsequent short-circuits are not returned; if false, foo is returned.

Can also be used for simple judgments instead of lengthy if statements:

let variable = param && param.prop
Copy the code

Return param.prop if param is true, false otherwise. This prevents an error in some places when param is undefined.

But should pay attention to the following example if the data is zero (or an empty string is returned data), at the moment with | | operators will wrong, returns the default value:

// let res = {data: 0, // background return status code (0 indicates non-existence, 1 indicates existence) code: 200} let val = res. Data | | 'to' the console. The log (val) / / 'no data', actually we need the value of the dataCopy the code

Integer | 0

For a digital | 0 can be integer, negative number also applies, num | 0

1.3 | 1-1.9 | 0 0 / / / / - 1 ` ` `Copy the code

Judge the odd even & 1

A numeral & 1 can be odd or even, and a negative numeral, num & 1

const num=3; !!!!! (num & 1) // true !! (num % 2) // true ```Copy the code

function

Function defaults

func = (x, m = 3, n = 4 ) => (x * m * n); Func (2) //output: 24 func(null) //output: 12 because 1*null = 0Copy the code

Note that the default argument will be used if the argument is undefined or not passed, and will be overridden even if null is passed.

To this point and x = params | | ‘2’, there is a difference between | | is params = = false value of time

Mandatory parameter, error if missing

By default, JS sets function parameters to undefined if no value is passed to them. Others issue warnings or errors. To perform parameter assignment, you can use an if statement to throw an undefined error, or you can use mandatory parameters.

logError = ( ) => { throw new Error('Missing parameter! '); } foo = (bar = logError()) => {foo = (bar = logError()) => {foo = (bar = logError()); }Copy the code

The arrow function implicitly returns a value

The return value is the keyword we normally use to return the final result of a function. A one-statement arrow function that implicitly returns the result (the function must omit the curly braces {} to omit the return keyword).

To return multiline statements (such as object text), use () instead of {} to wrap the function body. This ensures that the code is evaluated as a single statement.

Function calcCircumference(diameter) {return Math.  calcCircumference = diameter => ( Math.PI * diameter; )Copy the code

Lazy loading function

In a scenario where we have a judgment statement in our function, the judgment statement generally does not change throughout the project, so the judgment that the branch will only run a particular branch throughout the project can be considered lazy loading functions

/ / lower version

function foo(){ if(a ! == b){console.log('aaa')}else{console.log(' BBB ')}} function foo(){if(a! = b){ foo = function(){ console.log('aaa') } }else{ foo = function(){ console.log('bbb') } } return foo(); }Copy the code

The method will be overwritten after the first run, and no judgment will be performed on the next run. Of course, now there is only one judgment, if there are many judgments, branches are complicated, then the savings are considerable.

### one-time function

As with the lazy loading function above, you can overwrite the current function in the function body, so you can create a one-time function. The code before reassignment is run only once, suitable for running some initialization code that only needs to be executed once

var sca = function() {
    console.log('msg')
    sca = function() {
        console.log('foo')
    }
}
sca()        // msg
sca()        // foo
sca()        // foo
Copy the code

string

Join () instead of using + or += to join longer strings

You should use arrays to hold string fragments, calling the Join method when you use them. Avoid concatenating long strings with + or +=; each string uses a small memory fragment; too many memory fragments can affect performance

Time string comparison (time form note complement 0)

To compare chronological order, use a string:

var a = "2014-08-08"; var b = "2014-09-09"; console.log(a>b, a<b); // false true console.log("21:00"<"09:10"); // false console.log("21:00"<"9:10"); // true time form note complement 0Copy the code

Because the string comparison size is based on the charCode of each character from left to right of the string, you have to pay special attention to the time form and pay attention to the complement 0

digital

Different base notation

ES6 has added different base writing formats. Note this when passing parameters in the background.

29 // 10 base 035 // 8 base 29 Original mode 0O35 // 8 base 29 ES6 mode 0x1D // 16 base 29 0B11101 // 2 base 29Copy the code

A decimal number accurate to a specified number of digits

Rounds a number to the specified decimal number. Round numbers to the specified decimal number using math.round () and template literals. Omit the second parameter decimals, and the number is rounded to an integer.

Const round = (n, decimals = 0) = > Number (` ${math.h round (` $${decimals} {n} e `)} e - ${decimals} `) round (1.345, 1) // 1.35 Number(1.345e2e-2) round(1.345, 1) // 1.3 // here E2 means multiplied by 10 ^ 2 1.23E1 //12.3 1.23e2 // 123 123.45E-2 // 1.2345 ' 'Copy the code

Digit complement 0 operation

For example, when displaying the time, it is necessary to replace one digit with two digits. In this case, you can use the slice and string padStart methods to add zeros

Const addZero1 = (num, len = 2) => (' 0${num} '). Slice (-len) const addzeroo2 = (num, len = 2) len = 2) => (`${num}`).padStart( len , AddZero1 (3) // 03 addZero2(32,4) // 0032 The resulting string can be concatenated with len zeros and then truncated with len stringsCopy the code

# # array

Count the number of identical items in an array

A lot of times, you want to count the number of duplicate items in the array and represent them as an object. Then you can use the reduce method to process this array.

The following code will count the number of vehicles of each type and represent the total as an object.

var cars = ['BMW','Benz', 'Benz', 'Tesla', 'BMW', 'Toyota']; var carsObj = cars.reduce(function (obj, name) { obj[name] = obj[name] ? ++obj[name] : 1; // obj[name] return obj; }, {}); carsObj; // => { BMW: 2, Benz: 2, Tesla: 1, Toyota: 1 }Copy the code

Exchange parameter value

Sometimes you will put multiple values returned by a function in an array. We can use array deconstruction to get each of these values.

let param1 = 1;
let param2 = 2;
[param1, param2] = [param2, param1];
console.log(param1) // 2
console.log(param2) // 1
Copy the code

Of course, we have a number of other ways to swap values:

var temp = a; a = b; b = temp            
b = [a, a = b][0]                     
a = a + b; b = a - b; a = a - b        
​```
Copy the code

Receiving multiple requests in batches returns results

In the code below, we get a post from /post and the associated comments from/Comments. Since we are using async/await, the function puts the return value in an array. By using array deconstruction, we can assign the return value directly to the corresponding variable.

async function getFullPost(){
  return await Promise.all([
     fetch('/post'),
     fetch('/comments')
  ]);
}
const [post, comments] = getFullPost();
Copy the code

Tiling an array to the specified depth

  • Basically, you can use the **[].flat()** method to flatten a single layer array, as shown below
let a1 = [{a:1},{a:2},[{a:3},{a:4},[{a:5}]]]
a1.flat()  // [{a:1},{a:2},{a:3},{a:4},[{a:5}]]
Copy the code
  • Using recursion, depth is decreased by 1 for each depth level. Use array.reduce () and array.concat () to merge elements or arrays. In the basic case, depth is 1 to stop the recursion. Omit the second argument, depth can only be tiled to a depth of 1 (single tile).
const flatten = (arr, depth = 1) => depth ! = 1? arr.reduce((a, v) => a.concat(Array.isArray(v) ? flatten(v, depth - 1) : v), []) : arr.reduce((a, v) => a.concat(v), []); flatten([1, [2], 3, 4]); // [1, 2, 3, 4] flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8] ' 'Copy the code

Object deconstruction of an array

Arrays can also be object destructed, which makes it easy to get the NTH value of an array

const csvFileLine = '1997,John Doe,US,[email protected],New York';
const { 2: country, 4: state } = csvFileLine.split(',');
 
country            // US
state            // New Yourk
Copy the code

The object array looks for the maximum value by a property

Var array = [{" index_id: "119," area_id ":" 18335623 ", "name" : "satisfaction", "value" : "100"}, {" index_id: "119," area_id ": "18335624", "name" : "satisfaction", "value" : "20"}, {" index_id: "119," area_id ":" 18335625 ", "name" : "satisfaction", "value" : "80"}); Math.max.apply(Math, array.map(function(o) {return O.value})) returns the maximum value of the array value attribute 100.Copy the code

Math.min.apply(Math, array.map(function(o) {return O.value}))) is more convenient than the for loop.

object

Use deconstruction to delete an object property

Sometimes you don’t want to keep certain object properties, perhaps because they contain sensitive information or are simply too large. You might enumerate the entire object and then delete it, but in reality you simply assign the useless attributes to the variable and leave the useful parts you want to keep as the remaining parameters.

In the following code, we want to remove the _internal and tooBig arguments. We can assign them to internal and tooBig variables and store the remaining properties in cleanObject for later use.

let {_internal, tooBig, ... cleanObject} = {el1: '1', _internal:"secret", tooBig:{}, el2: '2', el3: '3'}; console.log(cleanObject); // {el1: '1', el2: '2', el3: '3'}Copy the code

Deconstruct the nested object properties

In the following code, engine is an object nested within the object CAR. If we are interested in the Vin attribute of engine, we can easily get it using deconstructed assignment.

var car = {
  model: 'bmw 2018',
  engine: {
    v6: true,
    turbo: true,
    vin: 12345
  }
}
const modelAndVIN = ({model, engine: {vin}}) => {
  console.log(`model: ${model} vin: ${vin}`);
}
modelAndVIN(car); // => model: bmw 2018  vin: 12345
Copy the code

Code reuse

Object [key]

While it is common practice to write foo.bar as foo [‘bar’], it forms the basis for writing reusable code. Many frameworks use this approach, such as Element’s form validation.

Consider the following simplified example of a validation function:

function validate(values) { if(! values.first) return false; if(! values.last) return false; return true; } console.log(validate({first:'Bruce',last:'Wayne'})); // trueCopy the code

The above function does the job perfectly. But when there are many forms, validation needs to be applied, with different fields and rules. It would be a good choice if you could build a generic validation function that is configured at run time.

##Object [key] implement form validation

// object validation rules const schema = { first: { required:true }, last: { required:true } } // universal validation function const validate = (schema, values) => { for(field in schema) { if(schema[field].required) { if(! values[field]) { return false; } } } return true; } console.log(validate(schema, {first:'Bruce'})); // false console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // trueCopy the code

### Keep functions single responsibility, flexible combination

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 from the server is requested as follows: 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 ‘–‘

Scheme 1: the most basic direct cycle, three steps at the same time

let orderList=[ { id:1, status:0, startTime:1538323200000, }, { id:2, status:2, startTime:1538523200000, }, { id:3, status:1, startTime:1538723200000, }, { id:4, status:'', startTime:'', }, ]; The requirements seem simple, Let _status={0:' in progress ', 1:' done ', 2:' order exception '} 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,'-'):''; / / set - for (let the key item in) {if (item [key] = = = ' ') {item [key] = '-'; }}})Copy the code

It works fine, but it’s a lot more repetitive,

For example, the following is another set of user data requested by the server. The user data does not have two fields: Status and startTime, but needs to display the identity of the user according to type (0-ordinary user, 1-VIP, 2-super VIP).

Let userList=[{id:1, name:' waiting ', type:0}, {id:2, name:' waiting ', type:1}, {id:3, name:' once ', type:2}] You can't reuse the code you wrote before, you have to copy it and change it. Let _type={0:' common user ', 1:' VIP ', 2:' super VIP '} userlist. forEach(item=>{// set type item.type= item.type.tostring ()? _type[item.type]:''; / / set - for (let the key item in) {if (item [key] = = = ' ') {item [key] = '-'; }}})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.

Scheme 2: Single responsibility, split into multiple functions, resulting in an increase in the number of cycles

Let handleFn={setStatus(list){let _status={0:' in progress ', 1:' done ', } 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,'-'):''; }) return list; }, setInfo(list){ list.forEach(item=>{ for(let key in item){ if(item[key]===''){ item[key]='--'; } } }) 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]:''; }) return list; 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 results are fine, but there is a slight performance sacrifice due to the increased number of loops, but it is acceptable if there is not much data

If you don’t like the hassle of continuous assignment, you can borrow the jQuery idea and make chain calls. Scheme 3: many times to call the function is more boring, here use the chain call

Let ec=(function () {let handle=function (obj) {this.obj= json.parse (json.stringify (obj)); }; Prototype ={setInfo(){this.obj. Map (item=>{for(let key in item){ if(item[key]===''){ item[key]='--'; }}}); return this; }, / * * * @ the description Settings * / setStatus () {let _status = {0: 'on', 1: 'completed', } this.obj. ForEach (item=>{item.status= item.status.tostring ()? _status[item.status]:'' }); return this; }, /** * @description set time */ setStartTime(){this.obj.foreach (item=>{item.startTime= item.starttime.tostring ()? new Date(item.startTime).toLocaleDateString().replace(/\//g,'-'):''; }); return this; }, / * * * @ the description set type * / setType () {let _type = {0: 'ordinary users', 1:' VIP ', } this.obj. ForEach (item=>{item.type= item.type.tostring ()? _type[item.type]:''; }) return this; }, / * * * @ description returns processing result * @ return {Array} | * * / end () {return this. Obj. Return function (obj) {return new handle(obj); }}) (); 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 — that’s all done, but now setStatus().setstartTime ().setinfo () this code here, every time it executes a function, iterates through the array.

Plan 4: Optimization plan, in each function, only record what to process, but do not process, wait until the end of the execution of the unified processing, and return

let orderList=[ { id:1, status:0, startTime:1538323200000, }, { id:2, status:2, startTime:1538523200000, }, { id:3, status:1, startTime:1538723200000, }, { id:4, status:'', startTime:'', }, ]; Let the userList = [{id: 1, name: 'wait', type: 0}, {id: 2, name: 'grizzled troubadour, type: 1}, {id: 3, name:' once ', Type :2}] let ec=(function () {let handle=function (obj) {this.obj= json.parse (json.stringify (obj)); This.handlefnlist =[]; }; Prototype ={handleSetInfo(item){for(let key in item){if(item[key]===''){ item[key]='--'; } } return this; }, setInfo(){ this.handleFnList.push('handleSetInfo'); return this; }, /** * @description set status */ handleSetStatus(item){let _status={0:' in progress ', 1:' done ', } item.status= item.status.tostring ()? _status[item.status]:'' return item; }, setStatus(){ this.handleFnList.push('handleSetStatus'); return this; }, /** * @description set time */ handleSetStartTime(item){item.startTime= item.starttime.tostring ()? new Date(item.startTime).toLocaleDateString().replace(/\//g,'-'):''; return item; }, setStartTime(){ this.handleFnList.push('handleSetStartTime'); return this; }, /** * @description set type */ handleSetType(item){let _type={0:' ordinary user ', 1:' VIP ', } item.type= item.type.tostring ()? _type[item.type]:''; return item; }, setType(){ this.handleFnList.push('handleSetType'); return this; }, / * * * @ description returns processing result * @ return {Array | *} * / end () {/ / unified handling this operation. The obj. ForEach (item = > { this.handleFnList.forEach(fn=>{ item=this[fn](item); })}) return this.obj; Return function (obj) {return new handle(obj); }}) (); OrderList =ec(orderList).setStatus().setStartTime().setInfo().end(); console.log(orderList); UserList =ec(userList).setType().end(); console.log(userList);Copy the code