浅析设计模式-依赖倒置原则

依赖倒置原则的英文名称是 Dependence Inversion Principle,简称DIP

定义

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

阅读剩余部分 -

浅析设计模式-里氏替换原则

里氏替换原则的英文名称是 Liskov Subsitution Principle,简称 LSP。

定义

第一种定义,也是最正宗的定义: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is subsituted for o2 then S is a subtype T.(如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换为o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。)

第二种定义: Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.(所有引用基类的地方必须能透明地使用其子类的对象)。

阅读剩余部分 -

浅析设计模式-单一职责原则

单一职责原则的英文名称是 Single Responsibility Principle,简称SRP。

定义

应该有且仅有一个原因引起类的变更。也就是说,一个类应当只有一个职责,如果类的职责过多,代码就会臃肿,可读性变差,也难以维护。单一职责原则和接口隔离原则有一定的关系,接口隔离之后,职责也就单一了,实现这个接口的类的职责自然也就单一了。但,接口隔离关注的是抽象层,单一职责关注的偏重于实现。

阅读剩余部分 -

JavaScript代码简写技巧

1. 三元(三目)运算符

如果只想在一行中编写if..else语句时,这是一个很好的节省代码的方式。

常规:

const x = 20;
let answer;
if (x > 10) {
    answer = "大于 10";
} else {
    answer = "小于 10";
}

简写:

const answer = x > 10 ? "大于 10" : "小于 10"

嵌套版三元运算:

const answer = x > 10 ? "大于 10" : x < 5 ? "小于5" : "在5和10之间";

2. 短路判断简写

将变量值分配给另一个变量时,您可能希望确保源变量不为null,undefined或为空。您可以编写带有多个条件的长 if 语句,也可以使用短路判断。

常规:

if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
    let variable2 = variable1;
}

简写:

const variable2 = variable1 || 'new';

再来点示例,尝试一下:

let variable1;
let variable2 = variable1 || 'bar';
console.log(variable2 === 'bar'); // true

variable1 = 'foo';
variable2 = variable1 || 'bar';
console.log(variable2); // foo

请注意,如果将variable1设置为false或0,则赋值为bar。

3. 声明变量简写

常规:

let x;
let y;
let z = 3;

简写:

let x, y, z = 3;

4. If真值判断简写

这可能是微不足道的,但值得一提。在执行“if 检查”时,有时可以省略全等运算符。

常规:

if (likeJavaScript === true)

简写:

if (likeJavaScript)

注意:这两个例子并不完全相同,因为只要likeJavaScript是一个真值,检查就会通过。

这是另一个例子。如果a不等于true,那就做点什么吧。

常规:

let a;
if (a !== true) {
    // do something...
}

简写:

let a;
if (!a) {
    // do something...
}

5. For循环简写

如果您想要纯JavaScript并且不想依赖外部库(如jQuery或lodash),这个小技巧非常有用。

常规:

const fruits = ['mango', 'peach', 'banana'];
for (let i = 0; i < fruits.length; i++)

简写:

for (let fruit of fruits)

如果您只想访问索引,请执行以下操作:

for (let index in fruits)

如果要访问文字对象中的键,这也适用:

const obj = {continent: '亚洲', country: '中国', city: '北京'}
for (let key in obj)
    console.log(key) // 输出: continent, country city

Array.forEach简写:

function logArrayElements(element, index, array) {
    console.log("a[" + index "] = " + element);
}
[2, 5, 9].forEach(logArrayElements);

6. 短路判断赋值

如果预期参数为null或undefined,我们可以简单地使用短路逻辑运算符,只需一行代码即可完成相同的操作,而不是编写六行代码来分配默认值。

常规:

let dbHost;
if (process.env.DB_HOST) {
    dbHost = process.env.DB_HOST;
} else {
    dbHost = 'localhost'
}

简写:

const dbHost = process.env.DB_HOST || 'localhost'

7. 十进制基本指数

你可能已经看过这个了。它本质上是一种编写没有尾随零的数字的奇特方式。例如,1e7实质上意味着1后跟7个零。它表示一个十进制基数(JavaScript解释为浮点类型)等于10,000,000。

for (let i = 0; i < 10000; i++) {}

简写:

for (let i = 0; i < 1e7; i++) {}

// 下面都会判断为true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

8. 对象属性简写

在JavaScript中定义对象很简单。 ES6提供了一种更简单的方法来为对象分配属性。如果变量名称与对象键相同,则可以使用简写表示法。

常规:

const x = 1920, y = 1080;
const obj = { x: x, y: y};

简写:

const obj = {x, y};

9. 箭头函数简写

经典函数以简单的形式易于读写,但是一旦你开始将它们嵌套在其他函数调用中,它们往往会变得有点冗长和混乱。

常规:

function sayHello(name) {
    console.log("Hello", name);
}

setTimeout(function() {
    console.log("Loaded")
}, 2000)

list.forEach(function(item) {
    console.log(item);
});

简写:

sayHello = name => console.log("Hello", name)

setTimeout(() => console.log("Loaded"), 2000);

list.forEach(item => console.log(item));

重要的是要注意,箭头函数内部的 this 与常规函数的不同,因此这两个示例并不严格等效。有关详细信息,请参阅有关箭头函数语法的文章。

10. 隐式返回简写

Return 是我们经常使用的关键字,用于返回函数的最终结果。具有单个语句的箭头函数将隐式返回其执行结果(函数必须省略大括号({})以省略return关键字)。

要返回多行语句(例如对象),必须使用 () 而不是 {} 来包装函数体。这可确保将代码执行为单个语句。

常规:

function calcCircumference(diameter) {
    return Math.PI * diameter
}

简写:

calcCircumference = diameter => (Math.PI * diameter)

11. 默认参数值

您可以使用if语句定义函数参数的默认值。在ES6中,您可以在函数声明本身中定义默认值。

常规:

function volume(l, w, h) {
    if (w === undefined) {
        w = 3;
    }
    if (h === undefined) {
        h = 4;
    }
    return l * w * h;
}

简写:

volume = (l, w = 3, h = 4) => (l * w * h)

volume(2) // output: 24

12. 模板字符串

您是否厌倦了使用 '+' 将多个变量连接成一个字符串?有没有更简单的方法?如果你能够使用ES6,那么你很幸运。您需要做的就是使用反引号,并使用 ${} 来包含变量。

常规:

const wecome = '您已经登陆,欢迎' + name + '.'

const db = 'http://' + host + ':' + port + '.' + database;

简写:

const wecome = `您已经登录,欢迎${name}`;
const db = `http://${host}:${port}/${database}`;

13. 解构赋值简写

如果您正在使用任何流行的Web框架,那么很有可能您将使用对象形式的数组或数据,在组件和API之间传递信息。数据对象到达组件后,您需要将其解构。

常规:

const observable = require('mobx/observable')
const action = require('mobx/action')
const runInAction = require('mobx/runinAction')

const store = this.props.store;
const form = this.props.form;
const loading = this.props.loading;
const errors = this.props.errors;
const entity = this.props.entity;

简写:

import {observable, action, runInAction } from 'mobx';

const { store, form, loading, errors, entity } = this.props;

您甚至可以分配自己的变量名称,比如entity替换原来对象中的contact:

const { store, form, loading, errors, entity:contact } = this.props;

14. 多行字符串

如果您发现自己需要在代码中编写多行字符串,那么您可以编写它:

常规:

const lorem = 'Lorem ipsum dolor sit amet consectetur, \n\t'
    + 'adipisicing elit. Quod nihil atque quis,tempore \n\t'
    + 'quo laboriosam quos dolores nesciunt id molestias \n\t'
    + 'libero, nobis quaerat dolorem aspernatur soluta \n\t'
    + 'exercitationem, debitis quae omnis.'

但是有一种更简单的方法。只需使用反引号。

简写:

const lorem = `Lorem ipsum dolor sit amet consectetur, 
    adipisicing elit. Quod nihil atque quis,tempore 
    quo laboriosam quos dolores nesciunt id molestias 
    libero, nobis quaerat dolorem aspernatur soluta 
    exercitationem, debitis quae omnis.`

15. 展开(spread)操作符

ES6中引入的展开运算符有几个用例,可以使JavaScript代码更高效,更有趣。它可以用来替换某些数组函数。展开操作符只是连续的三个点。

常规:

// 拼接数组
const odd = [1, 3, 5];
const nums = [2, 4, 6].concat(odd);

// 克隆数组
const arr = [1, 2, 3, 4];
const arr2 = arr.slice();

简写:

// 拼接数组
const odd = [1, 3, 5];
const nums = [2, 4, 6, ...odd];

console.log(nums);

// 克隆数组
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

与 concat() 函数不同,您可以使用spread运算符在另一个数组内的任何位置插入数组。

const odd = [1, 3, 5];
const nums = [2, ...odd, 4, 6];

您还可以将spread运算符与ES6解构表示法结合使用:

const { a, b, ...z} = { a: 1, b: 2, c: 3, d: 4};

console.log(a); // 1
console.log(b); // 2
console.log(z); // { c: 3, d: 4}

16. 强制参数

默认情况下,如果未传递值,JavaScript会将函数参数设置为undefined。其他一些语言会引发警告或错误。要强制执行参数赋值,可以使用 if 语句在未定义时抛出错误。

常规:

function foo(bar) {
    if (bar === undefined) {
        throw new Error('Missing parameter!');
    }
    return bar;
}

简写:

mandatory = () => {
    throw new Error('Missing parameter!');
}

foo = (bar = mandatory()) => {
    return bar;
}

17. Array.find

如果您曾经在纯JavaScript中编写过 find 函数,那么您可能已经使用了for循环。在ES6中,引入了一个名为 find() 的新数组函数

常规:

const pets = [
    { type: 'Dog', name: 'Max'},
    { type: 'Cat', name: 'Karl'},
    { type: 'Dog', name: 'Tommy'}
]

function findDog(name) {
    for (let i = 0; i < pets.length; i++) {
        if (pets[i].type === 'Dog' && pets[i].name === name) {
            return pets[i];
        }
    }
}

简写:

pet = pets.find(pet => pet.type === 'Dog' && pet.name === 'Tommy');

console.log(pet); // { type: 'Dog', name: 'Tommy'}

18. Object[key]

你知道Foo.bar也可以写成Foo ['bar']吗?起初,似乎没有理由应该这样写。但是,这种表示法可以为编写可重用代码块提供方便。

思考一下,验证函数的这个简化示例:

function validate(values) {
    if (!values.first) {
        return false;
    }
    if (!values.last) {
        return false;
    }
    return true;
}

这个功能完美地完成了它的工作,但是请考虑这样一种情况,即您需要验证的表单有很多,表单都具有不同字段和规则。构建可在运行时配置的通用验证函数不是更好吗?

简写:

// 对象校验规则
const schema = {
    first: {
        required: true
    },
    last: {
        required: true
    }
}

// 通用校验函数
const validate = (schema, values) => {
    for (field in schema) {
        if (schema[field].required) {
            if (!values[field]) {
                return false;
            }
        }
    }
    return true;
}

现在我们有了一个通用验证函数,可以在所有表​​单中重用,而无需为每个表单编写自定义验证函数。

19. 双取反运算

双取反运算符有一个非常实用的场景。您可以将它用作 Math.floor() 的替代品。 双取反运算符的优点是它可以更快地执行相同的操作。

常规:

Math.floor(4.9) === 4 // true

简写:

~~4.9 === 4 // true

20. 数学指数幂函数

常规:

Math.pow(2, 3) // 8
Math.pow(2, 2) // 4
Math.pow(4, 3) // 64

简写:

2**3 // 8
2**4 // 16
4**3 // 64

21. 将字符串转换为数字

有时,您的代码会接收String类型的参数,但需要以数字类型处理。这不是什么大问题,我们可以进行快速转换。

常规:

const num1 = parseInt('100');
const num2 = parseFloat('100.01');

简写:

const num1 = +"100"
const num2 = + "100.01";

22. 对象属性赋值

考虑以下代码:

let fname = { firstName: 'Black'}
let lname = { lastName: 'Panther'}

你会如何把它们合并为一个对象?

一种方法是编写一个将第二个对象的数据复制到第一个对象的函数。

最简单的方法是,使用ES6中引入的 Object.assign 函数:

let full_names = Object.assign(fname, lname);

您还可以使用ES8中引入的对象销毁表示法:

let full_names = {...fname, ...lname};

您可以合并的对象属性数量没有限制。如果确实具有相同属性名称的对象,则将按合并的顺序覆盖值。

23. 取反运算 和 IndexOf

使用数组执行查找时,indexOf() 函数用于检索您要查找的项目的位置。如果未找到该项,则返回值-1。在JavaScript中,0被认为是'falsy',而大于或小于0的数字被认为是'truthy'。因此,必须像这样编写正确的代码。

常规:

if (arr.indexOf(item) > -1) {
    // item 找到
}

if (arr.indexOf(item) === -1) {
    // item没找到
}

简写:

if (~arr.indexOf(item)) {
    // item 找到
}

if (!~arr.indexOf(item)) {
    // item没找到
}

取反(〜)运算符对 -1 以外的任何值,都返回 truthy 值。对它进行非运算,直接 !〜。

或者,我们也可以使用 includes() 函数:

if (arr.includes(item)) {
    // 返回true,如果item在数组中,否则返回false
}

24. Object.entries()

这是ES8中引入的一项功能,允许您将对象转换为键/值对数组。请参阅以下示例:

const credits = { producer: 'John', director: 'Jane', assistant: 'Peter'};
const arr = Object.entries(credits);

console.log(arr);

/** 输出
[ ['producer', 'John'],
  ['director', 'Jane'],
  ['assistant', 'Peter']
]

25. Object.values()

这也是ES8中引入的一个新功能,它执行与 Object.entries() 类似的功能,但没有key部分:

const credits = { producer: 'John', director: 'Jane', assistant: 'Peter'};
const arr = Object.values(credits);

console.log(arr);

/** 输出
['John', 'Jane', 'Peter']

原: https://segmentfault.com/a/1190000020354772