Basic

var a = 10; // 
let b = 20; // 作用域以外不可引用,建议尽量用 let
const c = 30;
scope Hoisting Re-declaration
var Function-scoped Yes, undefined if not initialized Yes
let Block-scoped No, must be declared No
const Block-scoped No, must be declared No

String

let s = "Hello, world"

// => "ell": the 2nd, 3rd, and 4th characters
s.substring(1,4)

// => "ell": same thing
s.slice(1,4)

// => "rld": last 3 characters
s.slice(-3)

// => ["Hello", "world"]:
s.split(", ")

// => 2: position of first letter l
s.indexOf("l")

// => true: the string starts with these
s.startsWith("Hell")

// => true: s includes substring "or"
s.includes("or")

// => "Heya, world"
s.replace("llo", "ya")

// => "hello, world"
s.toLowerCase()

// => "H": the first character
s.charAt(0)

// => " x": add spaces on the left to a length of 3
"x".padStart(3)

Template

// greeting == "Hello Bill."
let name = "Bill"
let greeting = `Hello ${ name }.`

Pattern Matching

let text = "testing: 1, 2, 3"
let pattern = /\d+/g

pattern.test(text)
text.search(pattern)
text.match(pattern)
text.replace(pattern, "#")
text.split(/\D+/)

类型转换

// Number to string
let n = 17
let s = n.toString()

// String to number
// => 3
parseInt("3 blind mice")
// => 0.1
parseFloat(".1")

// If the value is a string, wrap it in quotes, otherwise, convert
(typeof value === "string") ? "'" + value + "'" : value.toString()

对象

let square = {
  area: function() { return this.side * this.side; },
  side: 10
};
//等价于
let square = {
  area() { return this.side * this.side; },
  side: 10
};

数组

// forEach
let data = [1, 2, 3, 4, 5], sum = 0
data.forEach(value => { sum += value; })

// map
let a = [1, 2, 3]
a.map(x => x*x)

// filter
let a = [5, 4, 3, 2, 1]
a.filter(x => x < 3)

// find and findIndex
let a = [1, 2, 3, 4, 5]
a.findIndex(x => x === 3)
a.find(x => x % 5 === 0)

// every and some
a.every(x => x < 10)
a.some(isNaN)

// reduce
a.reduce((x,y) => x+y, 0)

// flat and flatMap
[1, [2, 3]].flat()
let phrases = ["hello world", "the definitive guide"]
let words = phrases.flatMap(phrase => phrase.split(" "))

// concat
let a = [1,2,3];
a.concat(4, 5)

// stack and queue
let stack = []
stack.push(1,2)
stack.pop()

let q = []
q.push(1,2)
q.shift()

// subarrays
let a = [1, 2, 3, 4, 5, 6, 7, 8]
a.slice(0,3)
a.splice(4)

// fill
let a = new Array(5);
a.fill(0)

// indexOf
let a = [0, 1, 2, 1, 0]
a.indexOf(1)

// includes
let a = [1, true, 3, NaN]
a.includes(true)

// sort
let a = ["banana", "cherry", "apple"]
a.sort()

// reverse
a.reverse()

// to string
let a = [1, 2, 3]
a.join(" ")
[1,2,3].toString()

遍历

遍历列表

let arr = ["x", "y", "z"]

for (let i = 0; i < arr.length; i++) {
  console.log(arr[i])
}

for (let element of arr) {
  console.log(element)
}

遍历对象

let obj = {"x": 1, "y": 2, "z": 3}

for (let key in obj) {
  console.log(key, obj[key])
}

for (let key of Object.keys(obj)) {
  console.log(key)
}

for (let val of Object.values(obj)) {
  console.log(val)
}

for (let [k, v] of Object.entries(obj)) {
  console.log(k, v)
}

异步遍历

// Read chunks from an asynchronously iterable stream and print them out
async function printStream(stream) {
  for await (let chunk of stream) {
    console.log(chunk);
  }
}

排序

let unorderObj = {"c":"PHP", "d":"Laravel","b": "Html", "a":"Css"}
let orderObj = Object.keys(unorderObj).sort().reduce(function (r, k) {
    (r[k] = o[k], r), {}
})

let unorderArr = [
    {"name": "Tom", "age": 46},
    {"name": "Aack", "age": 26},
    {"name": "Hanson", "age": 16}
],
let orderArr = unorderArr.sort(function(a, b) {
    if(a.name < b.name) { return -1; }
    if(a.name > b.name) { return 1; }
    return 0;
})

对象序列化

let o = {x: 1, y: {z: [false, null, ""]}};
let s = JSON.stringify(o);
let p = JSON.parse(s);

Number and Math

Math object

// power
Math.pow(2,53)
// round
Math.round(.6)
// max
Math.max(x,y,z)
// random
Math.random()
// Pi
Math.PI

Number object

// Infinity
Infinity
Number.POSITIVE_INFINITY

// -Infinity
-Infinity
Number.NEGATIVE_INFINITY

// NaN
NaN
Number.NaN

// parseInt
parseInt()
Number.parseInt()

// parseFloat
parseFloat()
Number.parseFloat()

// isNaN
Number.isNaN(x)

// isFinite
Number.isFinite(x)

// isInteger
Number.isInteger(x)

// isSafeInteger
Number.isSafeInteger(x)

// MIN_SAFE_INTEGER = -(2**53 - 1)
Number.MIN_SAFE_INTEGER

// MAX_SAFE_INTEGER = 2**53 - 1
Number.MAX_SAFE_INTEGER

// EPSILON = 2**-52: smallest difference between numbers
Number.EPSILON

Date

// The current time as a Date object
let now = new Date()

// The current time as a timestamp (a number)
let timestamp = Date.now()

// Convert to a millisecond timestamp
let ms = now.getTime()

// Convert to a string in standard format
let iso = now.toISOString()

Function

function hello () {
    return "Hello world!"
}

// with parameters
function hello (name) {
    return "Hello " + name + "!"
}

// 匿名函数
function (name) {
    return "Hello " + name + "!"
}

// Arrow function
hello = () => { // 等价于 hello = function() {
  return "Hello World!";
}

// 省略 `{}` 和 `return`
hello = (name) => "Hello " + name + "!";
hello = (firstName, lastName) => "Hello " + firstName + " " + lastName + "!";
// 只有一个参数时,括号可以省略
hello = name => "Hello " + name + "!";

// 箭头函数并没有 this, 会作为变量一直向上级词法作用域查找,可能导致 bug

P.S.:

  • 函数只能有一个返回值,如果需要返回多个值,可以把它们放到对象或数组中返回

异步

Promise

A Promise is an object that represents the result of an asynchronous computation

  • 同步函数调用会被放入 Call Stack
  • Promise callback function 会被放入 Microtask Queue
  • setTimeout, setInterval 等异步 web APIs 会被放入 Task Queue
  • Event Loop 会一直检查 call stack,当其为空时会将 microtask queue 中的 callback function 放入 call stack,当 call stack 和 microtask queue 均为空时才会处理 task queue

创建 Promise 对象

let myPromise = new Promise((resolve, reject) => {
  // do something may not get result immediately
  const v = Math.random()
  console.log(v)
  if ( v > 0.5 ) { // some condition
    // case on some condition
    // call resolve callback function and pass result data as argument
    resolve({ data: 'Here is your data!' })
  } else {
    // case on other condition
    // call reject callback function and pass error as argument
    reject(new Error('Network error'))
  }
})
console.log("promise defined")

上述代码在 Promise 对象创建时会立即允许里面代码,在调用 resolve(res)/reject(err) 时会改变 Promise 对象的状态,这时 Promise 会进入成功/失败状态

调用 Promise.thenPromise.catch 会将里面的 callback 函数放入 microtask queue,等待 Promise 进入成功/失败状态后且 同步代码运行完后调用 callback 函数

// code in the Promise block get executed when created
// code in the `then/catch` block wait until the Promise enter resolved/rejected state
myPromise
  .then(result => {
    console.log('Data:', result.data)
  })
  .catch(error => {
  	console.error('Error:', error.message)  
  })

定义异步函数

function fetchData() {
  return new Promise((resolve, reject) => {
    console.log(Date.now() + ": promise start")
    const v = Math.random()
    if (v > 0.5) {
      resolve({ data: "hello" })
    } else {
      reject(new Error('Network error'))
    }
    console.log(Date.now() + ": promise end")
  })
}

这时 Promise 内部的代码并不是立即执行,而是在调用 fetchData 函数时执行,下面的代码会立即执行 Promise 的内容,并等待 Promise 状态改变后执行传入 then/catch 的回调函数

fetchData()
  .then((res) => {
    console.log(Date.now() + ": promise resolved")
    console.log(res.data)
  })
  .catch((err) => {
    console.log(Date.now() + ": promise rejected")
  })

链式调用:传入 .then(callback1) 的回调函数可以返回值,这个值会作为参数被传到下一个 .then(callback2) 的回调函数

let promise = new Promise((resolve, reject) => {
    resolve(1)
  })
  
promise
.then(res => {
    console.log(res) // 输出 1
    return res + 1
})
.then(res => {
    console.log(res) // 输出 2
    return res + 1
})
.then(res => {
    console.log(res) // 输出 3
    return res + 1
})

如果回调函数返回了一个 Promise 对象,那么下一个 .then(callback) 同样会等待上一个回调函数的执行

promise
  .then(value => {
    return new Promise(resolve => {
      setTimeout(() => {
        resolve(value + 1);
      }, 1000);
    });
  })
  .then(value => {
    console.log(value); // 输出 2,但是在 1 秒后
  });

await/async

是 ES7 中引入的新特性,具体用法如下

async function 关键字定义的函数,自动将返回值包装成一个 Promise,如果正常返回就是 resolved 状态,如果有异常则为 rejected 状态

async function asyncSleep(time) {
  setTimeout(() => {
    console.log(Date.now() + ": asyncSleep")
  }, time * 1000)
}
// 等价于
function sleep(time) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      console.log(Date.now() + ": sleep")
    }, time * 1000)
    resolve()
  })
}

await 只能用在用 async 定义的函数内部, 用于暂停执行等待某个 async 函数的返回

function sleep(time) {
  return new Promise((resolve, reject) => { setTimeout(() => {
      console.log(Date.now() + ": sleep")
    }, time * 1000)
    resolve()
  })
}

async function asyncSleep(time) {
  console.log(Date.now() + ": asyncSleep start")
  await sleep(time)
  console.log(Date.now() + ": asyncSleep end")
}

asyncSleep(1)
  .then(() => {
    console.log(Date.now() + ": asyncSleep resolved")
  })

模块

Node.js

Export

// Define all the functions, public and private
const sum = (x, y) => x + y;
const square = x => x * x;
const mean = data => data.reduce(sum)/data.length;
const stddev = d => {
  let m = mean(d);
  return Math.sqrt(d.map(x => x - m).map(square).reduce(sum)/(d.length-1));
};

// Now export only the public ones
module.exports = { mean, stddev };

Import

// 导入 built-in 包
const fs = require("fs");
const http = require("http");

// 导入第三方包
const express = require("express");

// 导入文件
const stats = require('./stats.js');
const BitSet = require('./utils/bitset.js');

ES6

Export

const PI = Math.PI;
function degreesToRadians(d) { return d * PI / 180; }
class Circle {
  constructor(r) { this.r = r; }
  area() { return PI * this.r * this.r; }
}

export { Circle, degreesToRadians, PI };

Import

import * as stats from "./stats.js";

// dynamic import
import("./stats.js").then(stats => {
  let average = stats.mean(data);
})

async analyzeData(data) {
  let stats = await import("./stats.js");
  return {
    average: stats.mean(data),
    stddev: stats.stddev(data)
  };
}

注意

null and undefined

null: a special object value that indicates “no object” undefined: the value of variables that have not been initialized and the value you get when you query the value of an object property or array element that does not exist.

== and ===

===: strict equality

==: allow type conversion

Typescript

Learning Resources