0%

Let

let is similar to var but let has scope. let is only accessible in the block level it is defined.

example:

1
2
3
4
5
if (true) {
let a = 40;
console.log(a); //40
}
console.log(a); // undefined

and

1
2
3
4
5
6
7
8
9
10
let a = 50;
let b = 100;
if (true) {
let a = 60;
var c = 10;
console.log(a/c); // 6
console.log(b/c); // 10
}
console.log(c); // 10
console.log(a); // 50

Const

Const is used to assign a constant value to the variable. And the value cannot be changed. Its fixed.

example:

1
2
3
4
const a = 50;
a = 60; // shows error. You cannot change the value of const.
const b = "Constant variable";
b = "Assigning new value"; // shows error.

Whenever you define a const variable, Javascript references the address of the value to the variable.

example:

1
2
3
4
const LANGUAGES = ['Js', 'Ruby', 'Python', 'Go'];
LANGUAGES = "Javascript"; // shows error.
LANGUAGES.push('Java'); // Works fine.
console.log(LANGUAGES); // ['Js', 'Ruby', 'Python', 'Go', 'Java']

the variable ‘LANGUAGES’ actually references to the memory allocated to the array. So you cannot change the variable to reference some other memory location later. Throughout the program it only references to the array.

Arrow Function

1
2
3
4
5
6
7
8
// Old Syntax
function oldOne() {
console.log("Hello World..!");
}
// New Syntax
var newOne = () => {
console.log("Hello World..!");
}

and

1
2
3
4
let NewOneWithParameters = (a, b) => {
console.log(a+b); // 30
}
NewOneWithParameters(10, 20);

There are two things to explain here.

  1. If you have a function with single parameter, you don’t need (). In our case element is the parameter.
  2. And If you have single line as the body of the function you don’t need {} and also JS will implicitly returns the value after executing the function. You don’t have to use return keyword.
  3. Arrow functions shine best with anything that requires this to be bound to the context, and not the function itself.

For of loop

for..of iterates through list of elements (i.e) like Array and returns the elements (not their index) one by one.

1
2
3
4
5
6
7
8
9
let arr = [2,3,4,1];
for (let value of arr) {
console.log(value);
}
Output:
2
3
4
1

and

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let string = "Javascript";
for (let char of string) {
console.log(char);
}
Output:
J
a
v
a
s
c
r
i
p
t

Spread attributes

1
2
3
4
5
6
7
8
9
10
11
let SumElements = (arr) => {
console.log(arr); // [10, 20, 40, 60, 90]

let sum = 0;
for (let element of arr) {
sum += element;
}
console.log(sum); // 220.
}

SumElements([10, 20, 40, 60, 90]);

consider the same example with spread attributes:

1
2
3
4
5
6
7
8
9
let SumElements = (...arr) => {
console.log(arr); // [10, 20, 40, 60, 90]
let sum = 0;
for (let element of arr) {
sum += element;
}
console.log(sum); // 220.
}
SumElements(10, 20, 40, 60, 90); // Note we are not passing array here. Instead we are passing the elements as arguments.

Math.max is a simple method that returns the maximum element from given list. It doesn’t accept an array.

1
2
let arr = [10, 20, 60];
Math.max(arr); // Shows error. Doesn't accept an array.

So lets use our savior:

1
2
let arr = [10, 20, 60];
Math.max(...arr); // 60

Maps

Map holds key-value pairs. It’s similar to an array but we can define our own index. And indexes are unique in maps.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var map = new Map();
map.set('name', 'John');
map.set('id', 10);

map.get('name'); // John
map.get('id'); // 10

map.size; // 2. Returns the size of the map.
map.keys(); // outputs only the keys.
map.values(); // outputs only the values.

for (let key of map.keys()) {
console.log(key);
}
Output:
name
id

for (let [key, value] of map) {
console.log(key+" - "+value);
}
Output:
name - John
id - 10

Sets

Sets are used to store the unique values of any type.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var sets = new Set();
sets.add('a');
sets.add('b');
sets.add('a'); // We are adding duplicate value.
for (let element of sets) {
console.log(element);
}
Output:
a
b

sets.size; // returns 2. Size of the set.
sets.has('a'); // returns true.
sets.has('c'); // returns false.

Static methods

1
2
3
4
5
6
7
8
class Example {
static Callme() {
console.log("Static method");
}
}
Example.Callme();
Output:
Static method

you can call the function without creating any instance for the class.

Getters and Setters

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class People {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
setName(name) {
this.name = name;
}
}
let person = new People("Jon Snow");
console.log(person.getName());
person.setName("Dany");
console.log(person.getName());
Output:
Jon Snow
Dany

Promises

They are used to make async operations such as API request, file handling, downloading images, etc.

Before promises, programmers used to define callbacks. Callbacks are normal functions in Javascript which executes when the async operation is complete.

  • three states in promises

    1. Pending: In this state the promise is just executing the async operation. For example, It’s making some API request to the server or downloading some images from cdn. from this state promise can move to either to Fulfilled or to Rejected
    2. Fulfilled: If the promise has reached this state, then it means that the async operation is complete and we have the output. For example, we have the response from the API.
    3. Rejected: If the promise has reached this state, it means that the async operation is not successful and we have the error which caused the operation to fail.
    1
    2
    3
    4
    5
    6
    7
    8
    const apiCall = new Promise(function(resolve, reject) {
    if ( API request to get some data ) {
    resolve("The request is successful and the response is "+ response);
    }
    else {
    reject("The request is not successful. The error is "+error);
    }
    });

    Then the resolve function is called if we get the response from the server. And if there is some error reject function is called with the error message.

  • We use handlers to get the output from the promise.

    Handlers are just functions which executes when some event occurs such as clicking a button, moving the cursor, etc.

    So we can use handlers to handle when the resolve function is called or **reject **function is called.

    • The handler then executes its function parameter when the resolve function is called inside the promise.
    1
    2
    3
    4
    5
    6
    // calling the promise with some handlers.
    apiCall.then(function(x) {console.log(x); })

    // Output
    The request is successful and the response is {name: "Jon Snow"}

    • Catch handler looks out for reject function.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    apiCall
    .then(function(x) {
    console.log(x);
    })
    .catch(function(x) {
    console.log(x);
    })

    // Assuming the request is not successful ( reject function is called in the promise. )
    Output:
    The request is not successful

Async / Await

async

1
2
3
async function hello() {
return "Hello Promise..!"
}

The above code is equivalent to the below code:

1
2
3
4
5
function hello() {
return new Promise(function(resolve, reject) {
// executor function body.
});
}

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
async function hello(a, b) {
if (a < b) {
return "Greater";
}
else {
return new Error("Not Greater");
}
}
hello(14, 10)
.then(function(x) {
console.log("Good..! " + x);
})
.catch(function(x) {
console.log("Oops..! " + x);
})
Output:
Oops..! Not Greater.
// if you call hello(4, 10) you get "Good..! Greater"

Don’t forget that async function will return a promise. So of course, you can call resolve and reject function inside async function too.

example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
async function Max(a, b) {
if (a > b) {
return Promise.resolve("Success");
}
else {
return Promise.reject("Error");
}
}
Max(4, 10)
.then(function(x) {
console.log("Good " + x);
})
.catch(function(x) {
console.log("Oops " + x);
});
Output:
Oops Error
// If we pass Max(14, 10) then we should get "Good Success" :)

await

It makes the Javascript to wait until you get the response from the endpoint. And then it resumes the execution.

await can be used only inside async function. It doesn’t work outside async function

1
2
3
4
5
6
7
8
9
10
11
12
13
async function hello() {
let response = await fetch('https://api.github.com/');
// above line fetches the response from the given API endpoint.
return response;
}
hello()
.then(function(x) {
console.log(x);
});
...
...
Output:
Response from the API.

Array

Array Map

1
2
3
4
5
6
7
let arr = [1,2,3,4,5];
let modifiedArr = arr.map(function(element, index, arr) {
return element * 10;
});
console.log(modifiedArr);
Output:
[10, 20, 30, 40, 50]

And also note we have to return some value in the end. Which will be the modified value of that element. If you didn’t return anything then the particular element will be undefined.

One more thing I like to add is the second and third parameter is only optional. Only the first parameter is mandatory. for example :

1
2
3
let modifiedArr = arr.map(function(element) {
return element * 10;
});

write the map operator with arrow functions:

1
2
3
4
5
6
7
8
9
10
11
12
let modifiedArr = arr.map((element, index) => {
console.log("index "+index);
return element * 10;
});
console.log(modifiedArr);
Output:
index 0
index 1
index 2
index 3
index 4
[10, 20, 30, 40, 50]

better:

1
2
let modifiedArr = arr.map(element => element * 10);
console.log(modifiedArr);

Array Filter

1
2
3
4
5
6
7
let arr = [1, 2, 3, 4, 5, 6]
let modifiedArr = arr.filter(function(element, index, array) {
return element % 2 == 0
});
console.log(modifiedArr);
Output:
[2, 4, 6]

try by arrow function:

1
let modifiedAarr = arr.filter((element, index) => element%2 == 0)

we have to return a boolean value for each element of the array. If you won’t return any boolean value at the end then the filter takes it as false and deletes the element.

Array Reduce

Array reduce is used to aggregate all the elements of an array and return a single value.

1
2
3
4
5
6
7
let arr = [1,2,3,4,5,6]
let total= arr.reduce(function(sum, element, index, array) {
return sum + element;
},0);
console.log("total is "+total);
Output:
total is 21

Unlike filter and map, reduce takes a function with four parameters and also a additional element. Unlike filter and map, the first two parameters are mandatory. Other two are optional.

The first parameter is the aggregator element.In our case it’s 0.

Like filter and map you have to return the end result.

write the same code with arrow functions:

1
let totalSum = arr.reduce((sum, element) => element+sum, 0)

Template Literals

1
2
3
4
5
6
7
8
9
let name = "Srebalaji";
let languages = () => {return "Ruby, Js, Java, Python"}
let msg = `My name is ${name}
My age is ${20+3}
And I code in ${languages()}`
Output:
My name is Srebalaji
My age is 23
And I code in Ruby, Js, Java, Python

Imports and Exports

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//app.js
export let name = "Jon"
export let age = 23

//index.js
import {name, age} from './app'
console.log(name);
console.log(age);

//index.html
<script src="./index.js"></script>

Output:
Jon
23

and:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//app.js
let a = 10;
let b = 2;
let sum = () => a+b;
export {a,b}
export default sum

//index.js
import * as variables from './app'
import addition from './app' // default value
console.log(variables.a);
console.log(variables.b);
console.log(addition());

Output:
10
2
12
  1. If you are using * to import values then you have to use alias (i.e) names that will refer to imported values. In our example we have used variables as alias.

  2. Using * to import values doesn’t import default value. You have to import it separately.

    for example:import addition, * as variables from './app'

Destructuring objects and arrays

1
2
3
4
5
6
7
8
9
let person = {firstName: "Jon", lastName: "Snow", age: 23}
const {firstName, lastName, age} = person
console.log(firstName);
console.log(lastName);
console.log(age);
Output:
Jon
Snow
23

Extend and Super

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Person{
constructor(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
displayName() {
return `${this.firstName} - ${this.lastName}`;
}
}
class Employee extends Person {
constructor(firstName, lastName, age, salary) {
super(firstName, lastName, age);
this.salary = salary;
}
displaySalary() {
return `${this.salary}`;
}
displayName() {
return super.displayName();
}
displayAge() {
return this.age;
}
}
let manager = new Employee("Jon", "Snow", 23, 100);
console.log(manager.displaySalary());
console.log(manager.displayName());
console.log(manager.displayAge());
Output:
100
Jon Snow
23

And then we have used super keyword to call the constructor of the parent class. And we also have called the method declared in the parent class using super.

Generator functions

  • Generator functions are written using the function* syntax. When called initially, generator functions do not execute any of their code, instead returning a type of iterator called a Generator.
  • When a value is consumed by calling the generator’s next method, the Generator function executes until it encounters the yield keyword.
    • Each yield in a generator basically represents an asynchronous step in a more synchronous/sequential process — somewhat like await in an asyncfunction.
  • The function can be called as many times as desired and returns a new Generator each time, however each Generator may only be iterated once.

some method

  • includes

    construct an array of the items, and use includes:

    1
    ['a', 'b', 'c'].includes('b')


Learn Regex

什么是正则表达式?

正则表达式是一组由字母和符号组成的特殊文本, 它可以用来从文本中找出满足你想要的格式的句子.

一个正则表达式是在一个主体字符串中从左到右匹配字符串时的一种样式.
“Regular expression”这个词比较拗口, 我们常使用缩写的术语”regex”或”regexp”.
正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等.

想象你正在写一个应用, 然后你想设定一个用户命名的规则, 让用户名包含字符,数字,下划线和连字符,以及限制字符的个数,好让名字看起来没那么丑.
我们使用以下正则表达式来验证一个用户名:

以上的正则表达式可以接受 john_doe, jo-hn_doe, john12_as.
但不匹配Jo, 因为它包含了大写的字母而且太短了.

目录

1. 基本匹配

正则表达式其实就是在执行搜索时的格式, 它由一些字母和数字组合而成.
例如: 一个正则表达式 the, 它表示一个规则: 由字母t开始,接着是h,再接着是e.

"the" => The fat cat sat on the mat.

在线练习

正则表达式123匹配字符串123. 它逐个字符的与输入的正则表达式做比较.

正则表达式是大小写敏感的, 所以The不会匹配the.

"The" => The fat cat sat on the mat.

在线练习

2. 元字符

正则表达式主要依赖于元字符.
元字符不代表他们本身的字面意思, 他们都有特殊的含义. 一些元字符写在方括号中的时候有一些特殊的意思. 以下是一些元字符的介绍:

元字符 描述
. 句号匹配任意单个字符除了换行符.
[ ] 字符种类. 匹配方括号内的任意字符.
[^ ] 否定的字符种类. 匹配除了方括号里的任意字符
* 匹配>=0个重复的在*号之前的字符.
+ 匹配>=1个重复的+号前的字符.
? 标记?之前的字符为可选.
{n,m} 匹配num个大括号之前的字符 (n <= num <= m).
(xyz) 字符集, 匹配与 xyz 完全相等的字符串.
| 或运算符,匹配符号前或后的字符.
\ 转义字符,用于匹配一些保留的字符 [ ] ( ) { } . * + ? ^ $ \ |
^ 从开始行开始匹配.
$ 从末端开始匹配.

2.1 点运算符 .

.是元字符中最简单的例子.
.匹配任意单个字符, 但不匹配换行符.
例如, 表达式.ar匹配一个任意字符后面跟着是ar的字符串.

".ar" => The car parked in the garage.

在线练习

2.2 字符集

字符集也叫做字符类.
方括号用来指定一个字符集.
在方括号中使用连字符来指定字符集的范围.
在方括号中的字符集不关心顺序.
例如, 表达式[Tt]he 匹配 theThe.

"[Tt]he" => The car parked in the garage.

在线练习

方括号的句号就表示句号.
表达式 ar[.] 匹配 ar.字符串

"ar[.]" => A garage is a good place to park a car.

在线练习

2.2.1 否定字符集

一般来说 ^ 表示一个字符串的开头, 但它用在一个方括号的开头的时候, 它表示这个字符集是否定的.
例如, 表达式[^c]ar 匹配一个后面跟着ar的除了c的任意字符.

"[^c]ar" => The car parked in the garage.

在线练习

2.3 重复次数

后面跟着元字符 +, * or ? 的, 用来指定匹配子模式的次数.
这些元字符在不同的情况下有着不同的意思.

2.3.1 *

*号匹配 在*之前的字符出现大于等于0次.
例如, 表达式 a* 匹配以0或更多个a开头的字符, 因为有0个这个条件, 其实也就匹配了所有的字符. 表达式[a-z]* 匹配一个行中所有以小写字母开头的字符串.

"[a-z]*" => The car parked in the garage #21.

在线练习

*字符和.字符搭配可以匹配所有的字符.*.
*和表示匹配空格的符号\s连起来用, 如表达式\s*cat\s*匹配0或更多个空格开头和0或更多个空格结尾的cat字符串.

"\s*cat\s*" => The fat cat sat on the concatenation.

在线练习

2.3.2 +

+号匹配+号之前的字符出现 >=1 次.
例如表达式c.+t 匹配以首字母c开头以t结尾,中间跟着任意个字符的字符串.

"c.+t" => The fat cat sat on the mat.

在线练习

2.3.3 ?

在正则表达式中元字符 ? 标记在符号前面的字符为可选, 即出现 0 或 1 次.
例如, 表达式 [T]?he 匹配字符串 heThe.

"[T]he" => The car is parked in the garage.

在线练习

"[T]?he" => The car is parked in the garage.

在线练习

2.4 {}

在正则表达式中 {} 是一个量词, 常用来一个或一组字符可以重复出现的次数.
例如, 表达式 [0-9]{2,3} 匹配最少 2 位最多 3 位 0~9 的数字.

"[0-9]{2,3}" => The number was 9.9997 but we rounded it off to 10.0.

在线练习

我们可以省略第二个参数.
例如, [0-9]{2,} 匹配至少两位 0~9 的数字.

如果逗号也省略掉则表示重复固定的次数.
例如, [0-9]{3} 匹配3位数字

"[0-9]{2,}" => The number was 9.9997 but we rounded it off to 10.0.

在线练习

"[0-9]{3}" => The number was 9.9997 but we rounded it off to 10.0.

在线练习

2.5 (...) 特征标群

特征标群是一组写在 (...) 中的子模式. 例如之前说的 {} 是用来表示前面一个字符出现指定次数. 但如果在 {} 前加入特征标群则表示整个标群内的字符重复 N 次. 例如, 表达式 (ab)* 匹配连续出现 0 或更多个 ab.

我们还可以在 () 中用或字符 | 表示或. 例如, (c|g|p)ar 匹配 cargarpar.

"(c|g|p)ar" => The car is parked in the garage.

在线练习

2.6 | 或运算符

或运算符就表示或, 用作判断条件.

例如 (T|t)he|car 匹配 (T|t)hecar.

"(T|t)he|car" => The car is parked in the garage.

在线练习

2.7 转码特殊字符

反斜线 \ 在表达式中用于转码紧跟其后的字符. 用于指定 { } [ ] / \ + * . $ ^ | ? 这些特殊字符. 如果想要匹配这些特殊字符则要在其前面加上反斜线 \.

例如 . 是用来匹配除换行符外的所有字符的. 如果想要匹配句子中的 . 则要写成 \. 以下这个例子 \.?是选择性匹配.

"(f|c|m)at\.?" => The fat cat sat on the mat.

在线练习

2.8 锚点

在正则表达式中, 想要匹配指定开头或结尾的字符串就要使用到锚点. ^ 指定开头, $ 指定结尾.

2.8.1 ^

^ 用来检查匹配的字符串是否在所匹配字符串的开头.

例如, 在 abc 中使用表达式 ^a 会得到结果 a. 但如果使用 ^b 将匹配不到任何结果. 因为在字符串 abc 中并不是以 b 开头.

例如, ^(T|t)he 匹配以 Thethe 开头的字符串.

"(T|t)he" => The car is parked in the garage.

在线练习

"^(T|t)he" => The car is parked in the garage.

在线练习

2.8.2 `### 号

同理于 ^ 号, $ 号用来匹配字符是否是最后一个.

例如, (at\.)$ 匹配以 at. 结尾的字符串.

"(at\.)" => The fat cat. sat. on the mat.

在线练习

"(at\.)$" => The fat cat. sat. on the mat.

在线练习

3. 简写字符集

正则表达式提供一些常用的字符集简写. 如下:

简写 描述
. 除换行符外的所有字符
\w 匹配所有字母数字, 等同于 [a-zA-Z0-9_]
\W 匹配所有非字母数字, 即符号, 等同于: [^\w]
\d 匹配数字: [0-9]
\D 匹配非数字: [^\d]
\s 匹配所有空格字符, 等同于: [\t\n\f\r\p{Z}]
\S 匹配所有非空格字符: [^\s]
\f 匹配一个换页符
\n 匹配一个换行符
\r 匹配一个回车符
\t 匹配一个制表符
\v 匹配一个垂直制表符
\p 匹配 CR/LF (等同于 \r\n),用来匹配 DOS 行终止符

4. 零宽度断言(前后预查)

先行断言和后发断言都属于非捕获簇(不捕获文本 ,也不针对组合计进行计数).
先行断言用于判断所匹配的格式是否在另一个确定的格式之前, 匹配结果不包含该确定格式(仅作为约束).

例如, 我们想要获得所有跟在 $ 符号后的数字, 我们可以使用正后发断言 (?<=\$)[0-9\.]*.
这个表达式匹配 $ 开头, 之后跟着 0,1,2,3,4,5,6,7,8,9,. 这些字符可以出现大于等于 0 次.

零宽度断言如下:

符号 描述
?= 正先行断言-存在
?! 负先行断言-排除
?<= 正后发断言-存在
?<! 负后发断言-排除

4.1 ?=... 正先行断言

?=... 正先行断言, 表示第一部分表达式之后必须跟着 ?=...定义的表达式.

返回结果只包含满足匹配条件的第一部分表达式.
定义一个正先行断言要使用 (). 在括号内部使用一个问号和等号: (?=...).

正先行断言的内容写在括号中的等号后面.
例如, 表达式 (T|t)he(?=\sfat) 匹配 Thethe, 在括号中我们又定义了正先行断言 (?=\sfat) ,即 Thethe 后面紧跟着 (空格)fat.

"(T|t)he(?=\sfat)" => The fat cat sat on the mat.

在线练习

4.2 ?!... 负先行断言

负先行断言 ?! 用于筛选所有匹配结果, 筛选条件为 其后不跟随着断言中定义的格式.
正先行断言 定义和 负先行断言 一样, 区别就是 = 替换成 ! 也就是 (?!...).

表达式 (T|t)he(?!\sfat) 匹配 Thethe, 且其后不跟着 (空格)fat.

"(T|t)he(?!\sfat)" => The fat cat sat on the mat.

在线练习

4.3 ?<= ... 正后发断言

正后发断言 记作(?<=...) 用于筛选所有匹配结果, 筛选条件为 其前跟随着断言中定义的格式.
例如, 表达式 (?<=(T|t)he\s)(fat|mat) 匹配 fatmat, 且其前跟着 Thethe.

"(?<=(T|t)he\s)(fat|mat)" => The fat cat sat on the mat.

在线练习

4.4 ?<!... 负后发断言

负后发断言 记作 (?<!...) 用于筛选所有匹配结果, 筛选条件为 其前不跟随着断言中定义的格式.
例如, 表达式 (?<!(T|t)he\s)(cat) 匹配 cat, 且其前不跟着 Thethe.

"(?<!(T|t)he\s)(cat)" => The cat sat on cat.

在线练习

5. 标志

标志也叫模式修正符, 因为它可以用来修改表达式的搜索结果.
这些标志可以任意的组合使用, 它也是整个正则表达式的一部分.

标志 描述
i 忽略大小写.
g 全局搜索.
m 多行的: 锚点元字符 ^ $ 工作范围在每行的起始.

5.1 忽略大小写 (Case Insensitive)

修饰语 i 用于忽略大小写.
例如, 表达式 /The/gi 表示在全局搜索 The, 在后面的 i 将其条件修改为忽略大小写, 则变成搜索 theThe, g 表示全局搜索.

"The" => The fat cat sat on the mat.

在线练习

"/The/gi" => The fat cat sat on the mat.

在线练习

修饰符 g 常用于执行一个全局搜索匹配, 即(不仅仅返回第一个匹配的, 而是返回全部).
例如, 表达式 /.(at)/g 表示搜索 任意字符(除了换行) + at, 并返回全部结果.

"/.(at)/" => The fat cat sat on the mat.

在线练习

"/.(at)/g" => The fat cat sat on the mat.

在线练习

5.3 多行修饰符 (Multiline)

多行修饰符 m 常用语执行一个多行匹配.

像之前介绍的 (^,$) 用于检查格式是否是在待检测字符串的开头或结尾. 但我们如果想要它在每行的开头和结尾生效, 我们需要用到多行修饰符 m.

例如, 表达式 /at(.)?$/gm 表示小写字符 a 后跟小写字符 t , 末尾可选除换行符外任意字符. 根据 m 修饰符, 现在表达式匹配每行的结尾.

"/.at(.)?$/" => The fat
                cat sat
                on the mat.

在线练习

"/.at(.)?$/gm" => The fat
                  cat sat
                  on the mat.

在线练习

6. 贪婪匹配与惰性匹配 (Greedy vs lazy matching)

正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用 ? 将贪婪匹配模式转化为惰性匹配模式。

"/(.*at)/" => The fat cat sat on the mat. 

在线练习

"/(.*?at)/" => The fat cat sat on the mat. 

在线练习

贡献

许可证

MIT © Zeeshan Ahmad

Like any unfamiliar technology, React does have a learning curve. With practice and some patience, you will get the hang of it.

  • React also streamlines how data is stored and handled, using state and props.

create react app

  • npm install -g create-react-app
  • npx create-react-app my-app or npm init react-app my-app

JSX: JavaScript + XML

Babel compiles JSX down to React.createElement() calls.

jsx

1
const heading = <h1 className="site-heading">Hello, React</h1>

non-jsx

1
const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')

the feature of jsx:

  • className is used instead of class for adding CSS classes, as class is a reserved keyword in JavaScript.
  • Properties and methods in JSX are camelCase - onclick will become onClick.
  • Self-closing tags must end in a slash - e.g. <img />

Components

Whether you declare a component as a function or a class, it must never modify its own props.

Function

The simplest way to define a component is to write a JavaScript function:

1
2
3
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}

Class Components

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, { Component } from 'react'

class Table extends Component {
render() {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
</tbody>
</table>
)
}
}

export default Table

Simple Components

The other type of component in React is the simple component, which is a function. This component doesn’t use the class keyword. Let’s take our Table and make two simple components for it - a table header, and a table body.

1
2
3
4
5
6
7
8
9
10
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
1
2
3
4
5
6
7
8
9
10
const TableBody = () => {
return (
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
</tbody>
)
}
1
2
3
4
5
6
7
8
9
10
class Table extends Component {
render() {
return (
<table>
<TableHeader />
<TableBody />
</table>
)
}
}

Everything should appear as it did before. As you can see, components can be nested in other components, and simple and class components can be mixed.

A class component must include render(), and the return can only return one parent element.

Converting a Function to a Class

convert a function component to a class in five steps:

  1. Create an ES6 class, with the same name, that extends React.Component.
  2. Add a single empty method to it called render().
  3. Move the body of the function into the render() method.
  4. Replace props with this.props in the render() body.
  5. Delete the remaining empty function declaration.

Props

Props are an effective way to pass existing data to a React component, however the component cannot change the props - they’re read-only.

  • props are a way of passing data from parent to child.

State

State is similar to props, but it is private and fully controlled by the component.

State is reserved only for interactivity, that is, data that changes over time.

You can think of state as any data that should be saved and modified without necessarily being added to a database - for example, adding and removing items from a shopping cart before confirming your purchase.

  • You must use this.setState() to modify an array. Simply applying a new value to this.state.property will not work.

    ie.

    1
    2
    // Wrong
    this.state.comment = 'Hello';
    1
    2
    // Correct
    this.setState({comment: 'Hello'});

tips:

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

ie.

1
2
3
4
// Wrong
this.setState({
counter: this.state.counter + this.props.increment,
});

use a second form of setState() that accepts a function rather than an object. That function will receive the previous state as the first argument, and the props at the time the update is applied as the second argument:

1
2
3
4
// Correct
this.setState((state, props) => ({
counter: state.counter + props.increment
}));

The Data Flows Down

If you imagine a component tree as a waterfall of props, each component’s state is like an additional water source that joins it at an arbitrary point but also flows down.

Neither parent nor child components can know if a certain component is stateful or stateless, and they shouldn’t care whether it is defined as a function or a class.

This is why state is often called local or encapsulated. It is not accessible to any component other than the one that owns and sets it.

This is commonly called a “top-down” or “unidirectional” data flow. Any state is always owned by some specific component, and any data or UI derived from that state can only affect components “below” them in the tree.

Lifecycle methods

constructor

componentDidMount

The componentDidMount() method runs after the component output has been rendered to the DOM.

componentWillUnmount

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}

componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}

componentWillUnmount() {
clearInterval(this.timerID);
}

tick() {
this.setState({
date: new Date()
});
}

render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}

ReactDOM.render(
<Clock />,
document.getElementById('root')
);

Let’s quickly recap what’s going on and the order in which the methods are called:

  1. When <Clock /> is passed to ReactDOM.render(), React calls the constructor of the Clockcomponent. Since Clock needs to display the current time, it initializes this.state with an object including the current time. We will later update this state.
  2. React then calls the Clock component’s render() method. This is how React learns what should be displayed on the screen. React then updates the DOM to match the Clock’s render output.
  3. When the Clock output is inserted in the DOM, React calls the componentDidMount() lifecycle method. Inside it, the Clock component asks the browser to set up a timer to call the component’s tick() method once a second.
  4. Every second the browser calls the tick() method. Inside it, the Clock component schedules a UI update by calling setState() with an object containing the current time. Thanks to the setState() call, React knows the state has changed, and calls the render() method again to learn what should be on the screen. This time, this.state.date in the render() method will be different, and so the render output will include the updated time. React updates the DOM accordingly.
  5. If the Clock component is ever removed from the DOM, React calls the componentWillUnmount() lifecycle method so the timer is stopped.

总结:constructor->render()->componentDidMount()

state改变->render()

componentWillReceiveProps

componentWillReceiveProps在初始化render的时候不会执行,它会在Component接受到新的状态(Props)时被触发,一般用于父组件状态更新时子组件的重新渲染。

在componentWillReceiveProps中想作任何变更最好都将两个状态进行比较,假如状态有异才执行下一步。不然容易造成组件的多次渲染,并且这些渲染都是没有意义的。

Events

Conditional Rendering

Also remember that whenever conditions become too complex, it might be a good time to extract a component.

  • Returning null from a component’s render method does not affect the firing of the component’s lifecycle methods. For instance componentDidUpdate will still be called.

Lists and Keys

Keep in mind that if the map() body is too nested, it might be a good time to extract a component.

Forms

Lifting State Up

Composition vs Inheritance

  • Remember that components may accept arbitrary props, including primitive values, React elements, or functions.

Thinking in React

  • You can build top-down or bottom-up. That is, you can either start with building the components higher up in the hierarchy or with the ones lower in it. In simpler examples, it’s usually easier to go top-down, and on larger projects, it’s easier to go bottom-up and write tests as you build.
  • Remember: React is all about one-way data flow down the component hierarchy.

types

  • Number

  • String

  • Boolean

    false, 0, empty strings (“”), NaN, null, and undefined all become false.

  • Symbol (new in ES2015)

  • Object

  • null

  • undefined

    declare a variable without assigning a value to it. If you do this, the variable’s type is undefined. undefined is actually a constant.

Variables

  • let

    let allows you to declare block-level variables. The declared variable is available from the block it is enclosed in.

  • const

    const allows you to declare variables whose values are never intended to change. The variable is available from the block it is declared in.

  • var

    A variable declared with the var keyword is available from the written out function (as opposed to an anonymous function) it is declared in.

Operators

+, -, *, / , % ,=,+= and -=

Control structures

  • Conditional statements are supported by if and else

  • while loops and do-while loops.

  • for loop is the same as that in C and Java

1
2
3
4
5
6
7
8
9
10
11
for (var i = 0; i < 5; i++) {
// Will execute 5 times
}

for (let value of array) {
// do something with value
}

for (let property in object) {
// do something with object property
}
  • && and || operators

  • a ternary operator for conditional expressions:

var allowed = (age > 18) ? 'yes' : 'no';

  • switch statement

Objects

objects can be thought of as simple collections of name-value pairs, like HashMaps in Java.

The “name” part is a JavaScript string, while the value can be any JavaScript value — including more objects.

  • two basic ways to create an empty object:

    1
    2
    var obj = new Object();
    var obj = {};

Arrays

1
2
3
4
5
6
7
8
9
var a = new Array();
a[0] = 'dog';
a[1] = 'cat';
a[2] = 'hen';

var b = ['dog', 'cat', 'hen'];

a.length; // 3
b.length;//3
  • terating over an array

    1
    2
    3
    ['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) {
    // Do something with currentValue or array[index]
    });

Functions

A JavaScript function can take 0 or more named parameters. The function body can contain as many statements as you like and can declare its own variables which are local to that function. The return statement can be used to return a value at any time, terminating the function. If no return statement is used (or an empty return with no value), JavaScript returns undefined.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function avg(...args) {
var sum = 0;
for (let value of args) {
sum += value;
}
return sum / args.length;
}

//above defined is equivalent to below

var avg = function() {
var sum = 0;
for (var i = 0, j = arguments.length; i < j; i++) {
sum += arguments[i];
}
return sum / arguments.length;
};

avg(2, 3, 4, 5); // 3.5

Custom objects

JavaScript uses functions as classes.

  • the way to attach a function to an object.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    function makePerson(first, last) {
    return {
    first: first,
    last: last,
    fullName: function() {
    return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
    return this.last + ', ' + this.first;
    }
    };
    }

    var s = makePerson('Simon', 'Willison');
    s.fullName(); // "Simon Willison"
    s.fullNameReversed(); // "Willison, Simon"

    good:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = function() {
    return this.first + ' ' + this.last;
    };
    this.fullNameReversed = function() {
    return this.last + ', ' + this.first;
    };
    }
    var s = new Person('Simon', 'Willison');

    better:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function personFullName() {
    return this.first + ' ' + this.last;
    }
    function personFullNameReversed() {
    return this.last + ', ' + this.first;
    }
    function Person(first, last) {
    this.first = first;
    this.last = last;
    this.fullName = personFullName;
    this.fullNameReversed = personFullNameReversed;
    }

    best:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function Person(first, last) {
    this.first = first;
    this.last = last;
    }
    Person.prototype.fullName = function() {
    return this.first + ' ' + this.last;
    };
    Person.prototype.fullNameReversed = function() {
    return this.last + ', ' + this.first;
    };
  • this refers to the current object.

    What that actually means is specified by the way in which you called that function.

    If you called it using dot notation or bracket notation on an object, that object becomes this.

    If dot notation wasn’t used for the call, this refers to the global object.

  • new is strongly related to this.

    Functions that are designed to be called by new are called constructor functions. Common practice is to capitalize these functions as a reminder to call them with new.

  • Person.prototype is an object shared by all instances of Person.

    prototype chain:any time you attempt to access a property of Person that isn’t set, JavaScript will check Person.prototype to see if that property exists there instead. As a result, anything assigned to Person.prototype becomes available to all instances of that constructor via the this object.

    • JavaScript lets you modify something’s prototype at any time in your program, which means you can add extra methods to existing objects at runtime:

      1
      2
      3
      4
      5
      6
      7
      var s = new Person('Simon', 'Willison');
      s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function

      Person.prototype.firstNameCaps = function() {
      return this.first.toUpperCase();
      };
      s.firstNameCaps(); // "SIMON"
    • the prototype forms part of a chain. The root of that chain is Object.prototype, whose methods include toString() — it is this method that is called when you try to represent an object as a string.

  • The call() method calls a function with a given this value and arguments provided individually.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Product(name, price) {
    this.name = name;
    this.price = price;
    }

    function Food(name, price) {
    Product.call(this, name, price);
    this.category = 'food';
    }

    console.log(new Food('cheese', 5).name);
    // expected output: "cheese"
  • The apply() method calls a function with a given this value, and arguments provided as an array (or an array-like object).

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var numbers = [5, 6, 2, 3, 7];

    var max = Math.max.apply(null, numbers);

    console.log(max);
    // expected output: 7

    var min = Math.min.apply(null, numbers);

    console.log(min);
    // expected output: 2

Inner functions

方法是存储在对象属性中的函数

1
2
3
4
5
6
7
8
9
function parentFunc() {
var a = 1;

function nestedFunc() {
var b = 4; // parentFunc can't use this
return a + b;
}
return nestedFunc(); // 5
}

Closures

1
2
3
4
5
6
7
8
9
function makeAdder(a) {
return function(b) {
return a + b;
};
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6); // returns 11
y(7); // returns 27

Scope objects form a chain called the scope chain, similar to the prototype chain used by JavaScript’s object system.

Other

curly braces

括号()

Spread syntax

省略号

  • The spread syntax is simply three dots: ...
  • It allows an iterable to expand in places where 0+ arguments are expected.

asterisk

星号 *

regular expression

  • 校验含有空格

    reg = /^((?! ).)*$/;

  • 校验只有数字、字母和下划线

    reg = /^[_0-9a-z]*$/;

setInterval

定时调度

What is a Data Structure

a data structure is a container that stores data in a specific layout.

Why do we need Data Structure

As data structures are used to store data in an organized form, and since data is the most crucial entity in computer science.

Based on different scenarios, data needs to be stored in a specific format. We have a handful of data structures that cover our need to store data in different formats.

Commonly used Data Structure

1. Arrays

An array is the simplest and most widely used data structure. Other data structures like stacks and queues are derived from arrays.

  • the two types of arrays:
    • One-dimensional arrays
    • Multi-dimensional arrays
  • basic operations
    • Inserts an element at given index
    • Get — Returns the element at given index
    • Delete — Deletes an element at given index
    • Size — Get the total number of elements in array

2. Stacks

LIFO (Last In First Out)

  • basic operations
    • Push — Inserts an element at the top
    • Pop — Returns the top element after removing from the stack
    • isEmpty — Returns true if the stack is empty
    • Top — Returns the top element without removing from the stack

3. Queues

Similar to Stack, Queue is another linear data structure that stores the element in a sequential manner. The only significant difference between Stack and Queue is that instead of using the LIFO method, Queue implements the FIFO method, which is short for First in First Out.

  • basic operations
    • Enqueue() — Inserts element to the end of the queue
    • Dequeue() — Removes an element from the start of the queue
    • isEmpty() — Returns true if queue is empty
    • Top() — Returns the first element of the queue

4. Linked List

A linked list is like a chain of nodes, where each node contains information like data and a pointer to the succeeding node in the chain.

  • the types of linked lists
    • Singly Linked List (Unidirectional)
    • Doubly Linked List (Bi-directional)
  • basic operations
    • InsertAtEnd — Inserts given element at the end of the linked list
    • InsertAtHead — Inserts given element at the start/head of the linked list
    • Delete — Deletes given element from the linked list
    • DeleteAtHead — Deletes first element of the linked list
    • Search — Returns the given element from a linked list
    • isEmpty — Returns true if the linked list is empty

5. Graphs

A graph is a set of nodes that are connected to each other in the form of a network. Nodes are also called vertices. A pair(x,y) is called an edge, which indicates that vertex x is connected to vertex y. An edge may contain weight/cost, showing how much cost is required to traverse from vertex x to y*.*

  • types of Graphs
    • Undirected Graph
    • Directed Graph

6. Trees

A tree is a hierarchical data structure consisting of vertices (nodes) and edges that connect them. Trees are similar to graphs, but the key point that differentiates a tree from the graph is that a cycle cannot exist in a tree.

  • the types of trees
    • N-ary Tree
    • Balanced Tree
    • Binary Tree
    • Binary Search Tree
    • AVL Tree
    • Red Black Tree
    • 2–3 Tree

    Out of the above, Binary Tree and Binary Search Tree are the most commonly used trees.

7. Trie

Trie, which is also known as “Prefix Trees”, is a tree-like data structure which proves to be quite efficient for solving problems related to strings. It provides fast retrieval, and is mostly used for searching words in a dictionary, providing auto suggestions in a search engine, and even for IP routing.

8. Hash Table

Hashing is a process used to uniquely identify objects and store each object at some pre-calculated unique index called its “key.”

Hash tables are generally implemented using arrays.

  • The performance of hashing data structure depends upon these three factors:
    • Hash Function
    • Size of the Hash Table
    • Collision Handling Method

Here’s an illustration of how the hash is mapped in an array. The index of this array is calculated through a Hash Function.

reference:

系统结构

  • rpc

    1
    2
    Consumer => Provider
    Consumer调用的Provider提供的服务。
    • 同步调用,对于要等待返回结果/处理结果的场景,RPC是可以非常自然直觉的使用方式。
    • 由于等待结果,Consumer(Client)会有线程消耗。
    • RPC也可以是异步调用,如果以异步RPC的方式使用,Consumer(Client)线程消耗可以去掉。但不能做到像消息一样暂存消息/请求,压力会直接传导到服务Provider。
  • message queue

    1
    2
    Sender => Queue <= Receiver
    Sender发送消息给Queue;Receiver从Queue拿到消息来处理
    • Message Queue把请求的压力保存一下,逐渐释放出来,让处理者按照自己的节奏来处理。
    • Message Queue引入一下新的结点,让系统的可靠性会受Message Queue结点的影响。
    • Message Queue是异步单向的消息。发送消息设计成是不需要等待消息处理的完成。

见解

  • 这两者可以拿来比较,但是个人感觉并不是同一个层面的问题。RPC是分布式服务之间调用的一种解决方案,是我们在做架构设计决策时同分布式对象,REST等层面的东西比较,决策的一个方案! 消息系统更多是我们为了解决系统之间的解耦,以及性能问题等方面所考虑的方案。

英文碎片

  • Life is measured by thought and action, not by time.
  • Books and friends should be few but good.
  • Don’t give your past the power to define your future.
  • People will forget what you said, people will forget what you did, but people will never forget how you made them feel.
  • Success isn’t about being the best. It’s about always getting better.
  • Be yourself. Everyone else is already taken.
  • It’s kind of fun to do the impossible.
  • “Simplicity is the ultimate sophistication.”Leonardo da Vinci
  • Build a dream and the dream will build you.
  • Always make a total effort, even when the odds are against you.
  • You can, you should, and if you’re brave enough to start, you will.
  • Never give up, for that is just the place and time that the tide will turn.
  • Awareness is the greatest agent for change.
  • Nothing can dim the light which shines from within.
  • Our dreams can come true if we have the courage to pursue them.
  • Patience and perseverance have a magical effect before which difficulties disappear and obstacles vanish.
  • What you do makes a difference, and you have to decide what kind of difference you want to make.
  • The thing that is really hard, and really amazing, is giving up on being perfect and beginning the work of becoming yourself.
  • You are what you do, not what you say you’ll do.
  • This is the real secret to life—to be completely engaged with what you are doing in the here and now. And instead of calling it work, realize it is play.
  • I am strong because I’ve been weak. I am fearless because I’ve been afraid. I am wise because I’ve been foolish.
  • Every moment you live in the past is a moment you waste in the present.
  • Some changes look negative on the surface, but you will soon realize that space is being created in your life for something new to emerge.
  • The world breaks everyone and afterward many are strong at the broken places.
  • Don’t bury your failures. Let them inspire you.
  • Whether you think you can or you think you can’t, you are right.
  • “An investment in knowledge pays the best interest.”Benjamin Franklin
  • Be brave. Take risks. Nothing can substitute experience.
  • Learn to walk before run
  • This is love, deep in the trenches, worthy of respect, admiration and gratitude.
  • You will learn more in three days of acting than in six months of researching.

中文碎片

  • 虽千万人,吾往矣。
  • 在一个跪下去才能活着的时代,请给站着的人一点掌声!
  • 一个人一旦接触到真相,便无法再回头去相信谎言!
  • 码农不问出处,大佬不看岁数
  • 英雄不问出处,流氓不看岁数
  • 长多大屁股,穿多大裤衩
  • 没有最好的开发语言,只有最好的开发者
  • 能干的人,不在情绪上计较,只在做事上认真;无能的人!不在做事上认真,只在情绪上计较。
  • 把每一次练习都当成一次考试

名人碎片

  • 极深的暴力当中隐藏着极致的温柔 (北野武)

其它碎片

  • arithmetic
    • addition, subtraction, multiplication and division calculations
  • Promise(承诺)、Earnest(诚挚)、Respect(尊重)、Forgiveness(宽容)、Enioy(享受)、Cherish(珍惜)、Trust(信任)
  • In any case, measure, don’t guess! Only a measurement will tell you if the parallelism is worth it or not.(from stack overflow’s someone)

技术碎片

  • compare two things at different points, this not only makes them easy to compare but also makes it easy to remember differences.

版本管理

  • 可以用 nvm 进行管理
1
2
3
4
5
vue项目: npm run dev  会在开发环境下 立即启动项目   

react项目: npm run start 会在开发环境下 立即启动项目

编译打包项目:npm run build

Future and FutureTask

  • A Future interface provides methods to check if the computation is complete, to wait for its completion and to retrieve the results of the computation. The result is retrieved using Future’s get() method when the computation has completed, and it blocks until it is completed.
  • FutureTask
     1. FutureTask implementation Future interface and RunnableFuture Interface, means one can use FutureTask as Runnable and can be submitted to ExecutorService for execution.
     2. When one call Future.submit() Callable or Runnable objects then most of time ExecutorService creates FutureTask, and one can create it manually also.
     3. FutureTask acts like a latch.
     4. Computation represent by FutureTask is implemented with Callable interface.
     5. It implements Future or Callable interface.
     6. Behaviour of get() method depends on the state of the task. If tasks are not completed get() method waits or blocks till the task is completed. Once task completed, it returns the result or throws an ExecutionException.
    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Java program do two FutureTask 
// using Runnable Interface

import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;

class MyRunnable implements Runnable {

private final long waitTime;

public MyRunnable(int timeInMillis)
{
this.waitTime = timeInMillis;
}

@Override
public void run()
{
try {
// sleep for user given millisecond
// before checking again
Thread.sleep(waitTime);

// return current thread name
System.out.println(Thread
.currentThread()
.getName());
}

catch (InterruptedException ex) {
Logger
.getLogger(MyRunnable.class.getName())
.log(Level.SEVERE, null, ex);
}
}
}

// Class FutureTaskExample excute two future task
class FutureTaskExample {

public static void main(String[] args)
{
// create two object of MyRunnable class
// for FutureTask and sleep 1000, 2000
// millisecond before checking again
MyRunnable myrunnableobject1 = new MyRunnable(1000);
MyRunnable myrunnableobject2 = new MyRunnable(2000);

FutureTask<String>
futureTask1 = new FutureTask<>(myrunnableobject1,
"FutureTask1 is complete");
FutureTask<String>
futureTask2 = new FutureTask<>(myrunnableobject2,
"FutureTask2 is complete");

// create thread pool of 2 size for ExecutorService
ExecutorService executor = Executors.newFixedThreadPool(2);

// submit futureTask1 to ExecutorService
executor.submit(futureTask1);

// submit futureTask2 to ExecutorService
executor.submit(futureTask2);

while (true) {
try {

// if both future task complete
if (futureTask1.isDone() && futureTask2.isDone()) {

System.out.println("Both FutureTask Complete");

// shut down executor service
executor.shutdown();
return;
}

if (!futureTask1.isDone()) {

// wait indefinitely for future
// task to complete
System.out.println("FutureTask1 output = "
+ futureTask1.get());
}

System.out.println("Waiting for FutureTask2 to complete");

// Wait if necessary for the computation to complete,
// and then retrieves its result
String s = futureTask2.get(250, TimeUnit.MILLISECONDS);

if (s != null) {
System.out.println("FutureTask2 output=" + s);
}
}

catch (Exception e) {
Sysmtem.out.println("Exception: " + e);
}
}
}
}
1
2
3
4
5
6
7
8
9
Output:

FutureTask1 output=FutureTask1 is complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
Waiting for FutureTask2 to complete
FutureTask2 output=FutureTask2 is complete
Both FutureTask Complete

线程安全是编程中的术语,指某个函数、函数库在并发环境中被调用时,能够正确地处理多个线程之间的共享变量,使程序功能正确完成。即在多线程场景下,不发生有序性、原子性以及可见性问题。

how to avoid deadlock

ConcurrentHashMap faster than Hashtable

ConcurrentHashMap is introduced as an alternative of Hashtable in Java 5, it is faster because of its design. ConcurrentHashMap divides the whole map into different segments and only lock a particular segment during the update operation, instead of Hashtable, which locks whole Map.

submit() and execute() method of Executor and ExecutorService

The main difference between submit and execute method from ExecutorService interface is that former return a result in the form of a Future object, while later doesn’t return a result. By the way, both are used to submit a task to thread pool in Java but one is defined in Executor interface,while other is added into ExecutorService interface.

when to use

  • In general, if you are doing computational task e.g. calculating some risk stats, calculating factorial of large numbers or doing some time-consuming computation e which results in some value then use the submit() method. It immediately returns a Future object, which can be later queried to get the value of computation by calling get() method.
  • Remember, get() is a blocking call so always call the version which accepts a timeout. While you can use the execute() method if you just want your code to be run in parallel by worker threads of the thread pool.
1
2
3
4
5
6
7
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});

future.get(); //returns null if the task has finished correctly.
1
2
3
4
5
6
7
8
Future future = executorService.submit(new Callable(){
public Object call() throws Exception {
System.out.println("Asynchronous Callable");
return "Callable Result";
}
});

System.out.println("future.get() = " + future.get());

ReentrantLock vs synchronized

the advantages of ReentrantLock

  1. Ability to lock interruptibly.

  2. Ability to timeout while waiting for lock.

  3. Power to create fair lock.

  4. API to get list of waiting thread for lock.

  5. Flexibility to try for lock without blocking.

the disadvantages of ReentrantLock

  1. Major drawback of using ReentrantLock in Java is wrapping method body inside try-finally block, which makes code unreadable and hides business logic.

  2. programmer is responsible for acquiring and releasing lock, which is a power but also opens gate for new subtle bugs, when programmer forget to release the lock in finally block.

ReadWriteLock

stop thread

  • There was some control methods in JDK 1.0 e.g. stop(), suspend() and resume() which was deprecated in later releases due to potential deadlock threats, from then Java API designers has not made any effort to provide a consistent, thread-safe and elegant way to stop threads.
  • Programmers mainly rely on the fact that thread stops automatically as soon as they finish execution of run() or call() method. To manually stop, programmers either take advantage of volatile boolean variable and check in every iteration if run method has loops or interrupt threads to abruptly cancel tasks.

ThreadLocal

  • The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to aThreadLocal variable, then the two threads cannot see each other’s ThreadLocal variables.
  • Each thread holds an exclusive copy of ThreadLocal variable which becomes eligible to Garbage collection after thread finished or died, normally or due to any Exception, Given those ThreadLocal variable doesn’t have any other live references.
  • ThreadLocal variables in Java are generally private static fields in Classes and maintain its state inside Thread.

synchronized vs concurrent collection

later is more scalable than former

synchronized collections locks the whole collection e.g. whole Map or List while concurrent collection never locks the whole Map or List. They achieve thread safety by using advanced and sophisticated techniques like lock stripping. For example, the ConcurrentHashMap divides the whole map into several segments and locks only the relevant segments, which allows multiple threads to access other segments of same ConcurrentHashMap without locking.

CopyOnWriteArrayList

CopyOnWriteArrayList allows multiple reader threads to read without synchronization and when a write happens it copies the whole ArrayList and swap with a newer one.

Stack and Heap

  • Each thread has their own stack, which is used to store local variables, method parameters and call stack. Variable stored in one Thread’s stack is not visible to other.
  • heap is a common memory area which is shared by all threads.Objects whether local or at any level is created inside heap.
  • To improve performance thread tends to cache values from heap into their stack, which can create problems if that variable is modified by more than one thread, this is where volatile variables comes in picture. volatile suggest threads to read value of variable always from main memory.
  • If there is no memory left in the stack for storing function call or local variable, JVM will throw java.lang.StackOverFlowError, while if there is no more heap space for creating an object, JVM will throw java.lang.OutOfMemoryError: Java Heap Space
  • Variables stored in stacks are only visible to the owner Thread while objects created in the heap are visible to all thread. In other words, stack memory is kind of private memory of Java Threads while heap memory is shared among all threads.

thread pool

Java API provides Executor framework, which allows you to create different types of thread pools e.g. single thread pool, which process one task at a time, fixed thread pool (a pool of fixed number of thread) or cached thread pool (an expandable thread pool suitable for applications with many short lived tasks).

the benefits

  • Use of Thread Pool reduces response time by avoiding thread creation during request or task processing.

  • Use of Thread Pool allows you to change your execution policy as you need. you can go from single thread to multiple threads by just replacing ExecutorService implementation.

  • Thread Pool in Java application increases the stability of the system by creating a configured number of threads decided based on system load and available resource.

  • Thread Pool frees application developer from thread management stuff and allows to focus on business logic.

volatile vs atomic variable

Volatile variable provides you happens-before guarantee that a write will happen before any subsequent write, it doesn’t guarantee atomicity. For example count++ operation will not become atomic just by declaring count variable as volatile. On the other hand AtomicInteger class provides atomic method to perform such compound operation atomically.

3 multi-threading best practice

  • Always give meaningful name to your thread

  • Avoid locking or Reduce scope of Synchronization

  • Prefer Synchronizers over wait and notify

  • Prefer Concurrent Collection over Synchronized Collection

Wait、Sleep、Yield

  • sleep() and yield() methods are defined in thread class while wait() is defined in the Object class

  • The key difference between wait() and sleep() is that former is used for inter-thread communication while later is used to introduced to pause the current thread for a short duration.

  • This difference is more obvious from the fact that, when a thread calls the wait() method, it releases the monitor or lock it was holding on that object, but when a thread calls the sleep() method, it never releases the monitor even if it is holding.

  • yield() just releases the CPU hold by Thread to give another thread an opportunity to run though it’s not guaranteed who will get the CPU. It totally depends upon thread scheduler and it’s even possible that the thread which calls the yield() method gets the CPU again(有可能自己会再次获取到cpu执行时间). Hence, it’s not reliable to depend upon yield() method, it’s just on best effort basis.

    • If there is no waiting thread or all the waiting threads have a lower priority then the same thread will continue its execution.