语言

程序语言

c #

库
    libvirt

c++ #

问题
    野指针、迷途指针 Double Free问题
    智能指针
    RAII资源获取就是初始化
    二级指针
库
    opencv
            iplimage
                    # 图像处理

php #

安装
        php, php-cgi, php-fpm
    编译安装
        yum install libxml2-devel  openssl-devel  bzip2-devel libmcrypt-devel  -y
        ./configure --prefix=/opt/zly/php --with-mysql=mysqlnd --with-openssl --with-mysqli=mysqlnd --enable-mbstring --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-libxml-dir=/usr --enable-xml  --enable-sockets --enable-fpm --with-mcrypt  --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-bz2
        make
        make install
        cp php.ini-production /etc/php.ini
        cp sapi/fpm/init.d.php-fpm /etc/rc.d/init.d/php-fpm
        chmod +x /etc/rc.d/init.d/php-fpm
        cp /opt/zly/php/etc/php-fpm.conf.default /opt/zly/php/etc/php-fpm.conf
        chkconfig --add php-fpm
        chkconfig php-fpm on
        /etc/init.d/php-fpm start
命令
        php -S localhost:8000 -t dir/
配置
        /etc/php/php.ini
        date.timezone = Europe/Berlin
            # 时区设置
        display_errors = On


框架
    zend opcache
        # php5.5集成,把php执行后的数据缓冲到内存中从而避免重复编译
工具
    fpm
        # php fastCGI 进程管理器

scheme #

# 特点
    词法定界(Lexical Scoping)
    动态类型(Dynamic Typing)
    良好的可扩展性
    尾递归(Tail Recursive)
    函数作为值返回
    计算连续
    传值调用(passing-by-value)
    算术运算相对独立
# 标准
    R5RS (Revised5 Report on the Algorithmic Language Scheme)
    Guile (GNU's extension language)
# guile脚本中(.scm)
    #! /usr/local/bin/guile -s
    !#

# 语法
    注释
        ;
                # 注释到行尾
        #! ... !#
                # 标准中没有,实现中有的多行注释
    类型
        1
        'symbol
        "str"
        true, false
        struct
        empty
            # 表示一个空表
    块(form)
        (define x 123)
        (set! x "abc")
        (+ 1 2)
        (* (+ 2 (* 3 4)) (+ 5 6 7))
        (display "hello world")
        (not #f)
            # #t
        (not #t)
            # #f
            # not 后不是逻辑型,都返回#f

    非精确数
        (- #i1.0 #i0.9)
    函数
        or
        and
        not
        (sqrt A)
        (expt A B)
            # A^B
        (remainder A B)
            # A%B
        (log A)
            # A的自然对数
        (sin A)
        (cond
            [(< n 10) 5.0]
            [else .06])
        (if (< x 0)
            (- x)
            x)
        (symbol=? 'Hello x)
            # 符号,比较。符号还有字符串和图像
        (string=? "the dog" x)
            # 字符串,系统看作符号
        (make-posn 3 4)
            # 创建posn结构体
            (poson-x (make-posn 7 0))
                # 7
        (define-struct posn (x y))
            # 定义结构体
        (number?)
        (boolean?)
        (struct?)
        (zero?)
        (posn?)
            # 可以是自定义结构体名
        (null?)
            # 检查是否空list
        (eq? i list)
            # 元素i是否在list中, 否返回false, 是返回所在的子表
            # 可以比较符号
        (memq)
            # eq?的内部调用
        (error ''checked-number "number expected")
            # 马上出错
        (cons 'Mercury empty)
            # push
            (cons? alon)
                # 是否有元素
            (define x (cons 1 2))
                # 序对, 可嵌套
                (car x)
                    # 1
                (cdr x)
                    # 2
        (define (dispatch m)
            # 传0返回x, 传1返回y
            (cond ((= m 0) x)
                ((= m 1) y)
                (else (error "" m))))
        (first)
        (rest)
        (list (list 'bob 0 'a) (list 'car1 1 'a))
        (local)
            # 局部定义使用
        (lambda)
            # 匿名函数
        (append)
        (set! x 5)
# 例子
    复合数据
        (define-struct student (last first teacher))
        (define (subst-teacher a-student a-teacher)
            (cond
                [(symbol=? (student-teacher a-student) 'Fritz)
                    # 如果教师的名字是'Fritz
                    (make-student (student-last a-student)
                        # 创建student结构体,设置新教师名
                        (student-first a-student)
                        a-teacher)]
                [else a-student]))
    递归列表
        (define (contains-doll? a-list-of-symbols)
            (cond
                [(empty? a-list-of-symbols) false]
                [else (cond
                    [(symbol=? (first a-list-of-symbols) 'doll) true]
                    [else (contains-doll? (rest a-list-of-symbols))])]))
    排序
        (define (sort alon)
            (cond
                [(empty? alon) empty]
                [(cons? alon) (insert (first alon) (sort (rest alon)))]))
        (define (insert n alon)
            (cond
                [(empty? alon) (cons n empty)]
                [else (cond
                    [(>= n (first alon)) (cons n alon)]
                    [(< n (first alon)) (cons (first alon) (insert n (rest alon)))])]))
    or函数
        (define (blue-eyed-ancestor? a-ftree)
            (cond
                [(empty? a-ftree) false]
                [else (or (symbol=? (child-eyes a-ftree) 'blue)
                    (or (blue-eyed-ancestor? (child-father a-ftree))
                        (blue-eyed-ancestor? (child-mother a-ftree))))]))
    列表替换
        (define (replace-eol-with alon1 alon2)
            (cond
                ((empty? alon1) alon2)
                (else (cons (first alon1) (replace-eol-with (rest alon1) alon2)))))
    列表相等
        (define (list=? a-list another-list)
            (cond
                [(empty? a-list) (empty? another-list)]
                [(cons? a-list)
                    (and (cons? another-list)
                        (and (= (first a-list) (first another-list))
                            (list=? (rest a-list) (rest another-list))))]))
    匿名函数
        (define (find aloir t)
            (filter1 (local ((define (eq-ir? ir p)
                (symbol=? (ir-name ir) p)))
                    eq-ir?)
                aloir t))
        (lambda (ir p) (symbol=? (ir-name ir) p))
    快速排序
        (define (quick-sort alon)
            (cond
                [(empty? alon) empty]
                [else (append
                    (quick-sort (smaller-items alon (first alon)))
                    (list (first alon))
                    (quick-sort (larger-items alon (first alon))))]))
        (define (larger-items alon threshold)
            (cond
                [(empty? alon) empty]
                [else (if (> (first alon) threshold)
                    (cons (first alon) (larger-items (rest alon) threshold))
                    (larger-items (rest alon) threshold))]))
        (define (smaller-items alon threshold)
            (cond
                [(empty? alon) empty]
                [else (if (< (first alon) threshold)
                    (cons (first alon) (smaller-items (rest alon) threshold))
                    (smaller-items (rest alon) threshold))]))

erlang #

特点
    由爱立信所辖CS-Lab开发,目的是创造一种可以应对大规模并发活动的编程语言。易于编写分布式应用。
    面向并发(concurrent-oriented)
            在语言中定义了erlang进程的概念和行为,使它特别经量级(309字节),创建和结束一个进程时间为1-3ms
            该进程(绿进程)在rlang虚拟机内管理和高度,是用户态进程
            进程堆栈占用233字节
            erlang虚拟机支持几十万甚至更多进程
    结构化,动态,函数式

lisp #

介绍
    为人工智能开发的函数语言
    目前最主要两大方言为scheme和commonLisp。Emacs扩展语言为Lisp,有一种Emacs Lisp语言
    拥有理论上最高的运算能力

编译器
    sbcl
            # steel bank common lisp

lua #

介绍
    lua语言,来实现逻辑。 c/c++来实现功能
    eclipse ldt 来开发(cdt 再安装 ldt 使用更方便)
使用
    lua Hello.lua                # 执行脚本
    luac Hello.lua                # 编译字节码
    #-> lua luac.out
语法
    --                # 注释
    num = 10                # 定义

perl #

标准
    pcre: Perl Compatible Regular Expressions

prolog #

介绍
    programming in logic缩写, 是一种逻辑编程语言。广泛应用于人工智能
    不是真正意义上的程序,运行步骤由计算机决定。没有if, when, case, for这样的控制流程语句
    很难分清哪些是程序,哪些是数据,程序就是数据,是一个智能数据库
    有强大的递归功能。

R #

介绍
    本身是GNU的一个开源软件
    用于统计分析、绘图
    是S语言的一个分支(实现)
特点
    数据存储和处理
    数组运算(向量、矩阵运算强大)

D #

# 并发

ruby #

工具
    gems
        gem update --system

rust #

介绍
    mozilla开发的,注重安全, 性能, 并发的系统编程语言
    js之父Brendan Eich设计

scala #

介绍
    haskell衍生语言
    集成了面向对象和函数语言的特性
    可以很简单地与已有的java代码交互,只需要反java相关类导入就可以了
    面向对象语言同时结合命令式和函数式编程风格
工具
    sbt
        simple build tool
语法
    表达式
        actor1 ! case1          # 异步消息
        actor1 !? case1         # 同步消息, 需要对方一定返回
        actor1 !! case1         # 异步消息, 需要对方一定返回
    Actor
        o->
        import scala.actors.Actor

        class HelloActor extends Actor {
        def act() {
            while (true) {
            receive {
                case name: String => println("Hello, " + name)
            }
            }
        }
        }

        val helloActor = new HelloActor
        helloActor.start()
        helloActor ! "leo"
    case                        # 模式匹配
        case class Login(username: String, password: String)
        class UserManageActor extends Actor {
        def act() {
            while (true) {
            receive {
                case Login(username, password) => println(username + password)
            }
            }
        }
        }
        val userManageActor = new UserManageActor
        userManageActor.start()
        userManageActor ! Login("leo", "1234")

.net #

objective-c #

swift #

groovy #

    # 基于jvm,结合python, ruby, smalltalk的特性

dart #

    # 谷歌发布的基于javascript的编程语言

hack #

    # facebook开发的基于HHVM,可与PHP无缝对接
    特点
            结合了PHP开发高效性同时,有了静态语言的报错特性
            支持lambda表达式和强制返回等流行特性

roy #

    # 可编译到js

elm #

    # 可编译到js

jujia #

    # 动态语言,用于科学和数值计算

Fortran #

    # 最早出现的高级语言,用于工程计算领域

ML #

    # meta language, 非纯函数式编程,允许副作用和指令式编程

OCaml #

    # 在caml上加上oo, 源于ML

simula #

    # 专注于仿真的语言,由类创建的对象会在协调的多线程模式下,像erlang的进程一样并行处理

Haskell

介绍 #

源于ML
标准化的、纯函数式编程语言
非限定性语义和强静态类型
作为其他语言设计新功能时的样板,如Python的lambda标记语句

工具 #

检索函数用http://www.Haskell.org/hoogle

单词 #

polymorphism
    # 多态
monomorphic
    # 单态

风格 #

point free style
    sum' xs = foldl (+) 0 xs
    sum' = foldl (+) 0

注意 #

使用缩进代替括号,但也可用括号

文件扩展名 #

# 文件中不用let定义变量, 
# 变量赋值两次会报错, 这意味着代码顺序不重要
hs

内置变量 #

pi

模块 #

:m Data.Char Data.Map
    # 加载模块
    chr
        # chr :: Int -> Char
    ord
        # ord :: Char -> Int
    toUpper
    toLower
import Data.Char
    # 导入到全局命名空间
    import Data.List (nub, sort)
    import Data.List hiding (nub)
    import qualified Data.Map as M
        # 这样其中命名冲突的filter, null函数,只能用Data.Map.filter或M.filter方式调用
可用模块
    prelude
        # 默认载入的模块
    Data
        Char
        List
        Map
        Set
自定义模块
module Geometry.Sphere
(sphereVolume
, sphereArea
, Shape(..)
    # 导出类型和其所有构造子
) where
sphereVolum :: Float -> Float
sphereVolum radius = (4.0 / 3.0) * pi * (radius ^ 3)

命令函数 #

:load
    # 加载模块
    :load a.hs
:l
:cd
    # 切换工作目录
    :cd c:\a
:reload
    # 重载所有模块
:r
:type
    :type 'H'
:t
:info
    # 查看一个typeclass有哪些instance和subclass
    # 类型的信息、函数的类型声明
:k
    # 查看kind
    :k Int
        # Int :: *
    :k Maybe
        # Maybe :: * -> *

操作符 #

%
    # 分号
&&
||
++    
    # 字符串拼接
/=
    # 不等
do
    # 动作的combine, do 是>>=的语法糖, 用来连接一系列动作
<-
    # name <- getLine, 存到变量
    # 除了程序的最后一行用来作返回值,其它语句都可以用 <-

表达式 #

# 表达式可以随处安放
if x < 0 then
    -1
else if x > 0 then
    1
else
    0

case x of
    0 -> 1
    1 -> 5
    _ -> (-1)

let a = 1
    # 局部绑定, in可省略则定义到全局
    twice_a = 2 * a
in (a + twice_a, a - twice_a)
    
let boot x  y z = x * y + z in boot 3 4 2

I/O action #

# 在main中 I/O action才被执行
# return () 语句产生I/O action, do接着执行
# 执行后会打印结果,结果为()时不打印
main = do
    _ <- putStrLn "a"
    name <- getLine
    putStrLn (name)

类型表示 #

Eq a => a -> a -> Bool
    # => 前面是类型约束, 后面表示传入两个同类型参数,返回Bool类型

变量 #

let pi = 3.14
    # 变量不可变,但可重复定义
(-1)
    # 负数一般加小括号
  let r = 25 :: Double
    # 默认猜测是Integer
    # monomorphish restriction(单一同态限定)原理,可以指定polymorphic(多态)
    ## let r = 25 :: Num a => a
True, False
    # 类型为 Bool
"abc"
    # 类型为[char], 与'a':'b':'c':[]
    a = "aaa" :: String
        # 得到一个String, 与[char]同样使用
LT, GT, EQ

函数 #

# 函数名与参数,参数与参数之间有空格隔开
# 函数比运算符先结合
let area r = pi * r ^ 2
    # 定义函数, 
area 2
area (-2)
let area2 r = area r
let first (x, y) = x
    # 接收元组
uppercase, lowercase :: String -> String
    # 指定函数类型
分段定义
    # 编译成case语句
    f 0 = 1
    f 1 = 5
    f _ = -1
函数合成调用
    square (f 1)
    (square . f) 1
(\xs -> length xs > 15)
    # lambda表达式
    # lambda可以用模式匹配,但使用不了多个模式

列表 #

# 列表,类型必须相同。
# 列表都由[]追加得到,逗号是语法糖
let n = [1, 2]
[1..20]
    # range浮点数不精确
take 20 [1,2..]
[2,4..20]
['a'..'z']
0:n
    # 得到追加列表[0, 1, 2], 头部追加叫作consing, cons是constructor
    # -1:0:n
[[1], [2]]
n !! 1
    # 取元素
l1 > l2
    # 元素依次比较
[x*2 | x <- [1..10], x*2 >= 12]
    # list comprehension
    boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <-xs, odd x]
    [x*y | x <-[1,2], y <-[3,4]]
        # 聚合得[3,4,6,8]
    length' xs = sum [1 | _ <- xs]

    xxs = [[1,2], [3,4]]
    [[x | x <- xs, even x] | xs <- xxs]

    [(a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 = c ^2]

    [a + b | (a,b) <- xs]
        # list comprehension中的模式匹配
模式匹配
    x:xs
    x:y:z:xs

元组 #

# 类型可不同,不能单元素。2元组叫pairs, 3元组叫triples, n元组叫n-tuple
# 元组不可变
# 元组的类型由长度和其中的类型决定, ("a", 1)与(1, "a")是不同的类型,所以[("a", 1), (2, "b")]是错误的
(True, 1)
((1,2), True)

monad #

o-> do
doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    if (read guess) < num
    then do putStrLn "Too low"
        doGuessing num
    else if (read guess) > num
    then do putStrLn "Too high"
        doGuessing num
    else putStrLn "You Win"
        # 只有一个动作时,可省略do

o-> do
doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    case compare (read guess) num of
        LT -> do putStrLn "Too low"
        GT -> do putStrLn "Too high"
        EQ -> putStrLn "You Win"

o-> functor applicative monad
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
pure :: a -> f a
() :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> y
fail :: String -> m a
fail msg = error msg
instance Functor Maybe where
fmap func (Just x) = Just (func x)
fmap func Nothing  = Nothing
instance Applicative Maybe where
pure = Just
Nothing  _ = Nothing
(Just func)  something = fmap func something
instance Monad Maybe where
return = Just
Nothing >>= func = Nothing
Just x >>= func  = func x

内置函数 #

prelude
    $
        # 函数调用符,优先级最低。而空格是最高优先级
        # $右结合。而空格左结合
        # 等价于在右而写一对括号
    .
        # f . g = \x -> f (g x)
        # 函数组合
    main
        # main :: IO ()
        main = do
    signum
        # 根据数字返回 -1, 0, 1
    not
    id
        # identity
    unlines
        unlines ["a", "b"]
            # 成为 "a\nb\n"
    unwords
        unwords ["a", "b"]
            # 成为 "a b"
    show
        # 接受各种类型,转换为String, 再转义打印
    read
        read "5" :: Int
        read "5" - 2
        read "[1,2,3]" ++ [4]
    reads
        # 读取失败返回[]而不报错
    negate
        # 取反数字
    abs
        # 绝对值
    length
        # 列表的长度, [a] -> Int , a在这里是一个type variable, 以小写字母开头(具体类型都大写开头)。
    map
    compare
        # 返回 LT, GT, EQ其中一个
    min
    max
    compare
        # 返回LT, GT, EQ
        "Abc" `compare` "Zyx"
    mod
        # 取模
    odd
        # 奇数
    even
        # 偶数
    succ
        # 取Enum的后继
    pred
        # 取Enum的前置
    minBound
        # 取Bound下限
    maxBound
    substract
        # 减

    head
    tail
        # 除第一个
    last
    init
        # 除最后一个

    null
        # 检查list是否空
    reverse
        # list反转
    take
        take 1 [1,2,3]
    takeWhile
        # 取list值,直到某条件
    drop
        drop 1 [1,2,3]
    maximum
        # list中最大元素
    minimun
        # list中最小元素
    sum
        # list和
    product
        # list积
    elem
        # 判断元素是否在list中
        4 `elem` [3,4,5]
    cycle
        take 7 (cycle [1,2,3])
            # [1,2,3,1,2,3,1]
    repeat
        repeat 5
    replicate
        replicate 3 10
            # [10, 10, 10]

    fst (1, 2)
        # 只适合2元组
    snd (1, 2)
        # 只适合2元组
    zip
        # zip3, zip4 ... zip7
        zip [1,2,3] [4,5,6]
            # [(1,4), (2,5), (3,6)]
    zipWith
        # zipWith1 ... zipWith7
        zipWith (\x y -> x + y) [1,2] [3,4]
            # [4,6]
    fromIntegral
        # 返回更通用的数字类型
    error ""
        # 抛错
    flip
        # 翻转两个参数调用
    map
    filter
    foldl
        foldl (\acc x -> acc + x) 0 xs
    foldr
        foldr (\x acc -> f x : acc) [] xs
    foldl1
        # 以第一个元素为初始值,空list报错
    foldr1
    foldl'
        # foldl的strict版
    foldr'
    scanl
        # 返回累加过程的list
    scanr
    scanl1
    scanr1
    o-> I/O action
        # 只有在main中执行
        # 类型为 IO a
        putStrLn
            # 只接受String,不转义打印,加换行符
            # putStrLn :: String -> IO () , 表示接收String, 是IO动作, 结果类型是()。表示是一个"IO monad"动作
        putStr
            # 由putChar递归定义,边界条件是空字符串
        putChar
        print
            # 打印Show typeclass的值
        getLine
            # 控制台读一行
            # getLine :: IO String
            name <- getLine
        getChar
        sequence
        # 顺序执行I/O action
        mapM
            mapM print [1,2,3]
                # 对list元素执行sequence f
        mapM_
            # 同mapM,不打印[(),()]
        getContents
            # 读直到 eof (ctrl + d)
        interact
            # 用函数处理输入,返回到输出
Data.List
    # 每个元素存在thunk中
    \
        # 差集
        [1..3] \\ [2]
            # [1,3]
        "Im a big baby" \\ "big"
            # "Im a baby"
    union
    intersection
    insert
        # 插入一个元素到可排序list相对位置
    nub
        # 去重复元素,常用Set转换取代,提高很多效率
    map
        # 导出到了prelude
    filter
        # 导出到了prelude
    intersperse
        intersperse '.' "abc"
            # "a.b.c"
    intercalate
        # 同intersperse, 但插入list
    transpose
        # 二元list列为行
    foldl'
        # fold的严格版,直接计算出中间值,而非用惰性"承诺"塞满堆栈
    foldl1'
    concat
        # 移除一级嵌套
    concatMap
        # 先map再concat
        concatMap (replicate 2) [1..3]
            # [1,1,2,2,3,3]
    and
        # list中全true返回true
        and $ map (>4) [5,6,7,8]
    or
    any
    iterate
        # 无限迭代值到函数,结果形成list
        take 10 $ iterate (*2) 1
    splitAt
        # 断开list, 返回二元组
        splitAt 3 "abcdef"
            # ("abc", "def")
    takeWhile
        # 取元素,直到不符合条件
    dropWhile
    span
        # 同takeWhile, 不过返回分割list的二元组
    break
        # 同span, 但在条件首次为true时断开
    sort
        # list元素要求Ord类型,排序list
    group
        # 合并相邻并相等的list元素
    inits
        # init递归调用自身
        inits "abc"
            # ["", "a", "ab", "abc"]
    tails
        # tail递归调用自身
        tails "abc"
            # ["abc", "bc", "c", ""]
    isInfixOf
        # list中搜索子list, 有则返回true
        "cat" `isInfixOf` "im a cat"
    isPrefixOf
        # 是否以某list开头
    isSuffixOf
        # 是否以某list结尾
    elem
        # 是否包含某元素
    notElem
    partition
        # 条件划分list为二元组
        partition (`elem` ['A'..'Z']) "AbCD"
            # ("ACD", "b")
    find
        # 条件查找list, 返回第一个符合元素的Maybe值
    elemIndex
        # 返回elem第一个元素的索引的Maybe值
    elemIndices
        # 返回所有匹配索引的list
    findIndex
    findIndices
    lines
        # 字符串分行到list
    unlines
    words
        # 字符串分词到list
    unwords
    delete
        # 删除list中第一个匹配元素
        delete 'h' "hha"
            # "ha"
    replace
    lookup
        # 用a查找[('a', 'b')]中的b
    genericLength
        # 换Int类型为Num类型
    genericTake
    genericDrop
    genericSplitAt
    genericIndex
    genericReplicate

    nubBy
        # 传递函数判断相等性,取代==
    deleteBy
    unionBy
    intersectBy
    groupBy
    sortBy
    insertBy
    maximumBy
    minimumBy
Data.Monoid
    Monoid
    Product
    Sum
    Any
    All
Data.Foldable
    foldr
    foldl
    foldr1
    foldl1
Data.Function
    on
        ((==) `on` (> 0))
            # 判断相等性,等价于 (\x y -> (x > 0) == (y > 0))
        (compare `on` length)
            # 判断大小
Data.Char
    isControl
        # 是否控制字符
    isSpace
        # 包括空格, tab, 换行等
    isLower
    isUpper
    isAlpha
        # 是否字母
    isAlphaNum
        # 字母或数字
    isPrint
        # 可打印
    isDigit
    isOctDigit
    isHexDigit
    isLetter
        # 同isAlpha
    isMark
        # unicode注音字符
    isNumber
    isPunctuation
        # 是否标点符号
    isSymbol
        # 货币符号
    isSeperater
        # unicode空格或分隔符
    isAscii
        # unicode 前128位
    isLatin1
        # unicode 前256位
    isAsciiUpper
    isAsciiLower
    GeneralCategory
        # 得到字符的分类,一共31类, 属于Eq类型
        generalCategory ' '
            # Space
    toUpper
    toLower
    toTitle
    digitToInt
        # 数字,大小写字母list 转成 int list
    intToDigit
    ord
    char
Data.Map
    # 用avl树实现
    fromList
        # 重复键会忽略,要求key有相等性和排序性
    fromListWith
        # 重复键给函数处理
    toList
    empty
        # 返回空map
    insert
        insert 3 10 map
    insertWith
        # 已包含键时函数处理
    null
        # 检查map是否空
    size
        # 返回map的大小
    singleton
        singleton 3, 9
            # fromList [(3,9)]
    lookup
    member
        # key 是否在map中
    map
    filter
    keys
    elems
Data.Set
    # 要求元素可排序,自动排序、唯一
    # 用avl树实现
    fromList
    intersection
    difference
        # 存在于第一集合而不在第二集合的元素
    union
    null
    size
    member
    empty
    singleton
    insert
    delete
    isSubsetOf    
        # 子集
        fromList [1,2] isSubsetOf fromList [1,2]
    isProperSubsetOf
        # 真子集
    filter
    map
Data.ByteString
    # strict bytestring
    # Empty相当于[], cons相当于:
Data.ByteString.Lazy
    # 每个元素存在chunk中,每个chunk 64k,每个chunk相当于一个strict bytestring
    # cons在chunk不满的时候会新建chunk, cons'是strick版的cons, 会填充chunk
    pack
        # pack :: [Word8] -> ByteString
        pack [80,81]
    unpack
    fromChunks
        # 转换strick bytestring 到lazy
    toChunks
        # lazy转strick
Data.Ratio
Control.Applicative
    Applicative
        class (Functor f) => Applicative f where
            pure :: a -> fa
            (<*>) :: f (a -> b) -> f a -> f b
            f <$> x = fmap f x
    ZipList
        ZipList3
        ZipList7
    getZipList
    liftA2
        liftA2 f x y = f <$> x <*> y 
    sequenceA
Control.Monad
    when
        # Bool true时,返回后面的I/O action, 否则return ()
    forever
        # 不断执行后面的I/O action
        forever $ do
            putStr "a"
    forM
        # 同mapM, 但两个参数顺序相反
    liftM
        # monad中的fmap
    liftM2 liftM3 liftM4 liftM5
    `ap`
        # monad中的<*>
    join
        join :: (Monad m) => m (m a) -> m a
        join mm = do
            m <- mm
            m
    filterM
    foldM
Control.Monad.State
    State
        newtype State s a = State {runState :: s -> (a, s)}
    get
    put
Control.Monad.Error
System.IO
    openFile
        # openFile :: FilePath -> IOMode -> IO Handle
        # data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
        do
        handle = openFile "a.txt" ReadMode
        contents <- hGetContents handle
        putStr contents
        hClose handle
    withFile
        # withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
        # 处理完关掉
        withFile "a.txt" ReadMode (\handle -> do
            contents <- hGetContents handle
            putStr contents)
    readFile
        # readFile :: FilePath -> IO String
        do
        contents <- readFile "a.txt"
        putStr contents
    wirteFile
        # writeFile :: FilePath -> String -> IO ()
        do
        writeFile "a.txt" contents
    appendFile
    hSetBuffering
        # 读binary file时的buffer,默认是系统值
        # data BufferMode = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
        hSetBuffering handle $ BlockBuffering (Just 2048)
    hFlush
        # 写入时自动Flush
    openTempFile
        (tempName, tempHandle) <- openTempFile "." "temp"
    hGetContents
    hClose
    hGetLine
    hPusStr
    hPutStrLn
    hGetChar
System.IO.Error
    catch
        # catch :: IO a -> (IOError -> IO a) -> IO a
        toTry `catch` handler
        handler e
            | isDoesNotExistError e = 
                case ioeGetFileName e of Just path -> putStrLn $ "a" ++ path
                    Nothing -> putStrLn "b"
            | otherwise = ioError e
    isDoesNotExistError
    isAlreadyExistsError
    isFullError
    isEOFError
    isIllegalOperation
    isPermissionError
    isUserError
    ioeGetFileName
        # ioeGetFileName :: IOError -> Maybe FilePath
    ioError
        # 丢出接到的error
System.Directory
    removeFile
        removeFile "a.txt"
    renameFile
        renameFile tempName "a.txt"
    copyFile
    doesFileExist
System.Environment
    getArgs
    getProgName
System.Random
    mkStdGen
        # mkStdGen :: Int -> StdGen
    getStdGen
        # IO类型, 得到系统启动时的global generator
    newStdGen
        # 把现有的random generator分成两个新的generators, 其中一个指定成新的,返回另一个
    random
        # random :: (RandomGen g, Random a) = g -> (a, g)
        random (mkStdGen 100) :: (Int, StdGen)
    randoms
        take 5 $ randoms (mkStdGen 11) :: [Int]
    randomR
        # 区间random
        randomR (1,6) (mkStdGen 2)
    randomRs
        take 10 $ randomRs ('a', 'z') (mkStdGen 3) :: [Char]

函数 #

o-> 模式匹配
    # case的语法糖
    # 对构造子匹配,如 8 'a' : []
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)

first :: (a, b, c) -> a
first (x, _, _) = x

tell :: (Show a) => [a] -> String
tell [] = ""
tell [x: []] = ""
tell [x:y:[]] = ""
tell [x:y:_] = "too long, the first is " ++ show x ++ " and the second is " ++ show y

length' :: (Num b) => [a] -> b
length' [] = 0
length' (_:xs) = 1 + length' xs

capital :: String -> String
capital "" = ""
capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
    # @是as模式

o-> guard
bmiTell :: (RealFloat a) => a -> String
bmiTell weight height
    | bmi <= skinny = "You're underweight"
    | bmi <= normal = "You're supposedly normal"
    | bmi <= fat = "You're fat"
    | otherwise = "You're a whale"
    where bmi = weight / height ^ 2
    (skinny, normal, fat) = (18.5, 25.0, 30.0)
        # where是语法结构,不是表达式
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi w h | (w, h) <- xs, let bmi = w / h ^ 2]

myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
    | a > b = GT
    | a == b = EQ
    | otherwise = LT

o-> quicksort
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = 
    let smallerSorted = quicksort (filter (<=x) xs)
        biggerSorted = quicksort [a | a <- xs, a > x]
    in smallerSorted ++ [x] ++ biggerSorted

o-> curry
compareWithHundred :: (Num a, ord a) => a -> Ordering
compareWithHundred = compare 100

divideByTen :: (Floating a) => a -> a
divideByTen = (/10)
    # 中缀函数用括号来不完全调用
    # 但(-4)表示负4, (substract 4)来表示减4函数

o-> 高阶函数
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

o-> lambda
addThree :: (Num a) => a -> a -> a -> a
addThree = \x -> \y -> \z -> x + y + z

o-> $ 做数据函数
map ($ 3) [(4+), (10*), (^2), sqrt]

类型 #

类型
    Int
        # 有界整数
    Integer
        # 无界整数
    Float
        # 单精度浮点数
    Double
    Bool
    Char
    Maybe
    []
    ()
    a
        # type variables
类型约束
    Eq
    # 可判断相等性的类型,可用 == 或 /= 判断
        # 只除函数
    Ord
        #可比较大小的类型, 必定是Eq
        # 只除函数
    Ordering
        # 只有GT, EQ, LT
    Show
        # 可用字符串表示的类型
        # 只除函数
    Read
        # 与Show相反
    Enum
        # 连续的类型,有后继子(successer)和前置子(predecesor), 分别通过succ函数和pred函数得到
        # 可以[1..2]构造list
        # 包含 (), Bool, Char, Ordering, Int, Integer, Float, Double
    Bounded
        # 有上限和下限
        # 如果Tuple中都属于Bounded, 那么这个Tuple属于Bounded
    Num
        # 数字特征
    Integral
        # 整数
    Floating
        # 浮点,包含Float和Double
构造类型
    data Bool = False | True deriving (Ord)
        # Bool是构造的类型, False为值构造子,值可以用:t查看其类型
        # 值构造子可以用于模式匹配
        # 这里值构造子是没有参数的,叫作nullary
        # False在True前,所以比较时True比False大
    data Point = Point Float Float deriving (Show)
        # 值构造子可以与类型同名
    data Shape = Circle Point Float | Rectangle  Point Point deriving (Show)
        # 派生自Show, 就可show值成字符串
    data Person = Person {firstName :: String
        , lastName :: String
        } deriving (Show)
            # Record Syntax, 同 Person String String,  但自动生成同名的取值函数,show显示也改变
        let p = Person {firstName="aa", lastName="bb"}
    
        tellPerson :: Person -> String
        tellPerson (Person {firstName = a, lastName = b}) = a ++ b
    newtype CharList = CharList {getCharList :: [Char]} deriving {Eq, Show}
        # newtype将现有类型包成新类型,只能定义单一值构造子,且其只能有一个字段。并将包裹和解开的成本都去掉
类型构造子
    # data声明中不能加类型约束
    data Maybe a = Nothing | Just a
    data Car a b = Car { company :: a
        , year :: b
        } deriving (Show)
    tellCar :: (Show a) => Car String a -> String
类型别名
    type String = [Char]
    type AssocList k v = [(k,v)]
        # 别名类型构造子
    type IntMap = Map Int
        # 不全调用得到不全类型构造子, 同 type intMap v = Map Int v
infixr
    infixr 5 :-:
        # 定义中缀构造子, 5是优先级, :-:是符号
        # 默认left-associative

    infixr 5 .++
    (.++) :: List a -> List a -> List a
    Empty .++ ys = ys
    (x :-: xs) .++ ys = x :-: (xs .++ ys)
recursive data structures
    data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
typeclass
    class Eq a where
        (==) :: a -> a -> Bool
        (/=) :: a -> a -> Bool
        x == y = not (x /= y)
        x /= y = not (x == y)
            # 只需要instance一个定义就好,这个定义叫minimal complete definition
    data TrafficLight = Red | Yellow | Green
    instance Eq TrafficLight where
        Red == Red = True
        Green == Green = True
        Yellow == Yellow = True
        _ == _ = False
    instance Show TrafficLight where
        show Red = "Red light"
        show Yellow = "Yellow light"
        show Green = "Green light"

    class (Eq a) => Num a where
        # Num 是 Eq  的 subclass, 要是Num必是Eq

    instance (Eq m) => Eq (Maybe m) where
        Just x == Just y = x == y
        Nothing == Nothing = True
        _ == _ = False
            
o-> Either
data Either a b = Left a | Right a deriving (Eq, Ord, Read, Show)

o-> Tree
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)

o-> YesNo
class YesNo a where
    yesno :: a -> Bool
instance YesNo Int where
    yesno 0 = False
    yesno _ = True

o-> Functor
class Functor f where
    # map over
    fmap :: (a -> b) -> f a -> f b
instance Functor Maybe where
    # 接收构造子而非类型
    fmap f (Just x) = Just (f x)
    fmap f Nothing = Nothing
instance Functor (Either a) where
    # parital apply Either, Either a 是个类型构造子
    fmap f (Right x) = Right (f x)
    fmap f (Left x) = Left x
instance Functor ((->) r) where
    # 对函数的functor
    fmap f g = (\x -> f (g x))

命令 #

ghci
    set prompt "ghci> "
        # 设置显示的提示符
ghc
    ghc --make a.hs
runhaskell
ghc-pkg list
    # 列出已安装的软件包

玄学 #

o->
:{
data X = X
a :: Int -> Int
a x = x + 3
:}

Html

事件 #

blur
change
click
dblclick
focus
keydown
keypress
keyup
load
mousedown
mousemove
mouseout
mouseover
mouseup
reset
select
submit
unload

Abort
    # 中断图片下载时激发
AfterPrint
    # 打印文档后激发
AfterUpdate
    # 传送完数据
BeforeCopy
    # 复制到剪贴板前
BeforeCut
    # 剪切到剪贴板前
BeforeEditFocus
BeforePaste
BeforePrint
BeforeUnload
BeforeUpdate
Bounce
CellChange
CtextMenu
Copy
Cut
DataAvailable
DatasetChanged
DatasetComplete
Drag
DragDrop
DragEnd
DragEnter
DragLeave
DragOver
DragStart
Drop
Error
ErrorUpdate
FilterChange
Finish
Help
LoseCapture
Move
Paste

PropertyChange
ReadyStateChange
Resize
RowEnter
RowExit
RowsDelete
RowsInserted
Scroll
SelectStart
Start
Stop

标签 #

<var>               # 标识常量
<samp>              # 标识输出内容的样式
<pre>               # 代码块
<code>              # 一段代码

属性 #

全局属性
    # 配置所有元素共有行为
    accesskey
        # 快捷键
        ## 需要按alt + 指定的键
    class
    contenteditable
        # 内容是否可修改, 如p标签
    contextmenu
        # 定义右键菜单,未实现
    dir
        # 文字对齐方式
    draggable
    dropzone
    hidden
    id
    lang
    spellcheck
    style
    tabindex
        # tab键切换元素的顺序
    title

浏览器特性 #

视频播放 
    支持vaapi, chrome 加上--enable-vaapi参数可以开启硬件加速解码

方案 #

标签
    <input>表单
        单选框
        <input type="radio" name="name" checked value="1">
        <input type="radio" name="name" value="1">
        下拉框
        <select id="mySelect" size=10 multiple>    # 长度等于10 ,多选
            <option selected="selected">Apple</option>
            <option>Orange</option>
        </select>
        勾选框
        <input type="checkbox" name="" />
        按钮
        <input type="button"/>
        <button>                # <button><img src="">搜索</button>        button之间可以加图片
        
    <table>表格
        <caption> # 标题
        <thead>
            <th>
                <td><td>
            </th>
        <tbody>
            <tr>
                <td><td>
            </tr>
        <tfoot>
            属性
                <tr style="display: none;">                # 设置属性为隐藏

    <form>表单
        enctype属性
            application/x-www-form-urlencoded(默认)                # 在发送编码所有字符(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值)
            multipart/form-data                                                        # 不对字符进行编码,在上传文件时使用
            text/plain                                                                        # 空格转换为+,但是不对特殊字符进行编码
            
    <hr>分割线

    字体
        <h1></h1>  ...  <h6><h6>标题标签对
        
        <b>粗体</b><i>斜体</i><u>下划线</u><tt>打字机风格</tt><cite>引用</cite><em>强调(斜体粗体)</em><strong>重要(黑体加粗体)</strong>
        
        <sub>下标</sub><sup>上标</sup>
        
        <font size =-7到+7  coler = 颜色></font>

    <img src=""/>图片
        属性
            alt                # 规定图像的替代文本
            border
            width
            height

    <span>与 <div>
        <span> 在CSS定义中属于一个行内元素,在行内定义一个区域,也就是一行内可以被 <span> 划分成好几个区域
        ,从而实现某种特定效果。 <span> 本身没有任何属性。
        <div> 在CSS定义中属于一个块级元素 <div> 可以包含段落、标题、表格甚至其它部分。
        这使DIV便于建立不同集成的类,如章节、摘要或备注。在页面效果上,使用 <div> 会自动换行,使用 <span> 就会保持同行。
        
        <span>没有内边距
        
    <label>标签
        标记通常以下面两种方式中的一种来和表单控件相联系:将表单控件作为标记标签的内容,这样的就是隐式形式
        ,或者为 <label> 标签下的 for 属性命名一个目标表单 id,这样就是显式形式。

        例如,在 XHTML 中:
            显式的联系:
            <label for="SSN">Social Security Number:</label>
            <input type="text" name="SocSecNum" id="SSn" />
            
            隐式的联系:
            <label>Date of Birth: <input type="text" name="DofB" /></label>

    <head>标签
        <base> 标签为页面上的所有链接规定默认地址或默认目标。
        <meta http-equiv="pragma" content="no-cache">        定义响应信息头
        <meta name="keywrods" content="keyword1,keyword2">        关键字
        <meta name="description" content="This page is about the meaning of science, education,culture.">        网站主要内容
        <meta name="robots" content="none">        机器人索引 content的参数有all,none,index,noindex,follow,nofollow。默认是all。 
        <meta name="author" content="outrun">                作者
        
    <marquee behavior = "alternate">  文字行为                # alternate为来回滚动
        <font size = 30 color = "red">www.it315.org</font></marquee>
        <marquee behavior = "slide" "scroll" "alternate" direction="up""down""left""right">你好</marquee>
        
    <nobr> 标签之间的文字在浏览器中不换行显示
        <NOBR>这里是一行不该换行的文本 . . .
        这是文本行的结尾。</NOBR>

    <pre></pre>        标签之间的文字在浏览器中换行显示
        
    <blockquote></blockquote>缩进

    条目标签
        <dl>
            <dt>
                <dd>
                </dd>
            </dt>
        </dl>显示条目

        <ol>
            <li>
            </li>
        </ol>数字标签列表

        <ul>
            <li>
            </li>
        </ul>圆点标签列表
        
    <a>标签
        发送邮件
        <a href = "mailto:admin@it315.org?subject=咨询">我要留言</a>
                如:mailto:zxx@it315.org?cc=dreamdu@sina.com&subject=Feedback&body=how%20are%20you  # subject body cc 等用url参数拼接的方式拼接
                        %20代表空格 
                        subject= 是标题
                        body= 是邮件内容
                        CC=是抄送  
                        BCC=是暗送

        新窗口
                <a target="_blank" href=""><img src=""/></a>打开新窗口
        属性
        <a name ="mark1"/>
        <a href="text.html#mark1"></a>定位
        <a href="#"></a>打开自己
        <a href=""></a>打开目录

    <map></map>定义热点映射4
        <area></area>来说明 属性shape形状,coords坐标,href或nohref,target赖志明浏览器的哪个窗口或帧中显示
        <img>标签中增加名为usemap的属性来指定图像被用做图像地图,其设置值为图像热点名称 如<img src="" usemap="#mymap">
        <img src="logo.gir" border=0 usemap="#mymap">
        <map name=mymap>
        <area shape="rect" coords="0,0,50,50" href="">  左上和右下坐标 shape的属性值 rect poly circle
        </map>

    <embed></embed>标签 添加swf类型flash元素
        scale="noscale"                # 没有比例缩放
        wmode="transparent"                # 背景透明

样式
    小图标
        <link rel="Shortcut Icon" href="../imgs/favicon48.ico">  # 网页小图标
        <link rel="Bookmark" href="../imgs/favicon48.ico">                        # 收藏夹小图标
        
行为
    url标准
        基准url + 相对 url = 完整url
            http://www.it315.org/index.html#section2%E5%AE%9A%E4%BD%8D%E5%88%B0section2
                
        url中空格必须转换为+
        url中用字符的当前字符集编码在内存中的十六进制格式表示,并在每个字节前加上%
        如果确信特殊字符不会引起冲突,也可以直接传递给服务器,如汉字。也可以一部分编码,一部分不编码,如中&国 就是 中%26国


    文件下载
        超链接post提交
            <form action="${pageContext.request.contextPath }/downloadFile"        method="post" enctype="application/x-www-form-urlencoded">
                <input type="hidden" name="uuidFileName" value="" />
                <a href="#" onclick="download('${fileName}')"></a>
            </form>                
            <script type="text/javascript">
                function download(fileName) {
                    $(":hidden").val(fileName);
                    document.forms[0].submit();
                }
            </script>
    根目录
        <head>
        <base href="http://www.w3school.com.cn/i/" target="_blank" />                # href必选, target可选
                                                                                        ## js中的相对目录也起作用
        </head>
    frameset
        frameset的例子
            <frameset rows="70,*" cols="*" frameborder="no" border="0" framespacing="0">
            <frame src="head.html" name="topFrame" scrolling="No" noresize="noresize" id="topFrame" />
            <frameset cols="193,*" frameborder="no" border="0" framespacing="0">
                <frame src="left.html" scrolling="No" noresize="noresize" id="leftFrame" />
                <frame src="main.html" name="mainFrame" id="mainFrame" />
            </frameset>
            </frameset>
            
            # 在head.html 中的标签中添加链接
            ## <a href="/a.html" target="mainFrame">Frame main.html</a>
            ## 就可以使name 为 mainFrame的<frame>窗体刷新
            
            # 在src属性后面添加#name,可以跳转到指定名子的框架
            ## <frame src="/example/html/link.html#C10">跳转到link.html页面的:<a name="C10"><h2>Chapter 10</h2></a>位置
            ## 也可以在a标签中设置跳转<a href="/example/html/link.html#C10" target="showframe">带有锚的链接</a>

        内联框架:iframe 的例子
            <script type="text/javascript">
            function changeUrl(vPageName){
            var vIfr=document.getElementById("ifrObj");
            vIfr.src=vPageName+".asp";
            }
            </script>
            <iframe id="ifrObj"></iframe>
            <a href="javascript:changeUrl('2')">a</a>
            <a href="javascript:changeUrl('3')">b</a> 

svg #

介绍
    scalable vector graphics, 可缩放矢量图形
    使用xml格式定义图像
    由w3c定制
例子
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <rect width="300" height="100" style="fill:rgb(0, 0, 255); stroke-width:1; stroke:rgb(0, 0, 0)"></rect>
            # 矩形
    </svg>
滤镜

Css

基础 #

# cascading style sheet
层级匹配
    不同级
        1. style属性
        2. style标签
        3. link标签
        4. 浏览器中用户自定义样式表
        5. 浏览器默认样式             # 浏览器对每个元素定义了默认的样式表
    !important
        color: black !important
    同级                            # 评估得出最特殊的样式, 评分相同时,使用最后的
        1. id值的数目
        2. 其它属性和伪类的数目
        3. 元素名和伪元素的数目
继承
    部分元素继承父元素样式
        外观继承
        布局不继承
    inherit                         # 指明使用父元素样式
        border: inherit    
三种引入方式
    内联式
        <div style="color:#000;"></div>
    嵌入式
        <style type="text/css">
            div {color:#000;}
        </style>
    引用式
        <link href="css.css" rel="stylesheet" type="text/css" />
        @
            @charset "UTF-8"        # 默认UTF-8, 在import前
            @import "styles.css"    # 静态引用, 效率比<link>标签慢

单位 #

颜色
    名称, 如silver, gray
    0xffffff
    rgb(112, 128, 144)
    rgb(112, 128, 114, 0.4)
    hsl(120, 100%, 22%)         # 色相(hue), 饱和度(saturation), 明度(lightness)
    hsl(120, 100%, 22%, 0.4)
长度
    绝对单位                      # 只有在打印和设计文档时才用绝对单位
        cm
        pt                      # 磅
        in                      # 英寸
        mm
        pc                      # pica 等于12磅
    相对长度
        em                      # 元素字号
        ex                      # 元素字体的'x高度',字体基线到中线的距离,一般与x的高度相当,大致等于0.5em
        rem                     # 根元素(html元素)字号
        px                      # css像素,假定了设备的分辨率为96dpi, 是1英寸的1/96(windows系统标准像素密度, 其它平台浏览器自己转换), css在定义中px是相对单位,但浏览器实现中全是绝对单位
        %                       # 不是所有元素都可以用, 不同属性中%定义不同,如font-size挂钩继承的font-size值, width挂钩元素包含块的宽度
    算式                        # css3 未得到广泛支持
        width: calc(80% - 20px);
角度
    deg                         # 度, 0 - 360
    grad                        # 百分度 0 - 400
    rad                         # 弧度 0 - 6.28
    turn                        # 圆周 1 turn = 360 deg
时间
    s
    ms

选择器 #

*                               # 所有元素
<type>                          # 标签
.<class>                        # 样式
#<id>                           # id
[attr]                          # 属性, 如[title] {}
[attr="val"]
[attr^="val"]                   # 以val开头
[attr$="val"]
[attr*="val"]                   # 包含val
[attr~="val"]                   # 属性多值有val, 空格隔开
    [class~="class2"] {}
[attr|="val"]                   # 属性多值有val, - 隔开
    [lang |="en"] 
<selector>, <selector>          # 同时匹配
<selector> <selector>           # 后代
<selector> > <selector>         # 直接后代
<selector> + <selector>         # p 之后的第一个兄弟a
<selector> ~ <selector>         # p 之后所有兄弟a

o-> 伪元素                       # 直接使用匹配所有
::first-line                    # 块级元素文本首行
::first-letter                  # 块级元素文本首字母
:before                         # 之前插入内容
    {content: 'a'}
:after                          # 之后插入内容

o-> 伪类                         # 直接使用匹配所有
:root                           # 文档根元素, 总是返回html元素
:first-child                    # 第一子元素
    p > span: first-child , p 下面第一个span元素
:last-child
:only-child                     # 只有一个子元素的该元素
:only-of-type                   # 同上但指定类型,直接使用时会匹配更多,因为很多某类型的唯一元素
:nth-child(n)                   # body > :nth-child(2)
:nth-last-child(n)
:nth-of-type(n)
:nth-last-of-type(n)

o-> UI  伪类
:enabled                        # 已启用的元素
:disabled                       # 禁用的元素
:checked                        # 选中的单选或复选按钮
:default                        # 默认的元素, 如 <button type="submit">, 常和outline属性一起使用
:valid                          # 输入验证有效的元素
:invalid
:in-range                       # 范围内的input元素, 未广泛支持
:out-of-range
:required                       # 允许使用required属性的input元素
:optional                       # 非required

o-> 动态伪类
:link                           # 未访问的a元素
:visited                        # 已访问过的a元素
:hover
:active                         # 当前激活的元素(鼠标按下)
:focus                          # 获得焦点的元素
:not(<selector>)                # a:not([href*="apress"])
:empty                          # 无子元素的元素
:lang(<language>)               # lang属性为指定值
    :lang(en) 匹配 <a lang="en-us">
:target                         # url hash(片段标识符) 定向id所在的元素

例子
    o->
    span.class2 {}

    o->
    body > * > span, tr > th {}

    o-> 计数器
    body {counter-reset: paracount;}
    p:before {
        content: counter(paracount) " ";
        counter-increment: paracount;
            # counter-increment: paracount 2; 可以增加2
    }

    o->
    :checked + span

属性 #

布局 #

position                        # 默认static, top等属性不起作用
    static
    absolute
    fixed                       # fixed滚动固定
    relative
left
right
top
bottom

z-index
columns                         # 列数和列宽的简写属性
column-count                    # 多列布局的列数
    column-fill                 # 列间内容分布方式
    column-gap                  # 列间隔
    column-rule                 # 列间规则的简写属性
    column-rule-color
    column-rule-style
    column-rule-width
    column-span                 # 元素跨列数
    column-width
flex-align                      # 弹性盒子布局, 未实现
    flex-direction
    flex-order
    flex-pack
    -webkit-box-align           # 内容高度小于容器高度时
        # start(顶边放置), end(底边放置), center(中间放置), baseline, stretch(拉伸元素)
        -webkit-box-flex        # 元素可伸缩性
        -webkit-box-pack        # 元素伸缩到最大尺寸(max-width)时怎么做
            # start(左边放置), end(右边放置), center(中间放置), justify(平均分配到各个元素间)
        -webkit-box-direction   # 内部盒子排列顺序
例子
    o-> 多列布局
    column-count: 3;
    column-fill: balance;
    column-rule: medium solid black;
    column-gap: 1.5em;
    column-width: 10em;

    o-> 弹性盒
    #container {
        display: -webkit-box;
        -webkit-box-direction: reverse;
        -webkit-box-align: end;
        -webkit-box-pack: justify;
    }
    #first {-webkit-box-flex: 3;}
    #second {-webkit-box-flex: 1;}

    o-> css表格
    #table {display: table;}
    div.row {display: table-row;}
    p {display: table-cell;}

盒模型 #

box-sizing                      # 尺寸样式(如width, height)应用到哪部分
    # content-box, padding-box, border-box, margin-box
display
    inline                      # 显示为文本行中的字
        inline时,忽略width, height, margin属性
    block                       # 显示为段落, 在垂直方向有所区别
    inline-block                # 显示为文本行, 整体作为inline, 但内部作为block, 这样认width, height, margin属性
    list-item                   # 显示为列表项
    run-in                      # 类型取决于周围元素
        包含display:block元素,就是block
        兄弟都是block时,为inline
        其它都为block
    compact                     # 为块或标记盒(类list-item), 一般不支持
    flexbox                     # 弹性盒布局用
        -webkit-box
    table                       # 表格布局用
        inline-table
        table-caption           # 类似caption
        table-row-group         # 类似tbody
        table-header-group      # 类似thead
        table-footer-group      # 类似tfoot
        table-row               # 类似tr
        table-column-group      # 类似colgroup
        table-column            # 类似col
        table-cell              # 类似td
    ruby                        # ruby注释的文本布局用
        ruby-base
        ruby-text
        ruby-base-group
        ruby-text-group
    none                        # 元素不可见,不占空间
float                           # 元素左边界或右边界移动到包含块或另一个浮动盒的边界。其余inline部分流式环绕
    left, right, none
clear                           # 左右边界不能挨着另外浮动元素
    left, right, both, none
padding
    padding-bottom
    padding-left
    padding-right
    padding-top
margin
    margin-bottom
    margin-left
    margin-right
    margin-top
height                          # 长度或百分比
width
    max-height
    max-width
    min-height
    min-width
overflow
    auto                        # 同scroll, 但自动加滚动条
    hidden                      # 剪掉
    on-content                  # 移除内容, 已废弃
    on-display                  # 隐藏内容, 已废弃
    scroll, visible             # 溢出
overflow-x
overflow-y

visibility                      # 元素可见性
    collapse                    # 不可见,不占据空间, 只能用在表相关内容,如tr, td
    hidden                      # 不可见,占据空间
    visible

边框 #

border                          # border: 30px dashed #000
border-width                    # 可以是长度值, 百分比, thin, medium, thick 
    border-width: 15px 5px 15px 5px
border-style
    none 默认
    dashed 破折线
    dotted 圆点
    double 双线
    groove 槽线
    inset 内嵌效果
    outset 外凸效果
    ridge 脊线
    solid 实线

    border-style: solid dotted dashed double 定义了上、右、下、左的样式
    border-style: none的时候,边框其它属性无意义
border-color
    blue rgb(25%, 35%, 45%) #909090 red;
border-image                    # 不广泛支持
    border-image-outset
    border-image-repeat
        stretch 拉伸
        repeat 平铺
        round 不截断下拉伸
        space不截断下图片间保留间距平铺
    border-image-slice
    border-image-source
    border-image-width

    o->
    -webkit-border-image, -moz-border-image, -o-border-image
    border-image: url(a.png) 30 / 50px round repeat; 九宫格切分长度都为30, 宽度为50, 横round, 竖repeat
border-left
    border-left-style
    border-left-color
    border-left-width
border-right
    border-right-color
    border-right-style
    border-right-width
border-top
    border-top-style
    border-top-color
border-top-width
border-top-left-radius
    border-top-left-radius: 20px 15px; x半径20, y半径15
border-top-right-radius
border-bottom
    border-bottom-style
    border-bottom-width
    border-bottom-color
    border-bottom-left-radius
    border-bottom-right-radius
border-radius
    border-radius: 20px / 15px;
    border-radius: 50% 20px 25% 5em / 25% 15px 40px 55%

box-shadow
    box-shadow: hoffset voffset blur spread color inset
    水平偏移量, 正向右,负向左。垂直偏移量,正向下,负向上。模糊值。阴影延伸半径,正向各方向延伸,负缩小。颜色。内嵌阴影
    可设置多组阴影,用, 隔开
outline                         # 轮廓不属于页面,不影响布局, <颜色> <样式> <宽度>
    outline-color
    outline-offset              # 距元素边框边缘的偏移量
    outline-style               # 同border-style
    outline-width               # 同border-width

背景 #

# 不继承
background                      # background: <background-color> <background-position> <background-size> <background-repeat> <background-origin> <background--clip> <background-attachment> <background-image>
background-attachment           # 背景附着方式
    fixed 固定到视窗上, 不随文字滚动
    local 随文字滚动
    scroll 固定到元素上(使用浏览器的滚动条), 不随文字滚动
background-color                # 原点在border外边缘
    函数
        linear-gradient(transparent, rgba(0, 0, 0, 0.1) 20%, rgba(0, 0, 0, 0.5) 65%, rgba(0, 0, 0, 0.66))
            # 线性渐变 
background-image                # 原点在padding外边缘,也就是border内边缘
    background-image: url("bg.jpg")
background-position             # 起始位置, 可以是长度, top, left, right ,bottom, center, 第一个值控制垂直位置, 第二个值控制水平位置
    0px 0px                     # 左上偏移0, 0    
    right ?                    # 位置在右边显示
    left ?                     # 位置在左连显示(默认)
    ? bottom
    center center               # 位置在中间显示、内容从中间开始显示(默认)
    ? top                       # 内容从上开始显示
background-repeat
    no-repeat
    repeat 水平和垂直同时平铺
    repeat-x 水平平铺
    repeat-y 
    space 水平或垂直平铺, 统一间距,不截断, round 水平或垂直拉伸, 不截断
background-size                 # 可以长度值或百分比
    contain 等比缩放, 宽高适应匹配, 不超出容器
    cover 等比缩放, 宽高最大适应匹配, 可超出容器
    auto 本身尺寸显示
background-origin               # 定位显示原点
    border-box 边框盒子内 
    padding-box 内边距盒子内
    content-box 内容盒子内
background-clip                 # 裁剪, 属性同上

色彩 #

opacity
color                           # 前景颜色
    rgba(255, 255, 255, 0.7)
user-select                     # 用户不可选择
filter                          # 滤镜效果, ie8 或之前使用
    filter:alpha(opacity=50),同opacity: .5

文本 #

text-decoration                 # node时 a标签没有下划线
text-indent                     # 首行缩进
text-align
    start 语言的起始边界,可能是右
    end, left, right, center, justify
text-justify                    # text-align: justify时来指定规则
    auto
    none 禁用文本对齐
    inter-word 空白在单词之间
    inter-ideograph 中日韩
    inter-cluster 泰
    distribute, kashida 草体
text-transform                  # 转换大小写
    none, capitalize, uppercase, lowercase
text-decoration                 # 文本装饰
    none, underlinenone, overline, line-through, blink
text-shadow                     # 文本阴影, <h-shadow> <v-shadow> <blur> <color>, 水平偏移, 垂直偏移, 模糊程度, 颜色
direction                       # 文本对齐
    ltr, rtl
word-spacing                    # 词间距
letter-spacing # 字母间距
white-space
    normal 空白被压缩,文本行自动换行
    nowrap 空白压缩,文本行不换行
    pre 空白不压缩, 换行符换行
    pre-line 空白压缩,自动换行或换行符换行
    pre-wrap 空白不压缩, 自动换行或换行符换行
line-height                     # 行高, 百分比,长度
word-wrap                       # 行超距单词截断
    normal 溢出
    break-word
@font-face                      # 指定web字体, woff得到最广泛支持, 在@font-face中定义,font-family中使用
    @font-face {
        font-family: 'MyFont';
        font-style: normal;
        font-weight: normal;
        src: url('http://a/MyFont.woff')
    }
font                            # <font-style> <font-variant> <font-weight> <font-size> <font-family>
    简写属性
        font-family             # serif, sans-serif, monospace, cursive, fantasy
            font-family: MyFont, cursive
        font-style              # normal, italic, oblique
font-variant                    # normal, small-caps
    font-weight                 # bold, bolder, lighter
    font-size
        xx-small 浏览器决定的大小
        x-small, small, medium, large, x-large, xx-large
        smaller 相对父元素字体的大小
        larger, <length>, <%>

列表样式 #

list-style                      # <list-style-type> <list-style-position> <list-style-image>
    list-style-type             # 列表项前标记
        none, box, check, circle, diamond, disc, dash, square, decimal, binary, lower-alpha, upper-alpha
    list-style-image            # 图片作为列表标记
    list-style-position         # 相对于内容框的位置
        inside 内容框内部
        outside 外部
vertical-align                  # 垂直对齐(文字不行)

cursor
    auto :标准光标
    default :标准箭头
    hand :手形光标
    wait :等待光标
    text :I形光标
    vertical-text :水平I形光标
    no-drop :不可拖动光标
    not-allowed :无效光标
    help :?帮助光标
    all-scroll :三角方向标
    move :移动标
    crosshair :十字标 
    pointer
    e-resize n-resize nw-resize w-resize s-resize se-resize sw-resize ne-resize

表格样式 #

border-collapse                 # 相邻单元格边框样式
    separate 默认,重复画框
    collapse 合并边框
border-spacing                  # 相邻单元格边框距离
table-layout                    # 单元格行列的算法规则
    auto
    fixed 由表格自身样式和每列width属性决定布局[无则设等间距],由第一行决定列宽,以下行内容自动换行
caption-side                    # 表格标题的位置
    top, bottom
empty-cells                     # 是否显示表格中空单元格
    hide

计数器 #

counter-reset                   # 用于有序列表
counter-increment

动画 #

介绍
    本质是增强过渡
@keyframes
    指定一个以上关键帧
    只在过程中有效,动画结束后即使仍hover, 也返回初始状态
animation
    动画,动画完后回到初始状态。想停留在结束状态用过渡。
    可以用在初始布局中
    通过keyframe显式控制, 可重用
    <animation-name> <animation-duration> <animation-timing-function> <animation-delay> <animation-iteration-count>
        只是模拟属性值改变来实现动画,动画结束后属性无变化
        可以应用到页面的初始布局中去,而transform只能应用在动作上

    animation-delay             # 延迟,可以指定多个值,对应transition-property中的多个属性
    animation-direction         # 重复播放时播放方向
        normal 每次向前播放
        alternate 先向前,再反向,相当于animation-iteration-count: 2
    animation-duration          # 持续时间, 可多值
    animation-iteration-count   # 循环次数
        infinite                # 无休止交替播放
    animation-name              # 关键帧集合名称,可多个
    animation-play-state        # 动画状态, js中ele.style.webkitAnimationPlayState = 'paused'
        paused                  # 停止
        playing                 # 开始播放
    animation-timing-function   # 关键帧时间插值函数
        normal                  # 每次重复向前播放
        alternate               # 先向前播放,再反向播放,相当于animation-iteration-count: 2
transform                       # 变换,动画结束后属性有变化
    -moz-transform: rotate(-45deg) scaleX(1.2)              # 逆时针旋转45度, 延x轴缩放到1.2倍
    函数
        translate               # 水平、垂直或两个方向 平衡。长度,百分比
        translateX
        translateY
        scale                   # 数
        scaleX
        scaleY
        rotate                  # 角度
        skew                    # 倾斜, 角度
        skewX
        skewY
        matrix                  # 6个参数。自定义变换, 由于z缩放未被实现,后两个参数省略
    transform-origin            # 变换的起点,默认是元素中心点
        transform-origin right top;
        长度,百分比,left center right, top center, bottom

transition                      # <transition-property> <transition-duration> <transition-timing-function> <transition-delay>, 可以作为初始状态,也可以过渡
    transition-delay            # 开始之间延迟时间, ms
    transition-duration         # 持续时间, ms
    transition-property         # 应用过渡的多个属性
    transition-timing-function              # 时间函数
        ease 默认
        linear
        ease-in
        ease-out
        ease-in-out
        cubic-bezier 指定自定义曲线

    o->
    -webkit-
    transition: .2s background-cololr
    transition: .2s all
示例
    o-> 过渡
    #banana {
        font-size: large;
        border: medium solid black;
        -webkit-transition-delay: 10ms;
        -webkit-transition-duration: 250ms;
            # 反向过渡
    }
    #banana:hover {
        font-size: x-large;
        border: medium solid white
        background-color: green;
        color: white;
        padding: 4px;
        -webkit-transition-delay: 100ms;
        -webkit-transition-property: background-color, color, 
            padding, font-size, border;
        -webkit-transition-duration: 500ms;
        -webkit-transition-timing-function: linear;
    }

    o-> 动画
    #banana:hover {
        -webkit-animation-delay: 100ms;
        -webkit-animation-duration: 500ms;
        -webkit-animation-iteration-count: infinite;
        -webkit-animation-timing-function: linear;
        -webkit-animation-name: 'GrowShrink';
        -webkit-animation-direction: alternate;
    }
    @-webkit-keyframes GrowShrink {
        from {
            # 可以用0%替代
            font-size: xx-small;
            background-color: red;
        }
        50% {
            # 定义了变化的速率,可以用0%, 100%代替from和to子句
            background-color: yellow;
            padding: 1px;
        }
        to {
            # 可以用100%替代
            font-size: x-large;
            border: medium solid white;
            background-color: green;
            color: white;
            padding: 4px;
        }
    }

    o-> 变换
    #banana {
        -moz-transform: rotate(-45deg) scale(1.2);
        -moz-transform-origin: right top;
    }

典型问题 #

垂直居中
    line-height
        .content {
            height: 100px;
            line-height: 100px;
        }
    vertical-align
        .wrapper {display: table;}
        .cell {
            display: table-cell;
            vertical-align: middle;
        }
    position
        .wrapper {position: relative}
        .content {
            left: 50%;
            top: 50%;
            transform: translate(-50%, -50%)
        }
    position
        .content {
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }
    float填充一半
        .floater {
            float: left;
            height: 50%;
            margin-bottom: -120px;
        }
        .content {
            clear: both;
            height: 240px;
            position: relative;
        }
图标切分
    background-image: url(/base/icons.png);
    background-repeat: no-repeat;
    background-position: -910px -74px;
内部元素自动高度
    .parent {
        overflow: hidden;
    }
    .parent .children {
        overflow: hidden;
    }

工具 #

stylus
    # css扩展语言, 创建富有表现力的css, 比less更强大, 类似jquery的css引擎, 支持node.js
compass
    # 编译到css,是sass的toolkit, 是用ruby开发的
blueprint
    # css框架
sass
    # css扩展语言
caniuse.com
    # 在线浏览器兼容性测试
modernizr.com
    # 测试特性支持是否到位

less #

介绍
    less于css如jquery于js
安装使用
    npm install -g less
命令
    lessc styles.less > styles.css                # 编译
                                # -x 压缩  --clean-css 更复杂的压缩
语法
模板
    {% %}
变量
    @color: #4D926F;
    #header{
        color: @color
    }
    h2{
        color: @color
    }

Elixir

介绍 #

跑在erlang虚拟机上
与erlang相同,actor称作进程, 是比线程更轻量的概念

使用 #

o-> 元组
{:foo, "this", 42}
        # 三元组

o-> actor
defmodule Talker do
def loop do
    receive do
    {:greet, name, age} -> IO.puts("Hello #{name}")
    {:shutdown} -> exit(:normal)
    end
    loop
end
end

pid = spawn(&Talker.loop/0)
send(pid, {:greet, "Huey", 16})
sleep(1000)

Process.flag(:trap_exit, true)
pid = spawn_link(&Takler.loop/0)
send(pid, {:shutdown})
receive do
{:EXIT, ^pid, reason} -> IO.puts("Talker has exited (#{reason})")
end

o-> 有状态的actor
        # 递归
defmodule Counter do
def start(count) do
    spawn(__MODULE__, :loop, [count])
            # 伪变量__MODULE__, 是当前模块的名字
end
def next(counter) do
    send(counter, {:next})
end
def loop(count) do
    receive do
    {:next} ->
        IO.puts("Current count: #{count}")
        loop(count + 1)
    end
end
end
counter = spawn(Counter, :loop, [1])
send(counter, {:next})

counter = Countre.start(42)
Counter.next(counter)

Go

基础 #

特点
    易工程化
        简单性而不方便性,避免工程复杂性乘法增长            # 某部分变复杂,增加其他部分的复杂性(功能、选项、配置)
            没有动态库, 没有泛型, 没有继承, 没有异常, 没有宏,没有注解,没有线程局部存储
        类型系统,无类型风格
        自然方式工作
            不显式初始化和隐式构造函数
            集合直接持有元素
        标准库避免配置和解释     # 自带电池
        项目结构简单
        编译检查代码格式
    csp(communicating sequential process)并发,变长栈运行轻量线程
    编译为本地机器码        # 像c一样,所以又叫类c语言
        编译快
            引用包名在头
            包依赖有向无环,可独立和并行编译
            目标文件包含依赖包信息
    强静态类型
    有gc
    变长栈,最小2kb, 最大1GB
    大厂支持
历史
    2007年设计,受影响于Alef(CSP系列), Oberon-2(ALGOL60, Modula-2系列), C
        # 目的解决google许多复杂性激增的软件系统
    2009年发布, 作者是Robert Griesemer, Rob Pike, Ken Thompson
    2012年1.0
并发编程特点
    语言层面关键字
    例程
        流程控制: csp       # channel为一等公民
        通信方式: promise-future, channel, event
    高效调度模型(调度器,资源占用小)
        O(1)的调度
        一进程可支撑上百万例程,5kib/goroutine的开销,
            变长栈存goroutine
编译
    CGO_ENABLED=0
        # 静态链接,不跨平台
    初始化
        包级别初始化在main前
        局部变量在函数执行时
配置
    GOROOT                  # go安装目录
    GOPATH                  # 包目录, 默认要有go的bin目录
    GOBIN                   # 当前bin目录
    GO15VENDOREXPERIMENT    # 依赖目录
    GOOS                    # 指定操作系统, 如android, linux, darwin, windows
    GOARCH                  # 处理器架构,如amd64, 386, arm

命令 #

go
    help
        importpath          # 说明 指定代码托管网站版本协议
        gopath              # vendor怎么使用
        list                # go list 说明
    version
    env                     # 打印go环境信息
    run                     # 编译并运行
        -race               # 检查运行中的竞态冲突并报告
    build                   # 库被舍弃,main包编译成二进制执行文件, 会检测mod
        go build gopl.io
        go build x.go
        -race
        -i                  # 编译到指定位置
    install                 # 编译安装, 会检测mod
    clean                   # 清理build产生的文件
        -c                  # 清理.test文件
        -i                  # 清理生成的可执行文件
        -r                  # 包括依赖包的结果文件
    doc
        命令
            go doc go/build
        包
            go doc html/template
        包成员
            go doc time.Since
        方法
            go doc http.ListenAndServe
    fmt                     # 代码格式化

    get                     # 下载依赖, 默认目录是GOPATH下的pkg。下载后自动install
        go get gopl.io/...  # ...通配
        get gopl.io@2       # 指定mod版本号
        -u                  # 更新到mod最新版本
        -v                  # 查看进度
    list                    # 列出指定代码包的信息
        go list ...         # ...通配
        go list ...xml...
        -json hash          # 输出json格式完整信息
        -f                  # 使用go模板
    fix                     # 升级旧代码成新版本代码
    vet                     # 检查静态错误

    test
        # go test -cover -args -config config_it.toml -test.run "TestA"
        # 执行当前目录下所有_test.go结尾的文件
        -race

        -file               # 可省略,测试单个文件, 如go test test_a.go a.go a.pb.go
                            ## 测试单个文件需要引入原文件
        -args               # 运行时参数
        -run TestFoo        # 正则表达式匹配方法,NONE表示不匹配。如"^TestFoo", "F|F1"
        -test.run "TestCreate"                      # 同上
        -v                  # 每个测试用例的名称和时间
        -bench=".*"         # 正则匹配benchmark测试函数
        -benchmem           # 显示benchmark测试时内存分配
        --cpuprofile=cpu.prof                       # 生成cpu分析文件,使用多个标记时(如cpu, mem), 一个类别会覆盖另一个。性能剖析启用时, go test不丢弃其临时可执行文件
        --blockprofile=block.out                    # 生成阻塞分析文件
        --memprofile=mem.prof                       # 生成内存分析文件
        -c                  # 生成可执行的二进制文件,名为x.test,它用来生成状态图
        -cover              # 显示覆盖语句汇总信息
        -coverprofile=c.out # 生成日志文件c.out,记录语句覆盖信息
        -covermode=count    # 语句覆盖信息不用bool而用count累加

    tool
        cover               # 测试覆盖率工具使用方法
            go tool cover -html=c.out               # html分析c.out
        pprof               # 交互式访问概要文件
            go tool pprof module1.test cpu.prof                   # 性能测试状态图, 参数是可执行文件和剖析日志
            -test           # 文本格式
            -nodecount=10   # 限制输出10行
            -web            # 渲染有向图web显示
        fix                 # 同go fix
        vet                 # 同go vet
        cgo                 # 生成能够调用c语言代码的go源码文件
        compile
            -help           # 可传给编译器的参数
    mod
        init packageName1   # 生成go.mod
        download            # 下载mod
        tidy                # 下载缺少,删除多余
        edit                # 编辑go.mod
        graph               # 打印依赖图
        vendor              # 复制依赖到vendor
        verify              # 验证mod
        why                 # 打印依赖原因
godoc                       # 提供html页面
    -http=:6060             # 运行本地帮助网站
    -analysis=type          # 提供静态分析结果
        -analysis=pointer
gofmt
golint                          # 检查风格

常用 #

go mod 配置
    环境变量
        GO111MODULE
            off                     # 总关闭
            on                      # 总开启
            auto                    # 默认,有go.mod开启
    路径
        $GOPATH/pkg/mod             # 保存多版本依赖, 被多项目引用
        go.mod                      # 被go命令维护, 融入了go命令的各个模块
        go.sum                      # 记录lock
    依赖加载顺序
        最新release tag
        最新commit
    命令
        go mod vendor
代理
    go env -w GOPROXY=https://goproxy.cn,direct
包升级
    go list -m -u all               # 检查可以升级的package
    go get -u need-upgrade-package  # 升级
性能测试
    go test -bench=.  --cpuprofile=cpu.prof --memprofile=mem.prof -config ../conf/config_lc.toml -test.run TestCreateType
覆盖率
    go test -cover -args -config config.toml -test.run "TestCreate"
性能分析
    go tool pprof service.test cpu.prof
    go-torch -b cpu.prof
包管理
    go list -m -u all
        # 列可升级包
    go list -u need-upgrade-package
        # 升级可升级包
    go get -u
        # 升级所有依赖

工具 #

glide #

介绍
    包管理
目录
    glide.yaml
    glide.lock
    main.go
    subpackages
    vendor
命令
    glide
        init
            # 扫描代码目录,创建glide.yaml文件,记录所有依赖
            删除glide.yaml中自己项目本身
        get
            # 安装并更新glide.yaml
            --all-dependencies -s -v github.com/go-redis/redis#5.0.0
                # --all-dependencies会更新subpackages
        update
            # 下载和更新glide.yaml中的所有依赖,放到vendor下
            # 递归更新
        install
            # 依据glide.lock与glide.yaml文件安装特定版本
            # glide.lock与glide.yaml不同步时,发出警告
        up
            # 更新依赖树,重建glide.lock文件
        name
            # 查看glide.yaml中依赖名称
        list
            # 依赖列表
        help
        --version
glide.yaml
    package: .
    import:
    - package: github.com/go-redis/redis
    version: 5.0.0
    repo:git@github.com:go-redis/redis
常见问题
    o-> cannot detect vcs
        glide.lock或vendor依赖旧版本
            清理glide.lock和vendor, 检查glide.yaml旧版本
        glide.yaml子目录处理不完善
            subpackages:
            - cloudsql
        glide mirror找不到包
            glide mirror set a a --vcs git
                # 改~/.glide/mirrors.yaml文件
    o-> does not appear to be a git repository
        加速服务没有项目
    o-> glide up依赖不是最新
        ~/.glide/cache中缓存了旧版本
    o-> cannot find package "." in
        glide对非git协议自有域名处理歧义,子目录分析不准确
            清理缓存
                ~/.glide/cache/src/包名
                ~/.glide/cache/info/包名
            glide.yaml添加repo重定向及subpackages
                package: github.com/grpc-ecosystem/grpc-gateway
                repo: git@github.com:grpc-ecosystem/grpc-gateway.git
                subpackages:
                - internal

govendor #

介绍
    包管理
使用
    go get -u -v github.com/kardianos/govendor

godev #

# 依赖管理

gv #

# 依赖管理

gvt #

# 依赖管理

gvm #

# 版本管理
命令
    gvm
        install go1.5
        use go1.5
        list
        listall
        implode
            # 删除所有go版本和gvm本身

gore #

# repl

go-torch #

# 性能火焰图
go-torch -b cpu.prof

gf #

-v/version
-h/help
init
build
gen         # 生成模块
    gen dao
run
swagger
pack
get
docker
mod
update

语法 #

包                              # 路径引用,命名空间
    不能循环依赖
    main包                      # 入口包, 产生可执行文件,也可当库导入
        main()                  # 入口函数
    包名最好匹配目录名          # 导入路径的最后一段
    import
        逐行import或import(多行)
        import 别名 包路径
        import "gopkg.in/yaml.v2" 忽略.v2, 包名为yaml
        import _ "image/png" 空导入
        可导入相对目录,以.或..开头
    var和const
        逐行或var(多行), const(多行)
    包文件函数
        init                    # 文件在编译前排序,按依赖顺序和文件名,也是init的调用顺序。init不能调用和引用
    包依赖排序依次初始化
    工作空间
        src
        bin                     # 编译后的执行文件
        pkg                     # 编译后的包, 重复使用加快编译
    vendor目录放本地依赖
    文档注释影响编译
        // +build linux darwin                  # linux和darwin才编译
        // +build ignore                        # 任何时候都不编译
    内部包                      # 路径有internal的包, 只能被父目录导入
        net/http/internal/chunked
注释
    //或/**/
    package前写文档注释,可出现在任何文件中,但一个包约定一个
    doc.go约定为包的扩展文档注释
命名
    字母或下划线开头,区分大小写, 不能用关键字
    关键字: break, default, func, interface, select, case, defer, go, map, struct, chan, else
        goto, package, switch, const, fallthrough, if, range, type, continue, for, import, return, var
    首字母大小写决定可见性,大写表示其是导出的
    go倾向短名称, 驼峰式命名, 缩写全大写或小写
操作符
    优先级:
        * / % << >> & &^    # 可加=, 如*=
        + - | ^             # 可加=, 如*=
        == != < <= > >=     # 基本类型都可比较
        &&
        ||
        + -                 # 一元取正负
    %                       # 只能整数,符号与被除数一致
    /                       # 整数除,去小数部分。溢出高位丢弃
    & | ^ &^                # 按位独立
        &^                  # and not(位清空)右边1清左边为0
        &                   # and
        |                   # or
        ^                   # xor, 前缀表示取反或按位取补(逐位取反)
    << >>                   # 注意,有符号数右移按符号位填补空位
声明定义
    不能有无用的声明变量
    var s string            # 未初始化值默认零值,类型和表达式可省一个
    var s string = ""       # 不推荐
    var s = ""              # 不推荐
    s := ""                 # 短变量声明

    var i,j int             # 自动引申变量类型
    i, j := 0, 1
    i, j := true, "a"       # 类型可不一致
    i, err := 0, e          # err声明过(只检测本词法块,外层不算),声明i, 赋值err。:=要求至少一个声明

    const                   # 编译时计算
        枚举
            type Weekday int
            const (
                Sunday Weekday = iota               # 值为0
                Monday
                ...
            )
            const (
                i T1 = 1 << iota                    # 值为1, 下值为 1<<1
                ...
            )
        无类型常量
            只有常量可以无类型
            无类型常量存大数精度高于基本类型, 算术精度高于机器精度, 至少256位
            可用于更多表达式,无需转换类型
            分类
                布尔: true
                整数: 0
                文字符号: '\u0000'
                浮点数: 0.0
                复数: 0i
                字符串: ""
            const (
                _ = 1 << (10 * iota)             # 下值为 1<<(10*1)
                ...
            )


    type                    # 类型声明
        type A int          # 底层共类型, 可赋值性,可比较性。可重写String方法让fmt打印时个性化
        a = A(i)            # 可赋值就可类型转换
    func
    变量生命周期
        包级别是整个程序执行时间
        局部变量声明时创建,直到不可访问
    堆栈
        逃逸变量(函数外保存地址)在堆,局部变量在栈                   # 与变量创建方式无关(new与否), 逃逸需要一次额外内存分配。
赋值
    x = 1
    *p = 1
    p.name = ""
    m[key] = 1

    +=
    i++和i--                # 只能自成一行, 且不能++i, --i
    _                       # 忽略变量
    a, b = b, a             # 多重赋值

    v, err = f()
    v, ok = m[key]          # map查询
    v, ok = x.(T)           # 类型断言
    v, ok = <-ch            # 通道接收
    可赋值性:类型精准匹配,nil赋值任何接口变量或引用变量, 常量更易隐式转换赋值
        ==和!= 比较,两边要求是可赋值的
指针                         # 不能运算
    &获取地址
    *获取指针
语句
    变长参数
        f(s...)
    for
        for i, j := 0, 1; i < n; i++ {}
        for i < n {}
        for {}
        for index, value := range slice1{}
        for key, value := range map1 {}
        for range s{}
    if
        if i < n {} else if i < m {} else {}
        if err := f(); err != nil {}
    switch
        switch {                # 无标签(tagless), 相当于switch true,
        case x > 0:             # fallthrough可贯穿, 可用控制流标签
        }
        switch i := 0 {}        # switch true
        switch i++ { }          # switch true
        switch f() {}           # switch true

        switch i {
        case 0:
        case 1:
        default:                # default可在任何地方
        }

        switch t.(type) {                   # 类型匹配, 无匹配类型会panic, 不能用fallthrough
        case nil:
        case int, uint;
        case bool:
        case string:
        default:
        }
        switch x := x.(type) {}
    select                                  # channel用select, 值用switch。一直等待直到匹配(default会直接匹配)。多情况匹配随机选择。不能用fallthrough
        select {
        case <-ch1:
        case x := <-ch2:
        case ch3 <- y:
        default:
        }

        o-> 超时
        select {
        case <-time.After(10*time.Second):
        case <-ch:
        }

        o-> 自发自接
        for i := 0; i < 10; i++{
            select {
            case x := <-ch:
            case ch <- i:
            }
        }

        o-> 标签
        c := make(chan struct{},2)
        label1:
        for {
            select {
            case c<- struct{}{}:
                fmt.Println(1)
            case <-c:
                fmt.Println(2)
                break                       # 无标签break跳出当前select块
                    # break label
                    # goto label2
                    # return
            default:
                fmt.Println(3)
            }
        }
        label2:
        ...
    控制流标签
        break, continue, goto   # 可标签化, 如break Label1
作用域
    词法块:语法块(block)(大括号), 隐式块(未在大括号中的声明, 如if中)
        全局块                   # 内置
        包级别                   # 函数外的声明
        文件级别                  # 导入的包
        局部
    控制流标签作用域是外层函数
    覆盖
        x := 1
        for {
            x := x+1
            if .. {
                x := x+1        # 这里值的x是最外层x
            }
        }
    if声明的变量(隐式词法块),else中可见
        if v, err := f(); err != nil {      # else中处理非err逻辑
            return err
        } else {
            v.close()
        }
    包中声明作用域无顺序,可递归    # 常量、变量不可以引用自己
 函数
    字面量
        var func()                   # 声明
        func f(i int) int {}
        func f(i, j int) (int, error){}
        func f() (r int){}
        func f(vals ...int) {}       # 变长函数, 只放最后, vals是slice
            f(vals...)
    一等公民
    函数签名,即函数类型,包括形参列表和返回列表, 命名不影响
    未定义时为nil, 不可比较
    值传递, 不能指定默认值
    函数返回多值, 可return, 可做传入参数
    返回值有命名,可祼返回(不在return后写参数)
    错误
        v, ok := f()                  # 错误只一种情况
        v, err := f()                 # 错误信息会串联,避免首字母大写和换行
        if err != nil {
            return nil, err
        }
    匿名函数用字面量定义,包含外层词法环境(闭包)
        递归要先声明,再赋值定义
        重定义变量
        for _, dir := range dirs() {
            dir := dir                      # for块作用域变量共享位置,重定义dir每次一个位置
            dirs = append(dirs, func(){     # 匿名函数引用外层变量,却不一定同步执行
                os.RemoveAll(dir)
            })
        }
方法
    字面量
        func (t T) f(){}                    # t值传递, 方法名唯一, 方法名不能用字段名
        func (t *T) f(){}                   # t引用传递

        type Path []Point                   # 别名赋方法(不能是指针和接口), 可覆盖原类型方法
        func (p *Path)f(){}
    方法可在任何类型(除指针和接口), 如函数
    变量与变量指针都可直接调方法,编译器隐式取地址或取指针
        P{1}.f()                            # 编译器不报错但运行出错, f()声明成引用传递, 但P{1}.时, 内存地址还未分配, 即还没有*P, 就无法调f()
    有引用传递方法时,避免值传递方法,会产生多例
    值为nil时可调方法
    方法可赋值
        f := t.f
        f(t.f)
    组合
        结构体匿名成员方法可如属性般直接调用
        匿名成员是引用时,多结构体可组合同一成员对象
        多匿名成员方法冲突时,调用时编译报错
        可给未命名结构体加方法
            t = struct{
                sync.Mutex
                v int
            }
            t.Lock(); t.v++; t.Unlock()
接口
    字面量
        type I interface {
            f()
        }
        type I2 interface {                  # 接口组合
            I
        }

        v := t.(T)                           # 断言,失败panic
        v, ok := t.(T)                       # 失败不panic, ok=false
    隐式实现,方法匹配即可(接口即约定)           # 鸭子
    指针方法匹配接口,对接口赋值时要传指针
    interface{}为空接口类型,可赋值任何类型
    实现
        除了接口的定义类型,还包含动态类型(Type) + 动态值(Value)               # 编译时不知道,生成代码在运行时动态分发
            零值,是动态类型和动态值都是nil
                动态类型是nil, 指的是它为接口本身类型
                i = nil会设置接口为零值
            ==和!=比较
                动态值都为nil相等
                动态类型和动态值都相等,才相等
                    i = new(T); i != nil
                动态类型一致,动态值不可比较(如slice), 则panic                # 非平凡
                格式化输出%T拿到动态类型
    断言
        变定义类型, 动态类型和动态值不变
        空接口断言总失败
        断言成接口,使用公共功能
            v := t.(I)
            v.Common()
    风格
        强调功能相似性                         # 子类型多态(subtype polymorphism)
        联合再断言区分                         # 可识别联合(discriminated union), 特设多态(ad hoc polymorhpism)
            switch t.(type) {}
关键字
    defer fn                                 # 后进先出, return或panic后调用
        defer func(i){...}(1)
        return、出参赋值、defer顺序            # 先赋值,再defer,再return
            func f() (i int) {
                defer func(){
                    i++
                }
                return 0          # 相当于 i=0; i++; return
            }
    go fn
    异常
        panic()
            日志包括值(interface{}), 调用栈
                用interface{}自定义异常类型
                runtime.Stack()查看栈,利用defer函数在栈清理前调用, 所以栈存在
            终止当前goroutine, 外层goroutine不捕获
            按函数调用栈依次中止函数并调defer, 最上层后程序异常退出
            panic之后定义的defer不执行(声明不提前)
        recover()
            中止panic
            在defer中(panic时只调defer)捕获panic对象,没有时为nil
            捕获panic对象后, 捕获函数正常返回。要上抛就再手动panic()
        o->
        func Try(fn func(), handler func(interface{})) {
            defer func() {
                if err := recover(); err != nil {
                    handler(err)
                }
            }()
            fn()
        }

        func main() {/
            Try(func() {
                panic("a")
            }, func(e interface{}) {
                print(e)
            })
        }

内置 #

零值                              # 保障变量良好定义,没有未初始化变量
    数字0, 布尔false, 字符串""
    接口和引用类型(slice, 指针, map, channel, 函数)nil
    复合类型其所有元素或成员零值
常量
    true
    false
    iota
    nil
        比较
            var s []int         # 未初始化比较, ==nil
            s = []int(nil)      # 强转, ==nil
            s = []int{}         # 初始化比较, !=nil
基本类型
    字面量
        06                      # 8进制
        0x0a                    # 16进制
        .1或1.                   # 小数点前后可省略
        2.2e10                  # 科学计数法
        1 + 2i                  # 复数
        字符串
            "\\"                # 转义
            "\r"                # 光标退到行首
            "\b"                # 光标退一字符
            "\x1a"              # 16进制表示位数据, 必2位,无法识别成unicode
            "\212"              # 8进制表示位数据, 必3位, 无法识别成unicode
            "\u1234"            # unicode, 16进制数字, 共4x4=16位
            "\u12345678"        # unicode, 16进制数字, 共4x8=32位
            ``                  # 原生字符串, 回车被删除(换行符保留)
    注意
        会自动截断,如int i=127; i+1=-128; i*i=1
    int                         # 平台原生整数大小,或该平台运算效率最高值, 多是int32
    int8                        # -128-127
    int16
    int32
    int64
    uint                        # 平台决定大小。无符号极少用于表示非负值,往往用于位运算或特定算术运算符,如位集,解析二进制,散列,加密
    uint8                       # 0-255
    uint16
    uint32
    uint64
    uintptr                     # 存放指针,大小不明确,底层编程
    float32                     # 运算会迅速累积误差, 正整数范围有限
    float64
    complex64                   # float32构成
    complex128                  # float64构成
        var x complex128 = complex(1,2)
        x := 1 + 2i
    bool
    byte                        # uint8别名, 强调是原始数据
    rune                        # int32别名, unicode码点(UTF-8), 下标取字符(非字节)
    string                      # 认为是UTF-8编码的unicode, 不合理字节替换成方块(\uFFFD)。不可变(安全截取、共用), 下标取字节,越界宕机异常
        和数组和slice一样操作
        []byte和string元素操作一致,只类型不同
        互换
            []byte, []rune, string                  # 转换产生副本
    error
聚合类型
    数组
        字面量
            var q [3]int
            q := [3]int{1,2,3}
            q := [...]int{1,2,3}                        # 长度由元素个数决定
            q := [...]int{0: 1, 3:2}                    # 指定索引元素值
        数组是值传递
        数组元素不可包含自己
        默认元素为零值
        不同长度不同类型,不能赋值
        如果元素可比较,数组就可比较     # 深度比较
            q1 < q2                   # 字符串比较按字节字典排序
    slice
        字面量
            q := []int{1,2,3}                           # 这里创建了slice, 指向了隐式创建的数组
            q[0:1]                                      # 左闭右开
            q[:1]; q[1:]; q[:]
        轻量级数据结构,用来访问数组的部分
        零值是nil, 行为和slice一样,不用特殊判断
        slice后标访问越界时,会自动扩展,越界超过数组长度+1时,会panic
            append(arr[:i], arr[i+1:]...)删除元素, i为最后元素时, i+1不越界
        不可比较, 只有写函数实现。只能和nil比较
            因为slice的元素不是直接的
                有可能包含它自身
                同slice不同时间会拥有不同元素
                    如果slice可比较来做map键, map只对key做浅拷贝, slice需要深度比较, 所以要求slice元素不变
        三元素                         # 有自己的属性,不是纯引用类型,是聚合类型
            指针: 指向slice在数组上起始位置
            长度: slice长度
            容量: 指针到数组结尾元素个数
    map                                # key可nil, 取不存在key时, 得到value类型的零值。随机无序遍历
        字面量
            m := map[string]int{
                "a":1,
            }
            a["b"]=2
        不能获得地址,如&m["a"]          # 因为map增长时,已有元素可能重新散列
        迭代顺序随机                     # key用维护排序, 散列算法健壮
        零值是nil, 向nil map设置元素会panic
        map[key1]没有时,获得零值
            v, ok := m["a"]             # 判断有无key
        不可比较,只能和nil比较
        key要求可比较,可以数组,不可以slice,可以自己映射成可比较类型
            q := [2]int{}
            m := map[[2]int]int{}
            m[q] = 1
    结构体
        字面量
            type T struct {                             # 结构体,
                Name string `json:"name0,omitempty"`    # 成员标签定义, opmitempty在零值时忽略
                I1, I2 int
            }

            t := &T{"a"}                                # 顺序易出错, 用于明显的小结构。未指定成员为零值
            t := &T{
                Name: "a",
            }
            (*t).Name = "a"
            t.Name = "a"                                # .可以用于指针

            struct{}                                    # 空结构体,没有长度,无信息。

            type T1 struct{                             # 匿名成员
                T
                T2
                *T3
                Name1 string
            }
            t1 := T1{
                T: {
                    Name: "a"
                }
            }

        首字母大写可导出
        属性类型不可自己,但可自己指针
        结构体零值由成员零值组成            # 希望结构体方法中处理零值成一个自然的值,如sync.Mutex
        成员可比较,结构体实例可比较, 可作map key
        匿名成员(组合)
            点号访问可跨入(语法糖),访问匿名成员属性和方法
                t1.Name; t1.T.Name
            不能有相同类型的匿名成员
            不可导出类型的匿名成员,内部成员不影响,但匿名成员本身不可见
引用类型
    Type
    IntegerType
    FloatType
    ComplexType

    chan
        ch := make(chan string)

        var cin chan<- string
        var cout <-chan string

        ch <- ""
        <-ch
接口类型
    error
        Error()
命名类型
    type
    结构体
        type Point struct {
            X, Y int
        }
函数
    make()
        make([]int)
        make(map[string]int)
        make(chan int)
    delete()
        delete(m, "a")          # 删除map元素, 没key不报错返回零值
    len()
        len(ch)                 # 当前缓冲个数
    cap()
        cap(ch)                 # 缓冲区容量
    new()                       # 创建指定类型变量,初始化为零值,返回地址。不带任何信息且是零值(struct{}和[0]int)的类型, new出的地址不同(从前相同)
        t := new(T)
    append()                    # 操作slice
        先检查原容量,容量够修改原数组元素,不够创建新数组(容量扩一倍)复制元素, 返回新slice
        所以append()最好赋值给原slice
        s1 := append(s1, s2...)
    copy()                      # slice或string元素复制
    close()                     # channel中用
    complex()                   # 创建复数对象
    real()                      # 获取复数的实部
    imag()                      # 获取复数的虚部
    panic()
    recover()
反射
    谨慎使用
        脆弱,能导致编译报错的写法,反射中都对应panic,执行时才知道
        降低自动重构和分析工具的安全性与准确度,反射对类型操作无法静态检查
        反射慢1-2个数量级(实测20位左右), 适合测试用,不适合关键路径上用
unsafe
    值在内存中对齐,计算更高效。结构体用内存间隙来对齐,占空间比元素之和更大
    结构体成员内存中重新排列可省内存,但目前不是
cgo
    o-> c文件
    #include <bzlib.h>
    int bz2compress(bz_stream *s, int action, char *in, unsigned *inlen, char *out, unsigned *outlen) {...}

    o-> go文件
    /*
    #cgo CFLAGS: -I/usr/include
    #cgo LDFLAGS: -L/usr/lib -lbz2
    #include <bzlib.h>
    int bz2compress(bz_stream *s, int action, char *in, unsigned *inlen, char *out, unsigned *outlen);
    */
    import "C"
    import (
        "io"
        "unsafe"
    )
    type writer struct {
        w io.Writer
        stream *C.bz_stream
        outbuf [64*1024]byte
    }
    func NewWriter(out io.Writer) io.WriteCloser{
        const (
            blockSize = 9
            verbosity = 0
            workFactor = 30
        )
        w := &writer{w: out, stream: C.bz2alloc()}
        C.BZ2_bzCompressInit(w.stream, blockSize, verbosity, workFactor)
        return w
    }
    func (w *writer) Write(data []byte) (int, erro) {
        if w.stream == nil {
            panic("closed")
        }
        var total int
        for len(data) > 0 {
            inlen, outlen := C.uint(len(data)), C.uint(cap(w.outbuf))
            C.bz2compress(w.stream, C.BZ_RUN, (*C.char)(unsafe.Pointer(&data[0])), &inlen, (*C.char)(unsafe.Pointer(&w.outbuf)), &outlen)
            total += int(inlen)
            data = data[inlen:]
            if _, err := w.w.Write(w.outbuf[:outlen]); err != nil {
                return total, err
            }
        }
        return total, nil
    }

    注释
        #cgo 指令指定C工具链选项
    import "c"
        编译时促使go build用cgo预处理其上注释
        产生临时包包含c函数对应声明
            包含类型,函数,预处理宏对象
            这里用了C.bz_stream和C.BZ2_bzCompressInit
    go也可编译成静态库链接进C, 或编译成动态库通过C加载和共享

内部包 #

# golang.org/pkg 找到索引
errors
    New()
testing
    T
        Error()
        Errorf()
        Fatal()
        Fatalf()
    B
syscall                 # 执行其它语言
syscall/js
js/wasm                 # 1.11, webAssembly
go/doc
go/token
runtime
    Stack()                             # 调用栈
    Gosched()                           # 让出执行权
    Goexit()                            # 终止当前goroutine, 会执行defer
    LockOSThread()                      # 绑定协程到当前线程
    UnlockOSThread()
    GOMAXPROCS()                        # 并发线程数
    NumGoroutine()                      # 限制goroutine数
runtime/debug
os
    Stdin                   # 输入流
    Args                    # 运行参数
    FileInfo

    Open()                  # 打开文件
        File
            Read()
            Write()
            Close()
    Exit(1)                 # 1异常退出
    RemoveAll()
    Stat()                  # 文件信息
os/exec                     # 子进程
io
    EOF                     # 文件结束标志, 是一个error

    Copy()
    WriteString()
io/ioutil
    Discard                 # 丢弃

    ReadFile()              # 读整个文件到内存
    ReadAll()
    WriteFile()
    ReadDir()
bufio                       # 带缓冲io
    NewScanner()
        Scanner             # 以行或单词断开
            Scan()          # 有内容返回true
            Text()
    NewReader()
        ReadRune()
path                        # 文件路径
    Base()                  # 获得最后文件名
path/filepath               # 根据平台处理文件路径
net
    Conn
net/http
    poolServer(epoll/kqueue/iocp)
        # 支持多核大量并发连接fd
    Get()
        Header
            Get()
        Body
            Close()
    HandleFunc()
        ResponseWriter
        Request
            RemoteAddr      # 客户ip:端口
            Host
            Method
            Proto           # 网络协议
            Header
            Form            # 先ParseForm()
            URL
                Path

            ParseForm()
    ListenAndServe()
net/http/httputil
net/url
    QueryEscape()           # url转义
context                     # 线程安全, 树形结构
    Cancel()
    Deadline(Timeout)
    Value()
    TODO()

    o-> ctx.Done()
    func f(ctx context.Context) (error) {
        errc := make(chan error, 1)

        go func() {
            defer close(errc)
            time.Sleep(2 * time.Second)
            errc <- nil
        }()

        select {
        case <-ctx.Done():
            <-errc
            return ctx.Err()
        case err := <-errc:
            return err
        }
    }

    o-> WithTimeout
    ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)     # 调cancel提前结束
    defer cancel()
    return f(ctx)
flag
    Args                    # 非标识参数
    Parse()                 # 出错调os.Exit(2)

    o-> 输入'-s / a bc', 输出'a/bc'
    sep := flag.Strings("s", " ", "desc s")
    flag.Parse()
    println(strings.Join(flag.Args(), *sep))
log
    SetPrefix()
    SetFlags()              # 格式标记
    Fatal()                 # 加日期时间前缀
    Fatalf()
time
    Time
        Format()

    Now()
    Since()
        Seconds()
    After()
    AfterFunc()
    NewTicker()
        ticker := time.NewTicker(1 * time.Second)
        <- ticker.C
        ticker.Stop()
    Tick()
        tick := time.Tick(1 * time.Second)          # 无法中止, 用于全局,否则内部goroutine泄漏
        for {
            <-tick
        }


fmt                         # string类型会调对象的String()方法
    Stringer                # 接口,有String()方法可匹配

    Printf()                # 可以用转义序列(\t等)表示不可见字符
        %d                  # 十进制整数
        %x, %o, %b          # 十六进制、八进制、二进制整数
            %X
            % x             # 十六进制输出,两数一空格
        %f, %g, %e          # 浮点数6位小数、15位小数并自动精度与表示方式、6位小数e表示
            "%8.3f"         # 输出8字符宽度,保留3位小数
        %t                  # 布尔
        %c                  # unicode字符
        %s                  # 字符串
            %*s             # 缩进后面指定数字个空格
        %q                  # 带引号字符串("abc"),或字符('c')
        %v                  # 内置格式的任何值
            %#v             # 包含结构体成员名字
        %T                  # 类型
        %[1]c               # 重复利用第一个参数
            Printf("%d %[1]c %[1]q", 'a')
        %%                  # %本身
        特殊数字
            var z float64
            fmt.Println(z,-z,1/z,-1/z,z/z)              # "0 -0 +Inf -Inf NaN"
    Fprintf()
    Scanf()                 # 格式化输入
    Errorf()                # 产生一个error
strconv                     # 类型转换
    ParseFloat()
    ParseInt()
    ParseUint()
    Itoa()                  # 整数转字符串
    FormatInt(int64(1a), 2)
    FormatUint()
unicode                 # 单符号
    ToUpper()
    ToLower()
    IsDigit()
    IsLetter()
unicode/utf8            # 逐个处理
    RuneCountInString()                 # 字符数
    DecodeRuneInString()                # 解码, string类型默认调用
bytes                       # 操作byte数组
    Buffer
        WriteByte()
        WriteRune()
        WriteString()
        String()

    Index()
    Contains()
    Count()
    Fields()
    HasPrefix()
    Join()
    Equal()
strings                     # 处理UTF-8或位序列
    Index()
    Split()
    HasPrefix()
    HasSuffix()
    Contains()
    Count()
    Fields()
    Join()
regexp
    MustCompile()           # 检查
    Compile()               # 编译表达式
text/template
    Must()                  # 检查,有错panic


    o->
    {{.Name}}               # .代表当前值
    {{range .Items}}
        {{.Title | printf "%.64s"}}
        {{.CreateAt | daysAgo}}
    {{end}}
    template.New("report").
        Funcs(template.FuncMap{"daysAgo": daysAgo}).
        Parse(templ)
text/tabwriter              # 生成表格
    Flush()
html/template               # 对html, js, css, url中原字符转义, 避免对输出页面注入控制
    Html                    # 字符串转成该类型,受信任,不用转义

    Parse()                 # 解析html
encoding/json               # unicode
    Marshal()               # 转成json, 不可导出不可见
    MarshalIndent()         # 格式化转成json
    Unmarshal()
    NewDecoder()            # 流式解码
        Decode()
encoding/xml
encoding/gob
encoding/asn1
compress/gzip               # DEFLATE算法
    NewWriter()
    NewReader()
compress/bzip2              # Burrows-Wheeler变换, 压缩高,慢


sort
    IntSlice
        sort.Sort(sort.IntSlice(ints))

    Sort()
    Reverse()
        sort.Sort(sort.Reverse(values))
    IsSorted()
    Strings()
    Ints()
    IntsAreSorted()

    o->
    type StringSlice []string
    func (p StringSlice) Len()int {return len(p)}
    func (p StringSlice) Less(i, j int)bool {return p[i] < p[j]}
    func (p StringSlice) Swap(i, j int) {p[i], p[j] = p[j], p[i]}
    sort.Sort(StringSlice(names))
math
    Sin()
    NaN()               # 返回NaN, NaN值比较总false(除!=), NaN用作信号量
math/rand
    Seed(time.Now().UTC().UnixNano())
    Float64()
math/cmplx              # 复数运算
    Sqrt(-1)            # 0 + 1i
math/bits
image
    Rect()
    NewPaletted()
        SetColorIndex()
    Decode()
    Encode()
image/color
    Color
    White
    Black
image/gif
    GIF
image/jpeg              # 空导入注册解码器
image/png               # 空导入注册解码器


sync
    Mutex
        Lock()
        Unlock()
    RWMutex
        Lock()
        Unlock()
        RLock()
        RUnlock()
    Once                                # 单例资源初始化,解决了多线程下读检查,防重写的问题
        Do()
    WaitGroup
    Cond
        Wait()                          # 计数加1, 进入阻塞
        Signal()                        # 解除一个阻塞,计数减1
        Broadcast()                     # 解除所有阻塞
    Map
    Pool


reflect                 # 非导出字段反射可见, 不可更新
    Type                # 类型
        String()        # 类型描述, fmt.Printf()中的"%T" 内部调用
        Field()         # 结构体成员, 返回StructField
            Name
        Method()
    Value               # 值
        String()        # 值描述,如"<int Value>"
        Type()
        Interface()     # 返回接口具体值
            x := v.Interface()
            i := x.(int)
        Kind()          # 得到类型,Bool, String, 各种数字, Array, Struct, Chan, Func, Ptr, Slice, Map, Interface, Invalid(零值), Func
        Index()         # 数组
        NumField()      # 结构体成员数
        FieldByName()
        MapKeys()       # map
        MapIndex()      # map
        IsValid()
        IsNil()         # 指针
        Elem()          # 指针指向元素
        CanAddr()       # 是否可寻址,如指针元素取Elem()的值,数组元素
        Addr()          # 取地址
            v.Addr().Interface().(*int)
        CanSet()        # 检查CanAddr()和是否非导出字段
        Set()           # 要求可寻址, 类型一致。可Set()interface{}类型
            SetInt(), SetUint(), SetString(), SetFloat()            # 相对Set()有容错性,不可SetXx()interface{}类型
            SetMapIndex()
        NumMethod()     # 方法数
        Method()        # 取方法
            Name
        Call()          # 执行Func类型Value
    StructField
        Tag
    StructTag
        Get()           # 字段标签中key的值
    Method

    TypeOf()
    ValueOf()
    Zero()              # 零值
    Append()
    MakeMap()
    New()               # 类型新对象地址
    DeepEqual()         # 深度比较,基本类型用==, 组合类型逐层比较。
        判断武断,不认为值为nil的map和值不为nil的空map相等。slice同理
            var c, d map[string]int = nil, make(map[string]int)
            var a, b []string = nil, []string{}

unsafe                  # 由编译器实现,暴露了内存布局。
    Pointer             # 任何地址,可比较,可比较nil。无类型向内存写任意值。
        可转成uintptr对地址计算
            问题
                移动垃圾回收器(目前未用)在移变量时地址改变使地址出错。
                goroutine增长栈时旧栈地址重新分配
            解决
                Pointer转uintptr再转回来在一条语句中实现
            应用
                深度比较时,防止循环引用,每次比较存两个抽象的指针(即Pointer)和类型(y和y[0]地址一样)
        var f float64
        i := *(*uint64)unsafe.Pointer(&f)
    Sizeof()            # 表达式占字节长度, 不计算表达式,由编译器推断
    Alignof             # 报告类型对齐方式
    Offsetof()          # 成员相对起始偏移量, 计算空位

外部包 #

# godoc.org 搜索
goimports           # 格式化imports顺序

测试 #

规则
    文件名以_test.go结尾
    汇报PASS或FAIL, 平均执行时间
    忽略main函数, 当作库测试
        main特权函数 log.Fatal()和os.Exit()会阻止跟踪过程
    包测试循环依赖时,建立外部测试包
        导出内部成员用于测试的后门成员声明,放在export_test.go内
机制
    扫描*_test.go
    生成临时main包来调用,再编译、运行、汇报, 最后清空临时文件
Test函数                          # t用于汇报结果和日志
    func TestF(t *testing.T) {}
benchmark函数                     # 基准测试,性能
    b增加了成员N指定执行次数, 增加了性能检测方法
        开始指定小N, 再推断足够大的N检测稳定运行时间
    基准测试时初始化代码放循环外面,它的执行时间不加到每次迭代时间中。普通Test做不到
    用go test -bench=.运行
        报告中 f-8 1000000 1035 ns/op 分别代表GOMAXPROCS=8, 执行100000次,平均每次1035ns

    o-> 基本使用
    func BenchmarkF(b *testing.B) {
        for i := 0; i < b.N; i++{
            f()
        }
    }
    o-> 相对比较, 如数量级、找最佳缓冲区大小、选算法策略
    func benchmark(b *testing.B, size int){}
    func Benchmark10(b *testing.B) {benchmark(b, 10)}
    func Benchmark100(b *testing.B) {benchmark(b, 100)}
Example函数                       # 示例,无参无结果。
    用处
        可举例子作为文档
        结尾注释 // output: 验证终端输出
        实验代码
    func ExampleF()  {
        fmt.Print("a")
        // output: aa
    }

并发编程 #

同步
    func
    channel                                 # 和调度器深度关联,控制goroutine的阻塞和唤醒
        缓冲区
            作用
                异步
                    发送接收解耦
                    让数据可并行处理(计数信号量)
                    消除goroutine间速率差异(速率大致相同, 某刻休息)
                        上下游速率差异大时无作用
                阻塞时同步
            c := make(chan struct{})
            c1 := make(chan struct{}, 1)
            c ← struct{}{}                  # 阻塞
            ← c                             # 阻塞

            c1 ← struct{}{}                 # 不阻塞
            c1 ← struct{}{}                 # 阻塞
            ← c1                            # 不阻塞
            ← c1                            # 阻塞
        方向
            var c chan struct{}             # in和out
            var cin <-chan struct{}         # in, 关闭时panic
                v := <-cin
            var cout chan<- struct{}        # out
                cout <- v

            cin = c
            cout = c
            c = cin                         # 编译错误
            c = cout                        # 编译错误
        nil                                 # 永远阻塞, 用于开启禁用情况
            var c chan struct{}
            c <- struct{}{}                 # 阻塞
        关闭                                 # 关闭不是必须的,不影响回收。只是用来通知和广播
            c := make(chan struct{})
            close(c)                        # 再关闭panic
            c ← struct{}{}                  # panic
            o, ok := ← c                    # o得到零值, ok是false
    for range
        c := make(chan struct{})
        ...
        for x := range c {}                 # close(c)时break
    select

    sync包
    sync/atomic包


    o-> 并发三个业务, 一起结束
    cond := sync.NewCond(new(sync.Mutex))
    wg := sync.WaitGroup{}
    wg.Add(3)
    wg1 := sync.WaitGroup{}
    wg1.Add(3)
    for i := 0; i < 3; i++ {
        go func(i int) {
            defer wg1.Done()
            cond.L.Lock()
            fmt.Println("wait", i)          # 业务预处理
            wg.Done()
            cond.Wait()                     # 阻塞
            fmt.Println("done", i)          # 业务后续处理(要求所有业务预处理过)
            cond.L.Unlock()
        }(i)
    }
    wg.Wait()                               # 业务预处理完成

    cond.L.Lock()
    cond.Broadcast()                        # 处理业务后续
    cond.L.Unlock()
    wg1.Wait()                              # goroutine完成
异步
    语句
        语句是串行一致的(sequentially consistent)
        串行一致基础上,语句会重排, 重排中可能穿插执行其它goroutine语句
            t := map[string]int{
                "a": 1
                "b": 2
            }
            重排为
            t := make(map[string]int)
            t["a"]=1
            t["b"]=2
    goroutine
        语句
            go f()
        泄漏
            阻塞不能自动结束                  # 如操作channel时
            main中最后调panic(), 从崩溃转储信息判断资源释放情况
        死锁(deadlock)                      # 指没有可调度的goroutine
            所有goroutine阻塞或没有goroutine
        运行main的是主goroutine, main返回所有goroutine暴力终结
        无id(标识)
        不能中断
        无返回值
    runtime
    context
    time
并发模式                                    # 避免goroutine泄漏,保证通信顺序
    done/quit
        o-> done控制goroutine退出。         # 更快的响应要写更多的逻辑入侵,找到响应慢点写done逻辑
        func f(done <-chan struct{}) {
            select {
            case <-done:
                for range ch{              # 耗尽通道, 其它goroutine不会卡在ch<-上而退出
                }
                return
            }
        }
        func cancelled()bool{
            select {
            case <-done:
                return true
            default:
                return false
            }
        }
        func f2(){                          # 轮循函数中入口检查, 避免创建新goroutine
            if cancelled() {
                return
            }
        }

        done := make(chan struct{})
        defer close(done)
        f(done)
    channels of channels
        o-> 循环处理请求
        func handle(reqs chan chan interface{}) {
            for req := range reqs {
                req <- 0
            }
        }
        func server(req chan interface{}) {
            reqs := make(chan chan interface{})
            defer close(reqs)
            go handle(reqs)
            reqs <- req
        }
        func client() interface{} {
            req := make(chan interface{})
            defer close(req)
            go server(req)
            return <-req
        }
        fmt.Println(client())

        o-> 循环异常退出
        type S struct {
            closing chan chan error
        }
        func (s *S) close() error {
            errc := make(chan error)
            s.closing <- errc
            return <-errc
        }
        func (s *S) loop() {
            for {
                select {
                case errc := <-s.closing:
                    errc <- nil
                    return
                }
            }
        }
    pipeline(fan-in, fan-out)           # 传入传出channel来处理
        o->
        func gen(done <-chan struct{}, nums ...int) <-chan int {
            out := make(chan int)
            go func() {
                defer close(out)
                for _, n := range nums {
                    select {
                    case out <- n:
                    case <-done:
                        return
                    }
                }
            }()
            return out
        }
        func sq(done <-chan struct{}, in <-chan int) <-chan int {
            out := make(chan int)
            go func() {
                defer close(out)
                for n := range in {
                    select {
                    case out <- n * n:
                    case <-done:
                        return
                    }
                }
            }()
            return out
        }
        func merge(done <-chan struct{}, cs ...<-chan int) <-chan int {
            # wg等cs数目个协程合并数据到out后,关闭out
            var wg sync.WaitGroup
            out := make(chan int)

            output := func(c <-chan int) {
                for n := range c {
                    select {
                    case out <- n:
                    case <-done:
                    }
                }
                wg.Done()
            }

            wg.Add(len(cs))
            for _, c := range cs {
                go output(c)
            }

            go func() {
                wg.Wait()
                close(out)
            }()
            return out
        }

        func main() {
            done := make(chan struct{})
            defer close(done)

            for n := range sq(done, sq(done, gen(done, 2, 3))) {
                # gen产生维护数字chan, sq产生维护平方chan。三个chan
                # 三个goroutine done()时return, chan return时close()
                fmt.Println(n)
            }

            // 扇出
            in := gen(done, 2, 3)
            c1 := sq(done, in)
            c2 := sq(done, in)
            // 扇进
            for n := range merge(done, c1, c2) {
                fmt.Println(n)
            }
        }
    timeout
        select {
        case <-ch:
            ...
        case <-time.After(time.Second)
            return
        }
    控制并发数
        并发写缓冲区channel
        for循环产生并发数goroutine
常用
    中断
        # os.Exit()程序返回错误码

        done := make(chan struct{})
        go func() {
            defer close(done)
            c := make(chan os.Signal, 1)
            defer close(c)
            signal.Notify(c, os.Interrupt, os.Kill)
            defer signal.Stop(c)
            <-c
        }()
    并发压测
        func concurrent(done chan struct{}, fn func(), num int, ccu int, qps int) {     # num总数,ccu并行数,qps并发数
            interval := time.Duration(1e9/qps) * time.Nanosecond
            don := make(chan struct{}, 2)
            go func() {
                <-done
                for i := 0; i < ccu; i++ {
                    don <- struct{}{}
                }
            }()

            //
            tasks := make(chan struct{})
            go func() {
                var wg sync.WaitGroup
                wg.Add(num)
                for i := 0; i < num; i++ {
                    tasks <- struct{}{}
                    wg.Done()
                    time.Sleep(interval)
                }
                wg.Wait()
                close(tasks)
            }()

            //
            var wg sync.WaitGroup
            wg.Add(ccu)
            for i := 0; i < ccu; i++ {
                go func() {
                    defer wg.Done()
                    for range tasks {
                        select {
                        case <-don:
                            return
                        default:
                            fn()
                        }
                    }
                }()
            }
            wg.Wait()
        }
        m := sync.Mutex{}
        count := 0
        do := func(){
            m.Lock()
            count++
            m.Unlock()
        }
        concurrent(done, do, 999, 100, 1e3)

Python

介绍 #

虚拟机语言
虽然是脚本语言,可以预编译成pyc文件来执行

shell #

#! /usr/bin/python
# -*- coding: utf8 -*-

语法 #

规范
    pep8

内置函数 #

o->
    input("")
        # x = int(input("Please enter an integer:"))
    print("%s", % s1)
        ## %.3s % ("abcdef")取3字符
        ## %.* s % (2, "abcd")取2字符)
    # %r repr()显示字符串
        # %c 单个字符
        # %b 二进制整数
        # %x 十六进制整数
        # %d 十进制整数
        # %i 十进制整数
        # %o 八进制整数
        # %e %E 指数(基底分别为e E)
        # %-10.3f %-10.3F 浮点数
        ## 10位宽, 小数精确3位, 右对齐
        # %g %G 指数(e E)或浮点数(根据显示长度决定)
        # %% 字符%
        print("c is %s, e is %i" % (c, e)
    str(1)
    int("1")
    range(1, 10)
        # range(-2, -11, -3)
    exec('')
        # 执行字符串中的代码
    execfile(r'a.py')
    eval('2 * 3', globals, locals)
        # 执行字符串中的表达式
        # ast.literal_eval
    compile(str, filename, kind)
        # 编译字符串为模块
        # kind取值: single单语句, exec多语句, eval一个表达式
    assert 1 != 1
    repr(list)
        # 对象转换成代码字符串 
    map(str, range(100))
    filter()
    reduce()
    locals()
        # 当前作用域的变量字典
    isinstance(value, list)
    hasattr(obj, '__call__')
        # 判断是否函数
    type(l)
        # 返回对象类型,或创建metaclass
    chr(48)
        # 返回字符
    unichr
    ord('0')
        # 返回ascii码
    bool()
    iter()
    next()
    zip('abc', '123')
        list(zip())
o-> 文件
    spath = "D:/a.txt"
    f = open(spath, "w")
        # 没有时创建
    f.write("a\n")
    f.writelines("b")
    f.close()

    f = open(spath, "r")
    for line in f:
        print("%s" % line)
    f.readline()
    f.close()
o-> 文档
    dir(list)
    help(s.replace)

类型 #

o-> 基本类型
    数字
        1.2, 3+4j, Decimal, Fraction
    字符串


    列表
        [1, 2]
    字典
        {'a':1}
    元组
        (1)
    文件
        open('eggs', 'r')
    集合
        {'a'}
    其他类型
        类型, None, False, True
    编程单元
        函数, 模块, 类
    实现相关类型
        编译代码堆栈跟踪
                
o-> 扩展属性
    dict = type('dict', (dict,), {})
    d = dict()
    d.a = 1

o-> 序列
    [1,
    2]
    [1, [2]]

    len(l)
    l[0]
    l[-1]
    l[1:3]
    l[1:]
    l[:3]
    l[:-1]
    l[:]

    l + l
    l * 2
    del l[1:3]
    o-> 字符串
        # 不可变
        r'a' R'a' u'a' U'a' b'a' B'a'
        'abc\
        def'
        'a' 'b'
        'a' "a" '''a''' """a"""

        s.startswith('a')
        s.find('a')
        s.replace('a', 'A')
        s.split(',')
        s.join(list)
        s.upper()
        s.isalpha()
        s.isdigit()
        s.rstrip()
                # 去右侧空白
        '%s, %s' % ('a', 'b')
        '{0},{1}'.format('a', 'b')

        if 'a' in name:
    o-> 列表
        l.append('h')
        l.pop(2)
            # 弹出特定位置
        l.sort()
        l.reverse()

        print(l)

        for x in word:

        [2 * i for i in [2,3,4] if i > 2]
            # 列表解析
            [row[1] + 1 for row in M]
            [M[i][i] for i in [0, 1, 2]]
            {ord(x) for x in 'spaam'}
                # 创建集合
            {x: ord(x) for x in 'spaam'}
                # 创建字典
    o-> 元组
        # 不可变
        ('a', 'b')
        (1,) + (2,)
            # (1, 2)
        t.index('c')
        t.count('c')
    o-> set
        s = set('a')
        set([1])
        s.add(2)

        s1, s2
        s1 & s2
        s1 | s2
        s1 - s2
        {x ** 2 for x in [1,2,3,4]}
            # 返回set

o-> 字典
    d = {'a': 'aaa', 'b': 'bbb', 'c': 12}
    d['d'] = 3

    d.items()
        # key value
    d.keys()
        list(d.keys())

    len(d)
    del d['a']
    d.get('a', 0)
    d['a']

    for key in d:
    if 'a' in d:
    d['a'] if 'a' in d else 0
o-> 文件
    f = open('data.txt', 'w')
    f.write('a')
    f.close()

    text = f.read()
        text.split()

语句 #

o-> 语句
    在物理行中用分号划分逻辑行
    pass
o-> 运算符
    + - * / % << >> < > <= >= == !=
    & | ^ ~
        # 按位与 或 异或 翻转(x 变为 -(x + 1))
    not and or
    **
        # 幂
    //
        # 取整除
    code if None else 0
    True and 1 or 0
o-> 条件
    if x < 0:
            x = 0
    elif x == 0:
    else:
o-> 循环
    for x in a:
    else:

    while running:
    else:

函数 #

函数
    def sum(a, b=2, *args, **kwargs):
            # *args得到元组, kwargs得到字典
            ''' doc
        string'''

        global x
        nonlocal y
        return a + b
    sum(a=1)
    sum.__doc__

    def make_repeater(n):
        return lambda s: s * n
            # lambda只能跟表达式,返回一个函数
生成器
    def gn2():
        yield
    def gn(N):
        for i in range(N):
            yield i ** 2
        yield from gn2()
            # 相当于静态引入gn2
    g = gn()
    next(g)
    g.send(1)
asyncio模块
    @asyncio.coroutine
    def f():
        yield from asyncio.sleep(1)
    loop = asyncio.get_event_loop()
    tasks = [asyncio.async(f())]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()
协程
    @types.coroutine
    def f2():
        yield

    async def f():
        print(1)
        await f2()
                # 协程显式交替,线程不用写,会隐式交替

    try:
        f().send(None)
    except StopIteration:
        pass
协程asyncio
    async f():
        await asyncio.sleep(1)
    loop = asyncio.get_event_loop()
    tasks = [asyncio.ensure_future(f())]
    loop.run_until_complete(asyncio.wait(tasks))
    loop.close()
协程属性
    gi_frame
        f_code
            co_filename
        f_lineno
属性
    __name__
    __code__
    __annotations__

oop #

class Base:
    __metaclass__ = models.SubfieldBase
        # __metaclass__实例化结果是类,用于继承
    description = ''
    def __init__(self, name):
        # self就是this
        #  __del__(self)
        # __str__(self)
        # __lt__(self)
        # __getitem__(self, key)
        ## x[key]索引时调用
        # __len__(self)
        super(Base, self).__init__(*args, **kwargs)
        self.data = []

    def add(self, x)
        self.data.append(x)
    @classmethod
    def t1(cls):
    @staticmethod
    def t2():
class Child(Base):
    # 继承
    def plus(self, a, b):
        return a + b
oChild = Child()
oChild.add("str1")
oChild.data
oChild.plus(2, 3)

模块 #

# .pyc是字节编译文件
# __name__ 等于'__main__'时程序本身使用运行, 否则是引用

# a.py
def add_func(a, b):
        return a + b
# b.py
from a import add_func
    # import add_func as f
    # from a import *

# __init__.py
    # 表示文件夹为包, 可空

包路径
    # 环境变量PYTHONPATH中的值
    import sys
    import os

    sys.path
    sys.path.append(os.getcwd() + "\\parent\\child")

异常 #

if s == "":
    raise Exception("must not be empty.")
try:
    i = int(s)
except Exception as err:
    # except Exception, err
    print('Error %d: %s' % (e.args[0], e.args[1]))
except:
finally:
    print("Goodbye.")
else:

模块 #

os
sys
    argv
        # 参数列表, 多维列表
    exit()
        # 退出线程
imp
    reload
        # 重载模块
time
timeit
profile
decimal
fractions
urllib
http
    http.server
        # python3中的SimpleHTTPServer
re
functools
itertools
SimpleHTTPServer
    # python2自带ftp服务器。
    pythom -m SimpleHTTPServer 8080


PyQt
    # gui
PyGTK
    # gui
wxPython
    # gui
TkInter
    # gui
matplotlib
    # 图形
pillow
    # ocr, 文字识别
pytesseract
    # ocr, 精确


numpy
math
random
scipy
    # 科学计算

beautifulsoup
    # 网页结构化
scrapy
    # 网页结构化
requests
phantomJS
    # 运行网页js
selenium
    # 运行网页js


pandas
    # 数据分析,产生数据结构、操作、统计、绘图
seaborn
    # 数据可视化
scikit-learn
    # 机器学习
nltk
    # 自然语言分析


mysql-connector
mysqlclient
PyMySQL
MySQLdb
redis.py
south
    # 表结构迁移, django自带

pickle
    # 持久化
qrcode
    # 二维码


ast
    # 运算前检查的eval()
datetime
shutil
    # shell


fabric
    # 运程自动部署
celery
    # 定时调度

工具 #

ipython notebook
    # 在线运行python
bpython
    # 更好的repl
pdb
    # 调试
cprofile
    # 性能测试

steuptools #

easy_install

pip #

pip install -i http://pypi.douban.com/simple/ torndb
    # 用豆辨的pypi索引
pip install ipython==4.2.0
    # 安装指定版本

pyenv #

pyenv versions
pyenv install 3.7.6
    --list
pyenv virtualenv 3.7.6 37
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
pyenv activate 37
pyenv deactivate

conda #

环境相关
    conda env
        create -f e.yml     # 创建环境
            -n name1    
        list                # 列出所有环境
        remove -n name1     # 删除环境
    conda activate e1
    conda init bash
包相关
    conda list              # 当前环境所有软件包
    conda search pillow     # 列出包所有版本
    conda install pillow=7.0.0
        -c                  # 指定channel,相当于命名空间
    conda uninstall pillow
    conda upgrade numpy

容器 #

gunicorn
    # python实现
    sudo pip install gunicorn
    gunicorn -w4 -b0.0.0.0:8001 app.wsgi
uwsgi
    # c语言实现
    sudo pip install uwsgi
    uwsgi --http :8001 --chdir /path/to/project --home=/path/to/env --module project.wsgi
            # --home指定virtualenv的路径
nginx
shell

Clojure

介绍 #

    是jvm上的一个lisp语言变种,比lisp更强调纯函数式编程
    操作符知道自己的特征值(identity value), 如+是0, *是1
    数组是懒惰的,需要时求值。适用于任意层的嵌套。头元素在使用后舍弃
    集合(vector, map, set)都是持久的,使用共享结构,与ruby, java中非持久结构有相似的性能
            # 持久的数据结构中,其它线程对数据的修改对该线程是不可见的
    没有尾递归优化,不常用递归,要用loop.recur

语法 #

    s-expressions
            (max 3 5)
            (+ 1 (* 2 3))
            (def meaning-of-life 42)
            (if (< meaning-of-life 0) "negative" "non-negative")
    (def droids ["Huey" "Dewey" "Louie"])
            (count droids)
            (droids 0)
    (def me {:name "Paul" :age 45 :sex :male})
            (:age me)
    (defn percentage [x p] (* x (/ p 100.0)))
            (percentage 200 10)

并发 #

o-> 原子变量
        # 对一个值进行同步更新
(def my-atom (atom 42))
(deref my-atom)
@my-atom
(swap! my-atom inc)
(swap! my-atom + 2)
(reset! my-atom 0)

(def session (atom {}))
(swap! session assoc :username "paul")

(if (compare-and-set! a old new)
        # 判断原子变量a的值是否是old, 是时赋成new并返回true
new
(recur))

o-> conj 添加新成员
(def players (atom ()))
(defn list-players []
(response (json/encode @players)))
(defn create-player [player-name]
(swap! players conj player-name)
(status (response "") 201))
(defroutes app-routes
(GET "/players" [] (list-players))
(PUT "/players/:player-name" [player-name] (create-player player-name)))
(defn -main [& args]
(run-jetty (site app-routes) {:port 3000}))

o-> cons列表首添加元素
(def listv2 (cons 4 listv1))

o-> validator
        # 值改变之前调用
(def non-negative (atom 0 :validator #(>= % 0)))
(reset! non-negative -1)

o-> 监视器
        # 值改变之后调用 
(def a (atom 0))
(add-watch a :print #(println "Changed from " %3 " to " %4))
(swap! a + 2)
        # !的命名表示函数是事务不安全的

o-> 代理
        # 对一个值进行异步更新。
        # 代理维护的数据与事务数据相同。代理具有事务性,send会在事务成功后生效
        # 方便做内存并发日志系统
(def my-agent (agent 0))
@my-agent
(send my-agent inc)
        # send在值更新之前立即返回,不进行重试。多线程同时调用send, 调用被串行。具有副作用
        # send使用公用线程池,send-off使用一个新线程,send-via使用由参数指定的executor
(send my-agent #((Thread/sleep 2000) (inc %)))
        # 设置延迟时间
(await my-agent)
        # 等待代理执行完成后再继续。await-for函数可以设置超时时间

(def non-negative (agent 1 :validator (fn [new-val] (>= new-val 0))))
        # 代理可以使用校验器和监视器
        # 校验器失败时抛出异常,代理进入失效状态
        # 错误处理模式默认为 :fail, 可以置为:continue
        # 可以设置错误处理函数
(agent-error non-negative)
        # 查看代理是否在失效状态
(restart-agent non-negative 0)
        # 重置失效状态

o-> 引用
        # 只有在事务中才能修改引用的值,对多个值进行同步更新
(def my-ref (ref 0))
@my-ref

(dosync (ref-set my-ref 42))
        # dosync创建一个事务,事务同swap!一样,用重试机制实现
        # clojure的事务有原子性,一致性,隔离性,没有持久性
(dosync (alter my-ref inc))
        # commute替换alter,可以得到不很强的隔离性,用于做优化
(defn transfer [from to amount]
(dosync 
    (alter from - amount)
    (alter to + amount)))

o-> threed
(defn stress-thread [from to iterations amount]
(Thread. #(dotimes [_ iterations] (transfer from to amount))))
(let [t1 (stress-thread checking savings 100 100)
    t2 (stress-thread savings checking 200 100)]
(.start t1)
(.start t2)
(.join t1)
(.join t2))

o-> ensure确保当前返回的值不被其它事务修改
(when (and (= (ensure left) :thinking) (= (ensure right) :thinking))
(ref-set philosopher :eating))

csp #

介绍
        core.async提供了channel和go块
        引入的core.async中部分函数名与clojure核心库函数名冲突

o-> channel
(def c (chan))
(thread (println "Read:" (<!! c) "from c"))
        # thread是core.async提供的辅助宏,将其中代码运行在一个单独的线程上
(>!! c "Hello thread")

用例 #

o->求和
(defn recursive-sum 
""
        # 文档字符串
        ## (require '[philosophers.util :refer :all])
        ## (clojure.repl/doc swap-when!) 来查看文档字符串
[numbers & args])
        # &表示可变参数
        ## (apply f old args) 将args展开,作为附加参数传递给f
(if (empty? numbers)
    0
    (+ (first numbers) (recursive-sum (rest numbers))))

(defn reduce-sum [numbers]
(reduce (fn [acc x] (+ acc x)) 0 numbers))

(defn sum [numbers]
(reduce + numbers))

o->并行
(ns sum.core
(:require [clojure.core.reducers :as r]))

(defn parallel-sum [numbers]
(r/fold + numbers))

(def numbers (into [] (range 0 10000)))
(time (sum numbers))
(time (sum numbers))
        # 预热jim编译器
(time (parallel-sum numbers))

o-> map
(def counts {"apple" 2 "orange" 1})
        (get counts "apple" 0)
        (get counts "banana" 0)
                # 没有时返回设定的默认值0
        (assoc counts "banana" 1)
        (assoc counts "apple" 3)

o-> frequencies
(defn word-frequencies [words]
(reduce
(fn [counts word] (assoc counts word (inc (get counts word 0))))
{} words))

(frequencies ["one" "potato"])
        # 标准库中已提供

o-> partial函数
        # 返回一个被局部代入的函数
(def multiply-by-2 (partial * 2))
(multiply-by-2 3)

o-> 序列
(defn get-words [text] (re-seq #"\w+" text))
(get-words "one tow three four")
(map get-words ["one two three" "four five six"])
(mapcat get-words ["one two three" "four five six"])
        # 平辅数组

o-> iterate
        # 不断将函数应用到初始值,第一次返回值,第二次返回值
(take 10 (iterate inc 0))
(take 10 (iterate (partial + 2) 0))
(take-last 5 (range 0 10000))
        # 头元素使用后舍弃,耗相同的内存

o-> pmap
(pmap #(frequencies (get-words %)) pages)
        # pmap在需要结果时并行计算,仅生成需要的结果,称为半懒惰(semi-lazy)
        # #(...)是读取器宏,来快速创建匿名函数,参数通过%1, %2标识, 只有一个参数时可以是%
        ## (fn [page] (frequencies (get-words page)))与其等价

o-> merge-with
        # 标准库函数
(merge-with f & maps)
        # 将maps中其余map合并到第一个map中,返回合并后的map
        ## 同键名时,多个值从左向右地合并,调用传递的f(val-in-result val-in-latter)
(def merge-counts (partial merge-with +))
(merge-counts {:x 1 :y 2} {:y 1 :z 1})

o-> partition-all
        # 序列分批
(partition-all 4 [1 2 3 4 5 6 7 8 9 10])
        # ((1 2 3 4) (5 6 7 8) (9 10))

o-> reducers包
        # 化简器,不代表函数的结果,代表如何产生结果的描述
        ## 嵌套的函数返回化简器,比返回懒惰序列效率更高
        ## 可以对整个嵌套链的集合操作,可以用fold进行并行化
        # clojure.core中大部分函数都有其对应的化简器版本
(require '[clojure.core.reducers :as r]')
(r/map (partial * 2) [1 2 3 4])
        # 返回一个化简器(reducible)
(reduce conj [] reducible)
        # conj函数第一个参数为一个集合(初始值为[]), 将第二个参数合并到第一个参数中
(into [] reducible)
        # into函数为内置函数,同上

o->协议(类似java中的接口)来定义
(defprotocol CollReduce
        # 化简
(coll-reduce [coll f] [coll f init]))
        # coll相当于this, 支持多态性分派(polymorphic dispatch)
(coll-reduce coll f)

(defn my-reduce
([f coll] (coll-reduce coll f))
([f init coll] (coll-reduce coll f init)))
(my-reduce + [1 2 3 4])
(my-reduce + 10 [1 2 3 4])

(defn make-reducer [reducible transforms]
(reify
    CollReduce
    (coll-reduce [_ f1]
    (coll-reduce reducible (transformf f1) (f1)))
    (coll-reduce [_ f1 init]
    (coll-reduce reducible (transformf f1) init))))
        # 用reify实现一个协议
        # 调用reducible的coll-reduce方法。用transformf对f1进行转换,转换出的函数作为传给coll-reduce方法的一个参数
        # _表示未被使用的函数参数名,可以写成(coll-reduce [this f1])

(defn my-map [mapf reducible]
(make-reducer reducible
    (fn [reducef]
    (fn [acc v]
        (reducef acc (mapf v))))))
        # acc是之前化简结果, v是集合元素。mapf对v进行转换

o-> fold折叠
        # 不能适用于懒惰序列
(defprotocol CollFold
(coll-fold [coll n combinef reducef]))

(defn my-fold
([reducef coll]
    (my-fold reducef reducef coll))
([combinef reducef coll]
    (my-fold 512 combinef reducef coll))
([n combinef reducef coll]
    (coll-fold coll n combinef reducef)))

(defn make-reducer [reducible transformf]
(reify
    CollFold
    (coll-fold [_ n combinef reducef]
    (coll-fold reducible n combinef (transformf reducef)))

    (CollReduce
    (coll-reduce [_ f1]
        (coll-reduce reducible (transformf f1) (f1)))
    (coll-reduce [_ f1 init]
        (coll-reduce reducible (transformf f1) init))))

(def numbers (into [] (take 10000000 (repeatedly #(rand-int 10)))))
(require ['reducers.parallel-frequencies :refer :all'])
(time (frequencies numbers))
(time (parallel-frequencies numbers))

o-> doall强迫懒惰序列对全部元素求值
(reduce + (doall (map (partial * 2) (range 10000))))

o-> future
        # 单独线程中执行一段代码
        # 典型场景是异步通信
(def sum (future (+ 1 2 3 4 5)))
sum
        # 返回一个future对象
(deref sum)
@sum
        # 运行
(let [a (future (+ 1 2))
    b (future (+ 3 4))]
(+ @a @b))
        # let给a赋值,阻塞当前线程直到被求值
        # 外层加法将一直阻塞,直到所有代表的值被求值

o-> promise
        # 创建promise对象后,代码并不会像future一样立即执行,等待deliver赋值后执行
(def meaning-of-life (promise))
(future (println "The meaning of life is:" @meaning-of-life))
(deliver meaning-of-life 42)

o-> Compojure库的服务器
(def snippets (repeatedly promise))
(defn accept-snippet [n test]
(deliver (nth snippets n) test))
(future
(doseq [snippet (map deref snippets)]
    (println snippet)))

(defroutes app-routes
(PUT "/snippet/:n" [n :as {:keys [body]}]
    (accept-snippet (edn/read-string n) (slurp body))
    (response "OK")))
(defn -main [& args]
(run-jetty (site app-routes) {:port 3000}))

o-> re-seq正则
(defn sentence-split [text]
(map trim (re-seq #"[^\.!\?:;]+[\.!\?:;]*" text)))
        # trim是内置函数
(defn is-sentence? [text]
(re-matches #"^.*[\.!\?:;]$" text))

o-> reductions
        # 同reduce, 返回中间值构成的序列
(reductions + [1 2 3 4])
        # (1 3 6 10)

o-> clj-http库
(def translator "http://localhost:3001/translate")
(defn translate [text]
(future
    (:body (client/post translator {:body text}))))

o-> delay在解引用前不求值
(def translations
(delay
    (map translate (strings->sentences (map deref snippets)))))

o-> 系统时间
(defn now []
(System/currentTimeMillis))

o-> Schejulure库
(def session-sweeper
(schedule {:min (range 0 60 5)} sweep-sessions))
        # 定期调用

o-> Useful库
(defn expired? [session]
(< @(:last-referenced session) (session-expiry-time)))
(defn sweep-sessions []
(swap! sessions #(remove-vals % expired?)))
        # 删除元素

o-> Loop/Recur
(defn swap-when! [a pred f & args]
(loop []
    (let [old @a]
    (if (pred old)
        (let [new (apply f old args)]
        (if (compare-and-set! a old new)
            new
            (recur)))
        nil))))

工具 #

clojureScript
        # 编译到js

JS

基础 #

特性
    原型链, 面向对象, 动态语言(已超出脚本语言的范畴)
    弱类型,变量都是var
    解释器有自己的内存管理机制(garbage collection)
    自由数据类型转换                        # 产生了==, ===的判断相等的不同定义
v8引擎
    直接生成机器码
    分代式GC
    java jvm工程师参数了优化
历史
    Netscape(现Mozilla)创建JavaScript, 但JavaScript是Sun(现Oracle)的注册商标
    作为标准提交给ECMA(欧洲计算机制造协会), 改名为ECMAScript
        ECMAScript 3(ES3) 作为标准广泛使用
        ECMAScript 5(ES5) 定义了新的语言标准
        JavaScript1.5是Mozilla的版本号, 相当于ES3,包含一些非标准语言扩展
            JavaScript1.8 在实现es7
        JavaScript解释器或引擎(engine)也有版本号
            Google的叫做V8(现在是4.0)
    微软改动并取名Jscript

标准 #

ECMAScript 6 #

介绍
    目标是js可写
        复杂的应用程序
        函数库
        代码自动自成器(code generator)
    mozilla基于ECMAScript6 发布 JavaScript2.0
    V8, node.js使用

let                                 # 块级作用域中声明变量
const                               # 声明常量
Set对象                              # 同java Set, 是一个数组
    属性
        size
    方法
        add(value)
        delete(value)
        has(value)
        clear()
Map对象                              # 键值对,键可以是对象
    使用
        var m = new Map();
        o = {p: "Helllo"};
        m.set(o, "content");
        m.get(o);
    属性
        size
    方法
        set(key, value)
        get(key)
        has(key)
        delete(key)
        clear()
... (rest运算符)
yield关键字
class关键字

commonJS #

介绍
    模块化标准
    require同步加载, 再执行代码,会阻塞。对服务器不是问题,对浏览器是大问题
    输出的是值的拷贝
    require后的模块运行后缓存, 可手动清除缓存
commonJs规范下的javascript
    node.js
    mongoDB
    ringojs
使用
    var math = require('math');
    math.add(2, 3);
    let {stat, exists, readFile} = require('fs')
        # 加载fs所有方法生成_fs, 再取其中3个方法。没法做静态优化

AMD #

介绍
    模块化标准
    异步加载, 预执行
使用
    require(['math'], functioni (math){
        math.add(2, 3);
    });
        # 加载成功后进行回调

CMD #

介绍
    sea.js提出
    懒执行
使用
    define(function(require, exports, module){ ... })

词法 #

unicode编写的
    转义
        'café'表示为'caf\u00e9'
        'é' 也可以表示为'e\u0301', e后面跟一个语调符
区分大小写                                   # html中不区分大小写
注释
    //, /**/
标识符和保留字
    要求
        开头以字母、下划线、dollar符。
        后续可以加数字
        可以出现unicode字符集中的Mn类、Mc类、Pc类,如           # Mn表示非间距字符,Mc表示影响基字符标志位的间距字符, Pc是连接两个字符的连接符或标点符号。
            é, π,
    保留字
        break, delete, function, return, typeof, case, do, if, switch, var, catch, else, in, this, void, continue, false, instanceof, throw, while, debugger, finally, new, true, with, default, for, null, try
    未被使用的名保留字
        class, const, enum, export, extends, import, super
    严格模式下的保留字
        implements, let, private, public, yield, interface, package, protected, static
    严格模式下不能用做变量名
        arguments, eval
    es6新增保留字
        await
    ECMAScript3将所有java关键字列为保留字
    全局属性和对象和函数

直接量 #

直接量(numeric literal)
    1
    1.2
    "hi"
    'hi'
    true
    false
    /javascript/gi
        # 用于模式匹配
        ## 实际是一个RegExp对象
        ## gi是用来修饰匹配模式的含义
    null
    {x:1, y:2}
        {foo}                                   # 等同 {foo: foo}, 简化写法常用于函数返回值
        {method () {}}                          # 等同 {method: function () {}}
        {*m () {}}                              # generator
        {['a' + 'b']: 1}                        # object
        {['hello'](){reutrn 0;}}                # 对象属性是Symbol值时, name属性返回这个Symbol值的描述
        {get a () {}, set a (val) {}}           # 属性getter, setter。get, set函数的函数名name是 'get xxx', 'set xxx'
    [1,2,3,4]
整型直接量
    0
    10
    0xff/0Xff                                   # 16进制
    0o377                                       # 8进制
        0377                                    # ECMAScript标准不支持八进制直接量,某些实现可以采用八进制表示
                                                # ECMAScript6严格模式下, 八进制直接量是明令禁止的
    0b11/0B11                                   # 2进制
浮点型直接量
    3.14
    .333
    6.02e23                                     # 6.02 x 10^23
    1.4E-32
字符串直接量
    ECMAScript5可多行                             # ECMAScript3规定必须一行
        "one\
        long line"
    模板字符串                                   # 保留换行,空格,缩进
        var name = 'Bob';
        `hello ${name}                          # ${}中可用任意表达式,包括函数
        how are you`

语法 #

可省略的分号
    通用规则: 独占一行,并与下一行不能整体解析时
        var a = f
        反例                                      # 以 (, [, /, +, - 开始的语句极可能和前一条语句一起解析,可写成 ;(a+b)
            (a+b).toString(); 就不可以
    例外规则
        return, break, continue占一行时,总加分号
        ++, -- 永远解析为前缀, 所以作后缀时要加分号   # 如 x [换行] ++ [换行] y, 解析为 x; ++y
    '}'之前的分号

严格模式 #

区别
    所有变量都要先声明
    增加了保留字(如await, protected, static, interface)
    eval, arguments当作关键字
    不允许八进制整数直接量(0前缀)
    不能给只读属性赋值,不能给不可扩展对象创建新成员
    arguments对象拥有参数的静态副本。               # 非严格模式中,都是引用,可以改变原值
    限制调用栈检测能力                              # 具有caller和arguments属性,但访问时会抛出异常
        arguments.caller, arguments.callee都会抛出类型错误异常
        fn.caller, fn.arguments禁止使用
    对象定义同名属性产生语法错误, 函数声明同名参数产生语法错误

    禁止使用with语句
    this值在调用的函数中是undefined,                # this禁止指向全局变量
        指非属性调用,如eval(),非a.test()
    eval()代码不能创建局部变量或函数
        而是定义在eval创建的新作用域(在eval返回时弃用)中
        eval不包含外层作用域
    delete后非法标识符抛出异常
        如delete prop, 只能delete global[prop]
        delete不可配置属性抛出异常
    es5, es6中尾调用优化只在严格模式下开启             # 因为arguments.caller会跟踪函数调用栈, 无法开启

模块化 #

介绍
    es6中模块化思想是尽量静态化,编译时确定模块依赖关系与输入输出
    CommonJS(CMD)与AMD都只能在运行时确定
    UMD模式只是加了CMD和AMD的切换
es6
    特点
        import, export可以出现在顶层的任何位置
        import
            会变量提升, 会执行import的模块
            引入的变量是只读的,修改会报错。但可以修改引入变量的内部属性
            只加载3个方法,编译时加载,可能静态分析。但不能引用fs模块本身
            使引入宏(macro)和类型检查(type system)成为可能
        模块自动采用严格模式
        输出/引入的是值的只读引用, 值在运行时计算
    import
        import {stat, exists, readFile} from 'fs'                   # 多引用
        import {a as b} from './profile'                            # b 作为 a 的别名
        import 'lodash'                                             # 只运行模块
        import * as circle from './circle'                          # 引入模块到对象
            circle.area
        import a from './export-default'                            # 引入模块中默认的导出, a可以起任意名,不用大括号
            import {default as xxx} from './'                       # 本质是输出名字为default变量
        import def, {a} from './module'                             # 同时引入default和其它变量
    export
        export var a = 1;
        export function f () {}

        var b = 1, c = 1;
        export {b, c}                                               # 用于统一输出

        export {v1 as sv1}
        export {a as b} from './someModule'                         # 导入同时导出
        export v from 'mod'                                         # 导入同时导出, es7提案可省略大括号
        export default function() {}                                # export default命令来配置默认导出, 本质是输出名字为default的变量,系统允许它取任意名
                                                                    # export default foo 导出的foo名在模块外部是无效
    继承
        export * from 'circle'
        export var e = 2.7
        export default function() {}                                # 输出了circle模块的所有方法(忽略default), 又输出了自定义属性
循环引用
    CommonJS会输出已执行的部分
        写法问题
            var foo = require('a').foo
                a在别处循环引用时, 得到的foo可能是执行到一半的值
                而var a = require('a'), a.foo就会得到执行完后的值
        o-> 例子
        a.js
            exports.done = false;
            var b = require('./b.js');
            console.log('a.js => b.done : ', b.done)
            exports.done = true;
            console.log('a.js done')
        b.js
            exports.doen = false;
            var a = require('./a.js')
            console.log('b.js => a.done : ', a.done);
            exports.done = true;
            console.log('a.js done')
            main.js
            var a = require('./a.js'), b = require('./b.js')
            console.log('main.js => a.done: ', a.done, ' b.done: ', b.done)
        执行
            b.js => a.done: false
            b.js done
            a.js => b.done: true
            a.js done
            main.js => a.done: true b.done: true

            a.js中require('./b.js')阻塞, 执行b.js
            b.js中require('./a.js'), 加载已执行的a.js
            执行完b.js回到a.js, 执行完a.js
            main.js加载已执行的a.js b.js
    es6 import时不执行代码,而是引用
        o-> 例子                                  # CommonJS中不能执行, a加载b, b加载a, a没有输出, foo不存在, es6中可以执行
        a.js
            import {bar} from './b.js';
            export function foo() {
                bar();
                console.log('a.js done')
            }
        b.js
            import {foo} from './a.js';
            export function bar() {
                if(Math.random() > 0.5) {foo()}
            }
        babel-node a.js

        o-> 例子
        even.js
            import {odd} from './odd'
            export var counter = 0;
            export function even(n) {
                counter++;
                return n == 0 || odd(n - 1);
            }
        odd.js
            import {even} from './even';
            export function odd(n) {
                return n != 0 && even(n - 1);
            }
        main.js
            import * as m from './even.js'
            m.even(10)  // true
            m.counter    // 6                       # 10 变到 0 even执行了6次
            m.even(20)    // true                   # 20 变到 0 even执行了11次
            m.counter    // 17                      #es6中引用加载机制保证even, odd函数能加载,所以可执行。而CommonJS中循环引用,even和odd函数都不会加载

类型与变量 #

声明
    特点
        存值之前是undefined
        声明提前
        非声明变量赋值创建全局变量                     # ECMAScript 5 严格模式下未声明赋值会报错
            非声明的全局变量与声明全局变量的区别: 非声明的全局变量是可配置的(可delete),而var声明的全局变量不可配置
        let
            支持了直接用{}的块级作用域
            只在块级作用域有效
                for(let i = 0; ...; ...)
            无变量提升
            声明前存在暂时性死区
                死区中使用该变量会直接报错
            重复声明报错
            声明的全局变量不再是全局对象的属性
                同样机制的还有const, class
        const
            只能在声明时赋值一次, 其他同let
    var x;
    x = 1;
    let a = 10
    const PI = 3.1415
        export const A = 1;
            import * as constants from './constants'
            constants.A
类型
    特点
        可以拥有方法的类型, 不能拥有方法的类型
        可变(mutable)类型                           # 值可以改变, 比较(==, ===)是地址的比较
            对象
        不可变(immutable)类型                       # 比较(==, ===)是值的比较
            数字、布尔值、null、undefined、字符串     # 字符串不像c语言可以看作字符数组,js的字符串不可变
    原始值
        # 不可以拥有自己的方法
        null
        undefined
    原始类型(primitive type)                        # 可以拥有自己的方法, 原始类型都包含内置构造函数
        数字
        字符串
        布尔值
        Symbol
    对象类型(object type)或引用类型,如
        对象(object)是属性(property)的集合
            property由key/value组成
        全局对象(global object)
        数组类: Array
            内存连续保住的带编号的值的有序集合
        函数类: Function
            具有相关联的可执行代码的特殊对象
类型转换                                            # Symbol不可转换
    转换为数字                                      # 字符串允许在开始和结尾处带有空格
        false为 0
        true为 1
        ""为 0
        失败为 NaN
    转换为字符串
        -0 为"0"
        -Infinity 为"-Infinity"
        [9]为 "9"
        ['a']其他数组,调用join()方法
    对象转换字符串                                    # 运算符+ == != 的处理运用这里的原理
                                                    # 日期对象有自己的重定义,valueOf与toString返回的原始值将直接使用
        toString()
        valueOf()                                   # 没有toString()方法时调用, 如果返回原始值,自动将它转换为字符串
            数组、函数、正则表达式返回对象本身
            日期类返回毫秒数
        无法得到原始值则抛出异常
    对象转换数字                                      # 运算符 - < 用了这里的原理
        首先尝试valueOf()                            # 如果返回原始值,自动转换为数字
        再尝试toString()                             # 自动转换为数字
        无法得到原始值则抛出异常
        例子
            数字
                []为0                                # valueOf -> toString -> "" -> 0
                [9]为9                               # valueOf -> toString -> "9" -> 9
相等性
    null == undefined
    "0" == 0
    0 == false
    "0" == false

类型 #

数字
    基础
        所有数字用二进制浮点数表示(64位, 如java中的double)
            # IEEE-754标准
            ## 整数范围 -2^53 ~ 2^53(大约900亿亿)
        实际的操作(数组索引, 位操作符)基于32位整数
        负号是一元运算符,并不是数字直接量语法的组成部分
        0与-0唯一差别
            1/zero !== 1/-0    # 正无穷大和负无穷大不等
    实数近似表示(几乎所有现代编程语言都存在, 因为都是IEEE-754标准)
        浮点数表示褛的个数为18 437 736 874 454 810 627个
        IEEE-754标准精确表示1/2, 1/8, 1/1024,但不精确表示1/10, 1/00。
            # 建议用大整数进行重要计算(如元, 角, 分各用整数表示)
            所以js只能近似表示0.1
            var x = .3 - .2
            var y = .2 - .1
            x == y        // => false
            x == .1    // => false
            y == .1    // => true
字符串
    基础
        从0开始
        没有如c语言中的字符型
        采用UTF-16编码的Unicode字符集。
            是一组无符号16位值组成的序列。
                # 用16位内码表示, 表示一个单个字符
                ## 不能16位Unicode表示的遵循UTF-16编码规则,两个16位值来表示一个(代理项对)
                ### 长度为2的字符串可能表示一个Unicode字符,如var e ="\ud835\udc52"; e.length // => 2
            字符串的操作不对代理项对单独处理
            不对字符串做标准代加工
                所以不能保证字符串是剑的UTF-16格式
    运算
        +            # 字符串连接
    unicode
        允许采用\uxxxx表示\u0000 到 \uFFFF之间的字符
        超出范围时用4字节表示, 如 \uD842\uDFB7
        '\u20BB7' 会被解释成 '\u20BB' + '7'
        '\u{20BB7}' 会正确解释
        多种表示法
            '\z'
            '\172'
            '\x7A'
            '\u007A'
            '\u{7A}'
    转义
        十六进制数表示Latin-1或Unicode中的任意字码, 由两位十六进制数指定
            '\xA9'        // => ©
        \u表示4个十六进制数指定的Unicode字符
            '\u03c0'    // =>
        \n
        \'
        \0            # 同\u0000, 表示空字符串
        \b            # 同\u0008, 表示退格符
        \t            # 同\u0009, 表示tab
        \v            # \u000B, 垂直制表符
        \f            # \u000C, 换页符
        \r            # \u000D, 回车
布尔
    转换
        # 所有值都可以转换为布尔值
        false
            undefined
            null
            0
            -0
            NaN
            ""
        true
            除以上,全部为true
    api
        toString()                              # 转换成"true"或"false"
null undefined
    类型
        null为object                            # 但可以表示数字类型、字符串类型
        undefined为"undefined", 是一个单独类型
    比较
        null == undefined        // => true
        null === undefined        // => false
    无api                                       # .和[]取成员会产生类型错误
    bug
        undefined在ECMAScript可读/写,可赋任意值
    结论
        undefined表示系统级类似错误的空缺
        null表示程序级的,正常出现的空缺

Symbol
    介绍
        原始数据类型,因为不是对象,所以不能new, 不能添加属性
        不参与类型转换, 但可以toString            # 可以String(s)得到 'Symbol(a)', Boolean(s)得到true, !s 得到false。Number(s)会报错
        可以做属性名a[sym1] = 1, 不能用点运算符赋值或取值
        常用于设置常量结构体来switch,以消除魔术字符串

作用域 #

全局变量
    就是定义顶级对象的属性                         # 这点在ECMAScript规范中强制规定
    在js代码任何地方都有定义
局部变量
    在函数内有定义,优先于全局变量
与c语言区别(嵌套作用域)
    c中{}内产生块级作用域(block scope), 其中变量其外不可见
    js中没有块级作用域,是函数作用域(function scope), 变量在内部嵌套函数中有定义。
声明提前
    内部嵌套函数而言, 变量声明之前就可用, 称为声明提前(hoisting)         # hoisting js函数里声明的所有变量(不赋值), 被"提前"到函数体顶部,在js引擎预编译时进行。
    例子
        var scope = "global"
        function f(){
            console.log(scope)                  # undefined, 因为局部scope声明提前,覆盖了全局scope, 而声明提前不定义, 定义在执行代码时进行
            var scope = "local"                 # 等价于开头var scope;
            console.log(scope)
        }
特点
    js本身设计中没有构造函数,普通函数,对象方法,闭包。这些都是莫须有的叫法
    内部函数可以访问外部函数上下文
    非严格格式直接声明变量,挂到global上
    作用域在函数中定义, 非块定义, 所以
        for(var i = 0; i < 10; i++){            # 中定义的i与value,在for之外可以被访问, 且声明提前
            var value = 'hello';
        }
this
    有调用对象就指向调用对象
    没调用对象指向全局对象
        O.a = function(){
            var b = function(){                 # b中的this永远是全局对象
                console.log(this);
            };
            b();
        };
        O.a()
    new 构造时this指向新对象
        var O = function(){this.val = 100;}
        var o = new O();
        console.log(o.val);                     # 这里输出o.val而不是O.val
    用apply或call或bind方法改变this指向
        function tt(){
            console.log(arguments.callee);      # 永远是tt本身
            console.log(this);                  # 都是下面定义的a
        }
        var a = '1';
        tt.call(a, 1, 2);
        tt.apply(a, [1, 2]);
        var att = tt.bind(a);
        att();
参数调用时,会扩展作用域,如
    f(a.b)()                                    # a挂到f的作用域
    var f = function(c){}
作用域链(scope chain)
    特点
        每一段js代码有关联的作用域链
        一个对象链表,定义这段代码的作用域
        变量解析(variable resolution)时,从链第一个开始查找到最后一个   # 查找不存在时抛出引用错误(ReferenceError)
    原理
        定义一个函数时,实际上保存一个作用域链
        调用该函数时,创建新对象放局部变量,添加到保存的作用域链
        同时,创建一个新的、更长的"函数调用作用域链"
        该函数每次调用外部函数时,嵌套函数重定义
    代码作用域链分类
        顶层代码
            顶级对象属性
        无嵌套函数体
            var定义的局部变量
            顶级对象属性
        嵌套函数体
            var定义的局部变量
            顶级对象属性
            函数调用作用域"链"
    注意
        函数创建时,它的作用域链中会填入全局对象
        执行此函数时会创建一个称为“运行期上下文(execution context)”的内部对象
            运行期上下文定义了函数执行时的环境
            每个运行期上下文都有自己的作用域链
            其作用域链初始化为当前运行函数的Scope所包含的对象。
        函数中的值按照它们出现在函数中的顺序被复制到运行期上下文的作用域链中
            它们共同组成了一个新的对象,叫“活动对象(activation object)”
            该对象包含了函数的所有局部变量、命名参数、参数集合以及this
            此对象会被推入作用域链的前端
            运行期上下文被销毁,活动对象也随之销毁
        在函数执行过程中,每遇到一个变量,都会经历一次标识符解析过程以决定从哪里获取和存储数据。
            该过程从作用域链头部,也就是从活动对象开始搜索
            如果没找到继续搜索作用域链中的下一个对象
            如果搜索完所有对象都未找到,则认为该标识符未定义
        作用域链只会被 with 语句和 catch 语句影响。
    优化代码:
        因为全局变量总是存在于运行期上下文作用域链的最末端,因此在标识符解析的时候,查找全局变量是最慢的。
            所以,在编写代码的时候应尽量少使用全局变量,尽可能使用局部变量
            一个好的经验法则是, 如果一个跨作用域的对象被引用了一次以上,则先把它存储到局部变量里再使用
        优化with
            with(o){
            }
            使用with语句来避免多次书写document,看上去更高效,实际上产生了性能问题。
                代码运行到with语句时,运行期上下文的作用域链临时被改变了
                一个新的可变对象被创建,它包含了参数指定的对象的所有属性, 这个对象将被推入作用域链的头部
                这意味着函数的所有局部变量现在处于第二个作用域链对象中,因此访问代价更高了。
        优化try-catch
            try{
                doSomething();
            }catch(ex){
                alert(ex.message);              # 作用域链在此处改变。同理,catch语句使效率下降

            try{
                doSomething();
            }catch(ex){
                handleError(ex);                # 委托给处理器方法, 没有局部变量的访问,作用域链的临时改变就不会影响代码性能了。
            }                                   # 优化后的代码,handleError方法是catch子句中唯一执行的代码。该函数接收异常对象作为参数,这样你可以更加灵活和统一的处理错误。

表达式 #

介绍
    表达式(expression), 由解释器计算(evaluate)
原始表达式(primary expression)
    常量
    直接量
    关键字
        true, false, null, this
    变量名
对象和数组初始化表达式                             # 对象直接量、数组直接量
    {}
    []
函数定义表达式                                    # 函数直接量
    var square = function(x){reutrn x*x}
属性访问表达式                                    # 其前面的表达式首先计算, null, undefined会抛出类型错误异常,因为它们不能包含属性
    .
    [1]
    ["a"]
调用表达式(invocation expression)
    顺序
        首先计算函数表达式,再计算参数表达式
        传入实参的值赋值给形参
        执行函数体
        return返回值给变量名,无return 函数名赋为undefined
    左边是属性访问表达式时,称作方法调用(method invocation)
        函数体的this是宿主对象(执行者)
        非方法调用时,this是顶级对象
            ECMAScript 5中非方法调用时, this是undefined
    f(0)                                        # 非方法调用
    Math.max(x, y, z)                           # 静态方法调用, this为Math类
    a.sort()                                    # 动态方法调用, this为a实例
对象创建表达式(object creation expression)
    特点
        创建一个对象并调用构造函数
        与调用表达式相似
    过程
        创建空对象,该对象作为构造函数的this,可用来初始化动态属性
        传入指定参数,执行构造函数。
        返回值以构造函数返回值优先(本次对象废弃),没有时则返回本次创建的对象
    new Point(2, 3)
    new Object()
    new Object                                  # 不传参时, ()可以省略
关系表达式
    ==
    <
    in
    instanceof
逻辑表达式
    !
    &&
    ||
赋值表达式
    (a=b) == 0
    i = j = k = 0;

运算符 #

概念
    可符号,可关键字
    一元、二元、三元运算符                         # - +(正负号)是一元,*是二元, ?!是三元
    期望与转型
        "3" * "5"                               # 期望数字, 自动转型
        对类型依赖
            +                                   # 数字则运算,字符串则拼接
            <                                   # 数字则比较, 字符则比较字符表次序
    左值(lvalue)
        表达式只能出现在赋值运算(=)的左侧
            &, ++等操作符的操作数
            内存栈中的变量名
                变量、对象属性、数组元素
        内置函数可返回左值,自定义函数不可以
    优先级
    左右结合性
    运算顺序
        总是严格从左到右计算表达式
        表达式会影响变量值(如++, --, delete)时,先执行
            b = (a++)+a                         # 计算b, 计算a++(返回的结果是1), 计算右边的a(结果是2), 计算等号右边(1 + 2), 赋值
关键字运算符
    delete, typeof, instanceof, in, void
    in运算符                                     # 判断是否存在属性, 左是字符串, 右是对象
        'toString' in obj
        for( var i in ojb)
    instanceof运算符                             # 判断是否实例, 会判断父类, (prototype chain)
        o instanceof f                          # 遍历原型链, 计算f.prototype, 然后在o原型链中查找f, 找到则返回true
    typeof 运算符                                # 返回一个对象的类型描述字符串
        typeof value == "string" ? "'" + value + "'" : value
        typeof(value)                           # 可以写作函数的形式
        返回值
            "undefined", "object", "boolean", "number", "string", "function"
            null, 对象和数组 返回"object"         # 函数是对象的一种,但typeof特殊对待。
                                                # instanceof, class特性, constructor属性
    delete运算符                                 # 严格模式下删除失败会报错
        删除属性, 成功则返回true
        内置核心客户端属性不能删除
        var语句声明的变量不能删除
        function定义的函数和其参数不能删除
    void运算符
        写在操作数前,操作数照常计算, 但返回undefined
            <a href="javascript:void window.open();">               # 使浏览器不必显示计算结果
普通一元(目)运算符
    +                                           # 这里+, -表示正负号, +, -会把变量自动转型为数字
    -
    ++                                          # ++, -- 作为前增量时, 返回计算后的值,后增量时,返回计算前的值。与c语言不一样,c语言的前后增量作用于整个表达式s
    --
普通二元(目)运算符
    特点
        必要时转换数字
        js中数字都是浮点数, 所以5/2 = 2.5
        左结合
        根据类型进行数字相加或字符串连接
        对象先尝试转换数字(Date除外,先转换字符串)
            如果存在字符串,则拼接(不论字符串值是否数字)
            都为非字符串,则转换数字计算,失败返回NaN
    -
    *
    /
    %
    **                                          # **是指数运算符
    +
三元(目)运算符
    ?:                                          # 条件运算符, 唯一三元运算符
位运算符(对操作数每位布尔运算)
    特点
        要求操作数是整数(32位整形而非64位浮点型)
        会自动强制转换
        NaN, Infinity, -Infinity转换为0
    &                                           # 按位与
        0x1234 & 0x00FF = 0x0034
    |                                           # 按位或
        0x1234 | 0x00FF = 0x12FF
    ^                                           # 按位异或
        0xFF00 ^ oxF0F0 = 0x0FF0
    ~                                           # 按位非
        ~0x0f = 0xFFFFFFF0或 -16
    <<                                          # 左移
        7<<2 = 28
                                                # 移动倍数是0~31的整数,用0补
    >>                                          # 左边高位 正数填0, 负数填1
        7>>1 = 3
        -7>>1 = -4
    >>>                                         # 无符号右移,左边高位总填0
相等不等运算符
    ==(equality operator), ===(严格相等(strict equality)或恒等(identity operator))
        ==                                      # 数字和字符串原始类型也是地址的相等(恒等)
            null == undefined
            数字==字符串, 字符串转换为数字比较, true转换成1比较
            "1"==true    # 同时转换为数字比较
            对象根据另一个值的类型转换
        === 与 ==
            不同类型间比较,==之比较“转化成同一类型后的值”看“值”是否相等,===如果类型不同,其结果就是不等
    !=, !==是==, ===的求反
比较运算符
    <, >, <=, >=                                # 存在NaN则返回false, <=只是简单的不大于,>=相反。不进行==比较
        0 == -0
        Infinity最大(除了本身)
        -Infinity最小(除了本身)
    转换
        对象转换为数字
        同为字符串,字母表顺序比较(16位unicode字符索引顺序)
        存在不为字符串,转换数字
逻辑运算符
    ! && ||                                     # !会隐式转换为布尔类型, &&比||优先级要高, !优先级最高
    隔断性
        (a == b) && stop()                      # 同if(a == b) stop();
        var max = a || b || 0;                  # 常用。层层按优先级判断,给max赋值, 用来给可能未传入的参数赋默认值
赋值运算符
    =
    带操作的赋值运算符
        +=, -=, *=, /=, %/, <<=, >>=, >>>=, &=, |=, ^=, **=
    注意
        data[i++] *=2
        data[i++] = data[i++] * 2               # 以上不相同
逗号运算符                                       # 计算左边表达式并忽略结果, 连接多上表达式成为一个表达式
    i=0, j=1, k=2                               # 计算结果是2
    for(var i=0, j=10; i < j;j--)
扩展(spread)运算符                               # 展开具有[Symbol.iterator]接口的可遍历对象,所以可以展开字符串, Map, Set, Generator
                                                # 内部使用for of, 支持4字节字符
    [1, 2, ...arguments]                        # 展开成新数组, 等于[1, 2].concat(arguments)
    [a, ...rest] = [1, 2, 3]                    # 模式匹配给rest赋值, 只能放在最后
    array.push(1, ...items, 2)                  # 函数调用
函数绑定运算符                                    # 返回原对象, 可以链式调用a::b::c, 把b, c都绑定到a
    foo::bar                                    # bar.bind(foo)
    ::obj.foo                                   # obj.foo.bind(obj)
优先级
    优先级(js权威指南六版66页)
算术运算
    不报错
        溢出(overflow), 下溢(underflow), 被零整除
        overflow
            超过表示的数字上限, 得到Infinity或-Infinity
        underflow
            比最小值还小, 返回0或负0, 负0几乎和0一样, 很少用到
        除零
            返回无穷大或负无穷大
    返回NaN
        零除以零
        无穷除以无穷
        负数开方
        无法转换为数字

eval #

介绍
    计算由源代码组成的字符串, 用eval("")来运行
    eval()是一个函数,但设计上更像运算符。
        限制eval()函数使它更像运算符
eval()
    一个参数,如果不传入字符串,则直接返回传入的参数。
        传入字符串, 则编译该字符串
            失败则抛出语法错误异常(SyntaxError),成功则开始执行这段代码
            执行成功,返回字符串中最后一个语句的值。最后语句没有值,返回undefined
            执行中抛出异常, 该异常将调用传递给eval()[?]
    eval的作用域是当前作用域, 如eval("var y = 3;")
    用eval向函数中粘贴代码片段是无意义的,如
        var foo = function(a){eval(a)};
        foo("return;");                                             # 执行eval(a)的上下文是全局的, 会抛出return not in function错误
    eval作为单独脚本,如eval(" y = 1;")是有意义的
问题
    eval()中的代码,解释器不能分析和优化
        eval()可以改变局部变量,对优化是很大的问题
    eval()的函数名可以被赋予其他名字(与运算符的区别)
        var f = eval;
        var g = f;
        这样解释器无法优化任何调用g()的函数
            所以ECMAScript规定不可以对eval()赋予别名,会抛出EvalError异常
            实际上,大多数实现并不这么做。别名调用时, 会当作顶层全局代码来执行
            这样不会修改局部变量的值,不影响优化
    ECMAScript 5规定
        直接eval(direct eval), 总是在调用它的上下文作用域执行
        间接调用(指别名调用)则作为顶层代码执行,不能读、写、定义局部变量   # 间接eval是有用的特性,允许在局部作用域执行上下文无依赖的脚本
    ie9之前的不同
        别名调用eval()是局部调用
        用execScript()来全局eval调用                                  # 与eval不同在于总是返回null
    ECMAScript 5 严格模式
        eval作为保留字, 不能用别名覆盖(更像运算符)
        eval中的字符串以"use strict"指令开始
        可以使用和更改局部变量,不可以定义新的变量

语句 #

介绍
    语句以分号结束
    表达式计算出值,语句来执行。
        有副作用的表达式也会执行,叫作表达式语句(expression statement)
        声明语句(declaration statement), 来声明新变量或定义新函数
    js解释器依照语句编写顺序执行
        控制结构(control structure)改变顺序
            条件conditional
                switch
            循环loop
                while, for
            跳转jump
                break, return, throw
表达式语句
    赋值语句,如 greeting = "Hello" + name;
    ++, --
    delete
    函数调用,如 alert(greeting);                 # Math.cos(x)不是表达式语句,它没有对浏览器造成影响
复合语句和空语句
    {}括起来当作单独语句
        内部语句必须分号
        内部声明的变量作用域在外部(es6之前)
        如
            {
                x = Math.PI;
                cx = Math.cos(x);
            }
    空语句
        ;
        如
            if(){....}
            if();
块作用域(es6之后)                                 # 内部使用严格模式
    {
    }
声明语句
    特点
        声明语句创建的变量无法删除,但不是只读的,可以重写
        函数声明常出现在代码最顶层
        函数声明并没有归类为真正的语句
        函数声明不能出现在if, while等语句中
    var, function
    如
        var f = function(){}                    # 变量名指向函数对象,声明提前。初始化要在执行到时进行, 不可以在代码之前调用
        function f(){}                          # 函数声明和定义均提前,可以在代码之前调用
条件语句
    if(expression1) statement1
        else if(expression2) statement2
        else statement3
    switch(expression){ statements}
        特点
            不重复计算表达式
            无break向下执行,如c语言
            ECMAScript规定case可跟随任意表达式
                case是恒等比较, 所以不会作类型转换
                case是运行时(run-time)计算的, 灵活但效率低。
                c, c++, java中case是编译时(compile-time)常量
            编译时常量形成跳转表(jump table), 执行非常高效
            避免使用函数表达式和赋值表达式,建议常量表达式
            default标签可以在switch语句内的任何地方
        switch(typeof x){
            case 'number': break;
            default: break;
        }
    while(expression) statement
    do statement while(expression);             # 代码至少执行一次
    for(initialize; test; increment) statement                      # for(;;)比while(true)高效
    for(variable in object)                     # 遍历对象属性成员, 遍历出的数组key(如0, 1, 2)是字符串
        for(a[i++] in o)
        for(i in [1,2,3])
        原理
            计算object表达式
                为null或undefined 则跳过         # ECMAScript3的实现可能会抛出一个类型错误异常
                为原始值, 则包装对象
                否则就一定是对象,枚举对象属性(或数组索引)
                    只有可枚举(enumerable)属性才会遍历到
                        代码中所有属性和方法可枚举
                        ECMAScript 5可以特殊手段变为不可枚举
                        js语言核心定义的内置方法不可枚举(nonenumerable),如toString()
                        很多内置属性不可枚举
                        继承的自定义属性也可以枚举出来
                    prototype上有多个原型(原型链上多个对象), 每个都遍历
                    for/in中提前删除的未枚举属性不会枚举到
                        定义的新属性不会枚举到(有些实现是可以枚举到的)
                    每次循环计算variable表达式的值,以它为左值赋值
        顺序
            通常实现按照定义先后顺序
            原型链多继承对象有特定顺序
            数组依照数字顺序                    # 不是全部实现, 索引非数字或不连续时,按照特定顺序
    for(let c of s)                           # 会正确识别4字节字符
跳转语句(jump statement)
    break, continue, return, throw            # throw是复杂的跳转语句,跳转到最近闭合异常处理程序, 处理程序可以在同函数中或高层调用栈中
标签语句
    identifier: statement
        identifier不能是保留字。与变量或函数命名空间不同,可以使用同一个标识符作标签和函数名
        外层语句标签不能和它内部的重名。不嵌套下是可重名的
        break, continue是唯一可以使用语句标签的语句
    mainloop: while(token != null){
        continue mainloop;
        // break mainloop;
    }
break语句
    特点
        break后面无内容自动补分号
        不可以跳出函数边界,只在一个函数中起作用
        for中不会计算自增表达式, 直接退出
    break;
    break labelname;
continue语句
    特点
        continue后面无内容自动补分号
        while中跳到开头检测expression, do/while跳到结尾
        for中先计算自增表达式,再检测expression, for/in中遍历下一个属性名,赋给变量
    continue;
    continue labelname;
return语句
    特点
        return后面无内容自动补分号
        函数调用是表达式,return返回函数表达式的值并跳过后续结果。无return时, 函数表达式结果为undefined
        只在函数中出现
throw语句
    特点
        js解释器立即停止当前执行的逻辑,并跳转到就近异常处理程序
        try/catch/finally语句的catch编写异常处理程序
        没有异常处理程序, js把异常当作程序错误处理,报告给用户
    throw expression;
    throw new Error('x不能是负数');              # Error对象, name属性表示错误类型, message属性存放传递给构造函数的错误信息
try/catch/finally语句                           # catch可选, finally可选, try finally一起, finally用于清理代码
    finally中常写的逻辑                          # finally中return, continue, break, throw跳转,忽略已有返回值或异常,以finally中的为准
        o-> 正常终止, 收尾语句
        o-> break, continue或return终止
        o-> 抛出异常,被catch捕获。抛出异常未被捕获, 继续向上传播
    模拟for(initialize; test; increment)body;
    initialize;
    while(test){
        try{body;}                              # body中有break时, 这里相比for循环有一次额外的自增运算, 所以while不能完全模拟for
        finally{increment;}
    }
with语句
    with(object) statement
    with语句用于临时扩展作用域链, 将对象添加到作用域链的头部
    with下创建未声明变量不会添加到with对应对象作属性,而是和平时一样
        with执行完后把作用域链恢复到原始状态
        作用域链(scope chain)
            按序检索的对象列表, 通过它进行变量名解析
        严格模式下禁止使用with语句。非严格模式不擒获with, 因为运行慢且非常难于优化
            对象嵌套层很深时使用with来简化代码编写
debugger语句
    debugger;                                   # 产生一个断点(breakpoint),在解释器调试模式运行时使用
                                                # ECMAScript 5中加入的debugger语句。但从前主流浏览器已经实现了
"use strict"指令
    只出现在代码或函数体的开始或eval()中。其前可以有其字符串直接量表达式语句
        解释器可能将"use strict"之前的字符串和它都解释成解释器自有的指令
        直到第一条常规语句出现之后, 字符串直接量就只当作普通表达式语句对待
    表示其后的代码将会解析为严格代码
        函数和eval()只作用到自身
    ECMAScript 5引入的指令。可以使用单引号。对于没有实现ECMAScript 5的解释器来说,它什么也不做(没有副作用)
        将来ECMAScript希望用use做关键字
tag函数                                         # 用于过滤html字符串, 嵌入其他语言执行或filter出特定的值
    tag`hello ${1} world ${2}`
    function tag(strArr, ...values){}           # ['hello ', ' world ', ''] , 1, 2
数组推导                                        # 支持iterator接口, 即也支持字符串。惰性求值, 可以替代filter方法
    var a1 = [1, 2, 3]
    var a2 = [for (i of a1) i * 2]
    var a3 = [for (i of a1) if(i < 3) i]
    var b1 = [1, 2]
    var b2 = ['a', 'b']
    [for (s of b1) for (w of b2) s+w]    // ['1a', '1b', '2a', '2b']
    let c = (for (n of generator()) n * n)

模式匹配 #

特点
    模式匹配只对自身属性起作用

数组
    let [foo, [[bar], baz]] = [1, [[2], 3]]     # var, const同样适用
    let [,, third] = [1, 2, 3]
    let [head, ...tail] = [1, 2, 3]
    let [x, y, z] = new Set(['a', 'b', 'c'])    # 只要有Iterator接口,都可以匹配

    var [foo = true] = []                       # 设置默认值,在值严格等于undefined时生效
        var [x = 1] = [undefined]
            x = 1
        var [x = 1] = [null]
            x = null
        let [x = f()] = [1]                     # 惰性求值
        let [x = y, y = 1]                      # 报错, y 未声明

对象
    var {bar, foo} = {foo: 'a', bar: 'b'};
    var {foo: baz} = {foo: 'a'};                # baz = 'a'
    var {p: [x, {y}]} = {p: ['a', {'b'}]}       # 这里p是模式,不是变量,所以不声明或赋值
    let obj = {}, arr = [];
    ({foo: obj.prop, bar: arr[0]} = {foo: 1, bar: 0});              # 嵌套值, 不加()时{}会被解释成代码块
    var {x = 3} = {};
    let {log, sin, cos} = Math                  # 将对象的方法赋值到变量
    let n = {...{a: 3, b: 4}}                   # {a: 3, b: 4}, 扩展null, undefined会被忽略, 被扩展对象中的getter会执行
        let n = {x: 1, ...a}                    # a中的x属性会被覆盖掉, 原理同Object.assign
        let {x, y, ...z} = {x: 1, y: 2, a: 3, b: 4}                 # x // 1, y // 2, z // {a: 3, b: 4}, z 是引用
基本类型
    const [a, b] = 'hello'
    let {toString: s} = 123                     # 如果右边不是对象,先包装, null 和 undefined不能匹配
        # let {toString: s} = true

函数
    function add([x, y]){}
    add([1, 2])
    function move({x = 0, y = 0} = {})          # function move({x, y} = {x: 0, y: 0}) 是错误的

圆括号
    [(b)] = [3]
    ({p: (d)} = {})
    [(parseInt.prop)] = [3]                     # 只有非声明语句的非模式部分可以用圆括号

用途
    [x, y] = [y, x]                             # 交换值
    function f(){return [1, 2]}
    var [a, b] = f();
    function f(){return {foo: 1, bar: 2}}
    var {foo, bar} = f();                       # 函数返回多个值
    function f([x, y]){}
    f([1, 2])
    function f({x, y, z = 3}){}
    f({y: 2, x: 1})                             # 参数定义
    let {id} = {id: 42, status: 'ok'}           # json匹配
    var map = new Map(); map.set('a', 1)
    for(let [, val] of map){}                   # 遍历map
    const {SourceMapConsumer, SourceNode} = require('source-map')   # 输入模块方法

函数 #

特点
    js的函数是参数化的
        在js中,函数即对象,可以随意传递,可以设置属性和调用该函数的函数
        在js中,函数可以嵌套定义, 嵌套的函数可以访问被定义所处作域中的变量,这个作用域就是闭包(closure)
        函数是对象,但typeof经过处理,所以返回"function", 可以拥有静态属性和方法,可以用内部构造函数Function()创建
    形参 标识符列表(函数中定义的变量),调用时为其提供实参值。
    初始化对象的函数是构造函数
    return停止函数执行并返回它的表达式。没有表达式时返回undefined。没有return语句时返回undefined
    this是关键字,不是变量或属性名,所以不允许赋值。
        this没有作用域限制
    将函数绑定到Function.prototype上,以便所有函数对象都继承它
关键字
    this
        除实参外,每次调用拥有一个调用上下文 this
        对象调用函数时, 此次调用上下文是该对象。
    super
        super()调用父类的构造方法, super相当与父类的实例,super同时部署了父类的静态属性
        对象总是继承其他对象,所以在任意对象中,都可以使用super, 如
            var obj = {toString() {return 'a ' + super.toString() }}
    new.target
        构造函数中使用, 返回调用该构造函数时new 命令作用的对象
        如果直接调用等, 则值为undefined
        function Person() {new.target === Person}
        class {constructor() {new.target}}                          # 子类继承父类调用super()时, 父类构造方法中new.target指向子类, 可以利用写出不能继承的类
定义                                              # 函数名通常是动词或以动词为前缀的词组,常用的写短
    function a(){}
        声明和定义均提前
        ECMA只允许它作为顶级语句,不能出现在循环、条件判断或者try/cache/finally及with语句中
            一些js实现并未严格遵守规则,比如firefox就可以在if中出现函数声明
    var a = function(){}
        只声明提前。可作匿名函数
        此为函数定义表达式, 可以出现在js代码的任何地方
    o.m = f
        给已有对象的属性引用方法
创建函数
    function fun(){}
    var fun = function {}
    var fun = new Function("输入变量1","输入变量2","执行内容");        # 动态创建函数

    var f = (a, b) => a + b
    var f = n => n
    var f = () => {return 1}
    var f = () => ({a: 1})
    箭头函数特性:
        没有自己的this, this是外部的this, 所以不能用call, apply, bind改变this
        不能当作构造函数, 没有super, new.target
        没有arguments, arguments是外部的
        不能成为Generator
        大括号解释为代码块, 要返回对象时用圆括号括起来
        const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val)
        const plus1 = a => a + 1, mult2 = a => a * 2, addThenMult = pipeline(plus1, mult2);
        addThenMult(5)    // 12
        let insert = val => ({into: (arr) => ({after: (afterVal) => {
            arr.splice(arr.indexOf(afterVal) + 1, 0, val); return arr;
        }})})
        insert(2).into([1, 3]).after(1)    // [1, 2, 3]
参数
    function f(x, y = 5)
        f({x: 1, y: 2})可以模式匹配
        默认值可以是变量,作用域是函数内作用域。函数a默认值是函数b时, 函数b的作用域链不包含函数a
        默认值一般在最后, 可以一眼看出哪些参数可以省略,调用时也好看
    function f(url, {method = 'GET'} = {})
    function f({a, b}) {a, b}
        f({a: 1, b: 2}) 对象匹配
    function f(a = throwErr())
        设置不可省略的参数, 默认值是延迟计算的
    function f(...rest)
        一定在末尾
嵌套函数
    特性    
        内部嵌套函数可以读写外部参数
        this不会在嵌套函数中继承,函数调用和方法调用中this的规则不变。
            如果要在内部访问外部this, 需要将外部this保存到变量中(通常用self, [that 是传递this时使用的变量名])
调用
    方式
        作为函数
        作为方法
        作为构造函数
        通过它们的call()和apply()方法间接调用
    原理
        调用由函数对象,左圆括号,参数列表(逗号分隔),右圆括号组成
        每个参数表达式都会计算出一个值作为实参传递给声明时定义的形参
            在函数体中存在一个形参的引用指向当前传入的实参列表
        函数表达式的值成为调用表达式的值
        ECMAScritp 3和非严格ECMAScript 5中,函数调用上下文(this)是全局对象。严格模式下是undefined
            常用this判断是否严格模式
    调用表达式
        f()                                     # 作为普通函数调用
        o.m(x, y)                               # 函数表达式本身就是属性访问表达式, 此时函数作为一个方法调用, 方法调用的上下文是该调用对象o
        o["m"](x, y)
        a[0](z)                                 # 可以用方括号来方法调用
        a.b.c()
        f().m()                                 # 方法链, 链式调用, 返回this或构造对象
构造函数调用
    方法名前带有new, 就是构造函数的调用
    与普通的函数调用及方法调用在实参处理、调用上下文、返回值方面都不同
    定义一类(class)对象,创建对象继承构造函数的prototype属性
        class看作是对象类型的子类型
    使用新对象作为调用上下文, 如new o.m()中,this不是o
    如果return一个对象,则构造的就是这个对象,如果返回原始值或没有值,则忽略返回值
    原理
        计算实参表达式,传入函数内。没有形参,允许省略实参列表和圆括号,如
            var o = new Object()                # 无参时圆括号可以省略
        创建空对象,继承构造函数的prototype, 试图初始化该对象,并将该对象作为调用上下文
            尽管构造函数看起来像方法调用,但它用新对象作为调用上下文
            所以 new o.m()看起来是方法调用,但它的调用上下文并不是o
        通常不使用return关键字,显式返回构造的新对象
            显式使用return时,如果没有值或是原始值,就忽略return。如果是对象,就返回return的对象
间接调用
    call和apply
        可以显式指定调用上下文,这样任何函数都可以作为任何对象的方法来调用
        call使用自有的实参列表作为函数实参,apply以数组形式传入参数
实参和形参
    不检查传入的参数类型和参数个数,所以要手动做参数检查
        传入参数少时,剩下的形参都设置为undefined
            所以在参数检查时,要给省略的参数赋默认值。如 a = a || []
            a = a || [] 是习惯用法,用来代替if语句,前提是a必须预先声明
        前面的参数可选且不传时,传入占位符null(也可以传undefined)
        函数定义中使用/*optional*/来强调形参可选, 如
            function f(o, /*optional*/ a)
    可变长实参列表(实参对象)
        arguments
            是类数组对象,可以通过数字下标访问传入的实参值
            这种可以接收任意个数实参的函数    称为 不定实参函数(varargs function)
            非严格模式下, 实参对象的数组元素是函数形参对应实参的别名,改变实参值时,实参对象中的值也改变
                ECMAScript 5中移除了别名这个特性(实测没有移除)
            非严格模式中, arguments是一个标识符,严格模式中,它是一个保留字
            arguments的callee和caller属性
                ECMAScript 5 严格模式中,对这两个属性的读写操作都会产生类型错误
            非严格模式中, callee指代当前正在执行的函数,caller是非标准的,但大多数浏览器都实现了这个属性,指代调用callee的函数。
                通过caller属性可以访问调用栈
            可通过callee递归调用自身
                var factorial = function(x){
                    if( x <= 1) return 1;
                    return x * arguments.callee(x-1)
                }
    对象属性作实参,如
        easycopy({from: a, to: b, length: 4})
        function easycopy(args){
            args.from;
            args.from_start || 0;
        }
    类型注释
        function max(/*number*/a, /*optional*/b, /*array*/c, /*integer*/d, /*index*/e){
            if(isArrayLike(c)){
                if(isFinite(a));
            }
        }
函数作为值
    function a(){}                              # 定义创建函数对象,赋值给a。函数对象的名字是看不见
    o.f = f                                     # 将函数赋值给对象的属性,就称为方法
    var a = [function() {}, 20]                 # 没有名字的函数,放在数组直接量中
函数的自定义属性
    如当函数需要专属常量时,可在上面定义静态属性
    如要求函数返回唯一整数,可以定义静态属性做个计数器,
    如果要做缓存,也可以定义多个静态属性来缓存返回过的结果,属性名就是传入过的值
作命名空间
    无法声明只在一个代码块中可见的变量。所以定义一个函数做临时命名空间
    有些js扩展中(如mozilla的java script 1.7)可以使用let声明语句块内的变量, 如
        let(x = 1){ print(x)}
    (function(){
    }());
        匿名函数不会定义全局函数变量并运行, 定义了内部的局部变量
        最外层圆括号是习惯写法,尽管有些时候没必要也不应当省略
闭包
    js采用词法作用域(lexical scoping), 函数的执行依赖变量作用域。作用域在函数定义时决定,而非调用时
        当前函数的变量保存在函数作用域内(闭包)
        闭包指函数变量可以被隐藏于作用域链之内,象是函数将变量"包裹"了起来
    每函数中引入当前作用域链
    定义时与运行时
        大多定义函数时的作用域链在调用函数时依然有效
        调用函数时与定义函数时作用域链不是同一个时
            如返回内部嵌套的函数a时,外部运行a,其作用域链仍然是a的作用域链而非外部作用域链
    作用
        捕捉局部变量并一直保存
    原理
        如果一个函数的局部变量定义在cpu栈中, 函数返回时它们的确不存在了
        js中作用域链是一个对象列表,不是绑定的栈。
            运行js函数a时, 都创建新的对象保存局部变量。该新对象添加到作用域链中
                函数a返回时,从作用域链中删除该局部变量对象,等待垃圾回收
                如果a有嵌套函数,每个嵌套函数各自对应一个作用域链         # 该嵌套函数的作用域链,保留a的局部变量对象
                    嵌套函数在a中局部变量对象中保存时,会随其一起从作用域链删除
                    嵌套函数被返回或被外部引用时, 该嵌套函数不被回收,且其自身作用域链中的自身局部变量对象、a的局部变量对象也不删除。
        闭包的this值会随外部调用者而变动,所以要先将this转存。var self = this;
            闭包中使用的arguments也会变动,也要转存。var outerArguments = arguments;
可调用对象
    如"类数组对象"不是真正的数组,"可调用对象"不是函数,但所有函数都是可调用的
    可调用对象使用越来越少
    例如
        ie8及之前的版本window.alert()和document.getElementById()使用了可调用的宿主对象
        RegExp对象可以直接调用(如RegExp()), 是非标准特性, Netscape提出后被后续浏览器兼容
            typeof RegExp可能是"function"也可以是"object"
            最好不要对可调用RegExp对象有太多依赖,其可调用特性将来可能被删除

generator #

基本
    generator生成的遍历器g, g[Symbol.iterator]()得到自己。继承它prototype上的方法
        generator中this添加的属性, 生成的遍历器实例中没有, generator new相当于执行得到遍历器
        g.bind(obj) 可以改变generator中的this
    作为对象属性时写做 {* g() {}}, {g: function* () {}}
应用
    状态机
    协程(coroutine)
        generator是半协程(semi-coroutine), 只有generator函数的调用者,才能改变程序运行状态
        将多个协作的任务写成generator, 用yield语句交换控制权
    异步程序同步写法
    部署iterator接口
    可看作数组结构
yield
    特点
        惰性求值
        在表达式中时加圆括号, 如'hello' + (yield 1),字符串模板中`${yield}`
        var n = yield i; g.next(1) 来返回值给n, g.next()返回undefined
        第一次调用g.next()不能传值,因为执行第一个yield之前的代码, 还没有yield来接收
    var a = yield* g()
        展开g()得到的generator(可展开所有iterator), 是for ... of的一种简写形式
        g()中有return 时, a 得到return 的值
    yield [a(), b()]
        非展开,而是并列执行, 全部执行返回时返回
throw
    特点
        外部的throw语句只被外部捕获
        generator中throw的错误先内部捕获,再抛出, g.throw(1)相当于从内部yield处抛出一个错误
        generator抛出错误后不再能继续执行,再执行返回done=true
    var g = function* () {try {yield;} catch (e) {}}                # 可以多个yield一个try catch ,  而回调函数只能一个回调一个try catch
    var i = g(); i.next()
    try{i.throw('a'); i.throw('b') } catch(e){}                     # 内部捕获a, 外部捕获b
return
    特点
        相当于强制内部return
        generator中有finally时, g.return()延迟到所有finally执行后执行,再结束
    g.return(0)    // {value: 0, done: true}
使用
    function* f () {
        yield 1; yield 2; return 3;
    }
    var ff = f(), ff.next()
        # {value: 1, done: false}, {value: 2, done: false}, {value: 3, done: true}, {value: undefined, done: true}
        ## 没有return语句时, 去掉第三个结果,其它不变
自动执行                                    # 写执行器处理thunk和promise
    非promise
        thunk函数, 把回调函数抽离出来

promise #

三种状态
    进行中(pending)
    完成(fulfilled)
    失败(rejected)
状态转换
    状态可以由pending转换成fulfilled,或pending转换成rejected
    promise的状态转换只发生一次,之后代码会执行,但抛出的错误不捕获
    p2中return p1, 则p1的状态决定了p2的状态, 如果p1是resolved或reject, p2的回调立即执行
    所以返回promise对象时, then的回调相当于返回promise的then的回调
    新建即执行,不能取消。内部错误不抛出。无法得到具体pending状态

async #

特点
    generator的语法糖, 自动执行generator, 处理promise
    内置执行器,返回promise对象
使用
    var asyncReadFile = async function () {
        try {
            var f1 = await readFile('/etc/fstab');
        } catch (e) {}
        await p2.catch(function (e) {})
    }

class #

特点
    所有方法在prototype上(constructor, static外),不可枚举
    无变量提升
    类内部即严格模式
    class A的A.name = 'A', 意义同函数名

语法
    class Point {
        constructor(x, y) {                         # 不定义时,生成空constructor方法, this代表新生的实例
            this.x = x, this.y = y;
        }
        toString() {return 'a'}
        [methodName]() {}
        get prop() {...}
        set prop(val) {}
        * [Symbol.iterator]() {}
        static sMethod() {}                         # 相当于直接在Point上定义, es6 内只有方法,没有属性
        prop: 1                                     # es6中忽略, es7提案
        static prop2: 2                             # es6中忽略 es7提案
    }
    Point.a = 1;                                    # es6 静态属性只能在class外部定义
    var point = new Point(2, 3);

    o->
    var A = class B{};                              # 这时类的名字是A, 而B只能在类内中指代自己
    var A = class {};
    var a = new class {}();

继承
    两条原型链
        Object.setPrototypeOf(B.prototype, A.prototype)
        B.prototype.__proto__ = A.prototype         # 作为构造函数, 子类B的prototype是A的实例
        Object.setPrototypeOf(B, A)
        B.__proto__ = A                             # 作为一个对象, 子类B的原型是A(强行成为继承关系来得到A的静态属性)
        B.__proto__.__proto__ = A.__proto__,        # 子类原型的原型是父类的原型
    继承的特殊种类
        class A {}, A.__proto__ = Function.prototype, A.prototype.__proto__ = Object.prototype
        class A extends null {}, A.__proto__ = Function.prototype, A.prototype.__proto__ = undefined

    o->
    class A extends B {
        constructor(x, y, color) {                  # 默认construcotr为constructor(...args) {super(...args)};
            super(x, y);                            # 调用B的constructor, 必须调用super来创建父类对象作用自己的prototype, 否则整个继承失败,报错
            this.color = color                      # this必须在super调用之后才能使用, 否则没有prototype生成this, 报错
        }
    }
    let cp = new A(1, 2, 'a')
    cp instanceof A    // true
    cp instanceof B    // true

    o-> 继承原生构造函数(es5不可以)
        es5机制决定先新建子类实例this, 再将父类属性添加到子类上。父类的内部属性无法获取(如Array的[[DefineOwnProperty]])。
        es6允许继承原生父类构造函数定义子类, 即先新建父类this, 再用子类修饰, 父类的所有行为都可继承
    function MyArray() {Array.apply(this, arguments)}
    MyArray.prototype = Object.create(Array.prototype, {constructor: {
        value: MyArray,
        writable: true,
        configurable: true,
        enumerable: true,
    }})
    class MyArray extends Array {
        constructor(... args) {
        super(... args);
        }
    }

    o-> 用mixin来混合继承
    class A extends mix(B, C)

decorator #

介绍
    编译时执行
    相当于 class A {}, A = decorator(A) || A;
    不能用于函数,因为函数提升?

o-> 修饰类
function testable(target) {                         # target是被修饰的类, 参数2为属性名, 参数3为属性描述对象
    target.isTestable = true;
}
function testable(val) {
    return function(target) {
        target.isTestable = val;
    }
}
@testable
class A {}
A.isTestable    // true

o-> 修饰类属性
function readonly(target, name, descriptor) {
    descriptor.writable = false;
    return descriptor;
}
class Person {
    @readonly
    name() {return 0}
}

对象 #

基础
    一种复合值。属性的无序集合,属性由名/值对组成,看作字符串到值的映射。
        这种数据结构叫做散列(hash), 散列表(hashtable), 字典(dictionary), 关联数组(associative array)
        常用来模拟静态对象或静态语言的结构体。也可以模拟json字符串
    可以基于原型(prototype)继承属性,称作原型式继承(prototypal inheritance)
    除了字符串、数字、true、false、null、undefined外,js中的值都是对象
        字符串、数字、布尔值可以自动包装为对象(构造函数的实例)
    对象操作通过引用(而非值)。
    常见属性操作
        创建(create)
        设置(set)
        查找(query)
        删除(delete)
        检测(test)
        枚举(enumerate)
组成
    属性的名/值对 + 属性特性(property attribute) + 对象特性(object attribute)
            属性名可以是空字符串,不能重名
        属性特性包括: 可写(writable attribute), 可枚举(enumerable attribute), 可配置(configurable attribute)
            可配置表明是否可以删除或修改该属性
            通过代码给对象创建的所有属性都是可写、可枚举、可配置的, ECMAScript 5 中可以改变
        对象特性包括
            对象原型(prototype)                     # 指向另外一个对象, 本对象继承它的原型
            对象的类(class)                         # 一个标识对象类型的字符串
            对象的扩展标记(extensible flag)          # ECMAScript 5中指明是否可以向该对象添加新属性
分类
    内置对象(native object)                         # 由ECMAScript定义的对象或类。如数组、函数、日期、正则表达式
    宿主对象(host object)                           # js解释器( 如web浏览器)嵌入的宿主环境,如 HTMLElement对象
                                                   # 宿主环境定义的方法可当作普通js函数对象, 宿主对象可当作内置对象
    自定义对象(user-defined object)                  # 运行中的js代码创建的对象
    自有属性(own property)                          # 直接在对象中定义的属性
    继承属性(inherited property)                    # 对象的原型对象中定义的属性
原型
    每一个js对象(null除外)都与另一个对象(原型)关联,从原型继承属性。
    内容
        对象直接量创建的对象有同一个原型对象Object.prototype
        new的对象原型是构造函数prototype的属性的值     # 于是new Object()创建的对象继承自Object.prototype
        Object.prototype这个对象没有原型
        具体
            除Object.prototype的对象是普通对象,都有原型。
            所有内置构造函数都继承Object.prototype
                如, new Date()创建的对象同时继承Date.prototype和Object.prototype
                这一系列的链接的原型对象就是"原型链"(prototype chain)
创建对象
    {}
        ECMAScript 5中(ECMAScript3的部分实现), 保留字用作属性名可以不带引号
            ECMAScript 3中保留字作属性名必须用引号
        ECMAScript 3的IE中, 最后一个逗号不可以忽略
        每次计算对象直接量,都会计算它的每个属性的值
    new            # 关键字创建
        new后的函数是构造函数(constructor)。
    Object.create()
        ECMAScript 5中出现的静态函数
        参数1是原型对象, 参数2可选,对对象属性进一步描述

        Object.create({x:2})
        Object.create(null)
            传入参数null来创建没有原型的新对象。
            没有原型的对象没有toString等方法, 所有不能+运算
        Object.create(Object.prototype)
            创建普通对象
对象序列化(serialization)                            # json(JavaScript Object Notation)
    ECMAScript 5 api                                # stringify, parse的第二个参数可选,传入属性列表来定制序列化或还原操作
        JSON.stringify()
            支持对象, 数组, 字符串, 无穷大数字, true, false, null。NaN, Infinity, -Infinity序列化结果是null
                日期stringify为日期字符串,parse不能还原成对象
                只序列化对象的可枚举自有属性。不能序列化的属性自动省略掉
            函数, RegExp, Error对象和undefined不能序列化和还原
        JSON.parse()
创建对象                                            # 函数即对象,本身为构造方法
    var obj = {};                                  # var obj = []是数组, 数组中Obj['aa']添加的是属性而非成员, 静态对象
    function Obj(a, b){};
        new Obj(a, b);
    function Obj(a, b){
        thisf = new Array();
        return new Object(a, b)
    };            
        Obj(a, b);
            只能返回Obj里定义的新对象的实例(不能返回本身的实例)
            内的变量函数静态。指向外部函数可动态
            内对象为动态
        new Obj(a, b);                              # 内变量函数动态(内存浪费)
        Obj.prototype.c = 'c'
        Obj.prototype.d = function(){};
        Obj.prototype.e = new Array();              # prototype函数为静态函数, prototype对象为静态
    function Obj(a, b){ }                           # 内部prototype, 与外部完全相同
        if(typeof Obj._initialized == 'undefined'){
            Obj.prototype.c = function(){};
            Obj._initialized = true;
        }
    最好方式:
        内部定义变量和对象, prototype定义函数(防止new对象的函数动态)。
        prototype定义函数可以在内部,也可以在外部。
    扩展对象
        Obj.prototype.extend                        # 添加或重写当前对象的属性
        Object.prototype.extend                     # 所有对象上添加属性

属性 #

查询和设置
    . []
        ECMAScript 3中, 点运算符后的标识符不能是保留字。ECMAScript5(包括ECMAScript3的某些实现)中可以
        []中必须返回可以转换为字符串的值
        []的写法用了字符串索引,叫做关系数组(associative array), 散列或字典
    属性不存在时自动创建
描述对象
    value
    writable                                        # 可修改
    enumerable                                      # 可枚举性
        for...in, Object.keys(), JSON.stringify(), Object.assign(), Reflect.enumerate()会忽略不可枚举属性
        for...in等价Reflect.enumerate(), 会返回继承的属性
    configurable                                    # 可配置
遍历属性                                             # 先遍历属性名是数值的属性,再遍历字符串,再遍历Symbol
    for ... in                                      # 自身和继承的可枚举属性
    Object.keys                                     # 自身的可枚举属性(不含Symbol)
    Object.getOwnPropertyNames                      # 自身所有属性(不含Symbol)
    Object.getOwnPropertySymbols                    # 自身所有Symbol属性
    Reflect.ownKeys                                 # 自身所有属性
    Reflect.enumerate                               # 同for ... in
访问错误
    查询不存在的属性不报错, 返回undefined
    对象不存在,会查询null和undefined的属性,会报错
        建议写法: var len = book && book.subtitle && book.subtitle.length
    只读的设置不报错,如                              # ECMAScript 5的严格模式中会报错
        Object.prototype = 0;        
设置属性失败的情况
    o中属性p是只读的                                  # defineProperty()可以
    o中属性p是继承属性,且它是只读的
    o没有属性p, o没有使用p的setter方法, o可扩展性为false
删除属性
    delete
        删除成功,属性不存在,不是属性访问表达式时,返回true
        属性可配置性为false,非严格模式下返回false, 严格模式下抛出异常
        全局对象可以不用属性访问表达式, 如 delete x;
            严格模式下, delete x; 会报语法错误, 必须delete this.x
        只是断开联系
        只删除自有属性,不能删除继承属性
            继承属性可以从原型对象上删除它
            a = {p:{x:1}}; b= a.p; delete a.p; 执行后p.x还是1。因为属性的引用依然存在
                会内存泄漏,所以在销毁对象时,要遍历属性中的属性,依次删除
检测属性
    in                                              # 检测自有属性和继承属性
        "x" in o;
    o.x !== undefined                               # 同in,但没法区分属性的值为undefined时的属性,in可以
                                                    # !==可以区分null和undefined, 所以用!==
    hasOwnProperty()                                # 只检测自有属性
        o.hasOwnProperty("x");
    propertyIsEnumerable()                          # 自有属性且可枚举
        o.propertyIsEnumerable("x")
枚举属性                                             # ECMAScript 3 的不可枚举属性不能得到
    for/in
        ECMAScript 5之前, 工具库给Object.prototype添加的属性必须可枚举
        所以for/in会枚举出来,要用hasOwnProperty(p)来过滤
    Object.keys()                                   # ECMAScript 5中定义,返回可枚举的自有属性名数组
    Object.getOwnPropertyNames()                    # ECMAScript 5中定义,返回自有属性名数组
getter和setter
    通常用来表示同一组数据的两种方法(如笛卡尔坐标系表示法和极坐标系表示法)
        也用于检测属性的写入和读取值
    ECMAScript 5中属性值可以用方法替代,就是getter和setter, 叫做存取器属性(accessor property)
        是访问描述符,相对数据描述符(如writable)
        普通的属性叫做数据属性(data property), 只有一个简单的值
        存取器属性不具有可写性(writable attribute)
        作为替代, 只有getter, 则只读。只有setter, 则只写。同时拥有, 则可读写
            读取只写属性总是返回undefined
        存取器属性是可以继承的
    定义
        var o = {
            data_prop: 1,
            get accessor_prop(){},                  # 函数中的this表示当前对象o
            set accessor_prop(value){}
        };
        var descriptor = Object.getOwnPropertyDescriptor(o, 'accessor_prop');
        'get' in descriptor    // true
        'set' in descriptor    // true
    例子
        var p = {
            $x: 1.0, 
            $y: 1.0,
            get r () {return Math.sqrt(this.x * this.x + this.y * this.y);},
            set r (newvalue) {
                var oldvalue = Math.sqrt(this.x * this.x + this.y * this.y);
                var ratio = newvalue/oldvalue;
                this.x *= ratio;
                this.y *= ratio;
            },
            get theta () {return Math.atan2(this.y, this.x); }
        }
    例子
        var serialnum = {                           # 序列
            $n: 0,                                  # $暗示私有属性
            get next(){return this.$n++;},
            set next(n){
                if(n >= this.$n) this.$n = n;
                else throw "序列号的值不能比当前值小";
            }
        }
    例子2
        var random = {                              # 返回不同数量范围的随机数
            get octet(){ return Math.floor(Math.random() * 256)},
            get uint16(){ return Math.floor(Math.random() * 65536)},
            get int16(){ return Math.floor(Math.random() * 65536) - 32768}
        };
属性的特性                                           # ECMAScrit 3这些特性不可以配置, ECMAScript 5中提供查询和设置的api
    作用
        给原型对象添加方法,设置该方法为不可枚举,看起来像内置方法
        给普通对象定义不能修改或删除的属性,实现"锁定"
    组成
        值(value), 可写性(writable)、可枚举性(enumerable)、可配置性(configurable)
            存取器特性是读取(get)、写入(set)、可枚举性、可配置性
    原理
        ECMAScript 5定义了 属性描述符(property descriptor)对象, 代表4个特性
            该对象的属性有value, writable, enumerable, configurable, 代表4个特性
            存取器属性描述符用get和set代替value和writable
                writable, enumerable, configurable是布尔值
                get和set是函数值, value什么都可以
    调用                                             # 新建属性的默认特性对象为false或undefined
        Object.getOwnPropertyDescriptor(o, p)
            获得对象o的p自有属性的 属性描述符对象
            要得到继承属性的特性, 要遍历原型链
        Object.defineProperty(o, "x", {             # 新建或修改自有属性的特性, 传入对象和属性名与属性描述符对象
            value: 1,
            writable: true,
            enumerable: false,
            configurable: true
        });
        Object.defineProperty(o, "x", {get: function(){ return 0; }});
            修改x为存取器属性
                返回修改后的对象
            不允许创建或修改的属性,抛出类型错误异常
                规则(违反则抛异常)
                    对象不可扩展,可以编辑已有属性, 不能添加
                    属性不可配置, 不能修改可配置性和可枚举性
                    存取器属性不可配置, 不能修改getter, setter方法, 不能转换为数据属性
                    数据属性不可配置,不能转换在存取器属性
                    数据属性不可配置,不能可写性从false修改为true
                    数据属性不可配置且不可写, 不能修改值。可配置但不可写时可以修改值
                        实际上自动标记为可写,再改值,再转换为可写
        Object.defineProperties({}, {
            x: {value: 1, writable: true, enumerable: true, configurable: true},
            y: {value: 1, writable: true, enumerable:true, configurable:true},
            r: {
                get: function(){return Math.sqrt(this.x * this.x + this.y * this.y)},
                enumerable: true,
                configurable: true
            }
        })
            新建或修改多个属性及特性。第一个参数是修改对象,第二个参数是映射表
                返回修改后的对象
            不允许创建或修改的属性,抛出类型错误异常
    老式api(ECMAScript 5之前,非IE浏览器)
        __lookupGetter__()
        __lookupSetter__()                              # 返回一个属性的getter和setter
        __defineGetter__()
        __defineSetter__()                              # 定义getter和setter, 第一个参数是属性名, 第二个参数是getter或setter方法
对象三个属性
    包括
        原型(prototype)
        类(class)
        可扩展性(extensible attribute)
    原型
        api
            Object.getPrototypeOf()                     # ECMAScript 5出现, 传入对象返回原型
            o.constructor.prototype                     # 得到对的原型,对于Object.create()创建的对象常不是这样
            p.isPrototypeof(o)                          # 检测p是否是o的原型(或牌原型链中),与instanceof运算符类似
            __proto__                                   # Mozilla实现的js有的属性, safari和chrome也支持
    类属性
        表示对象类型信息的字符串, 用toString()方法可以得到
        ECMAScript 3和5 都不能设置这个属性,只能间接查询
        js内置构造函数创建的对象类属性与函数名称相匹配
            对象直接量、Object.create、自定义构造函数 创建的对象类属性是"Object"
            对于自定义类来说,没办法通过类属性来区分对象的类
        api
            toString()                                  # 返回如 [object class], 提取class, 很多对象的toString方法重写了, 要间接调用Function.call()方法
            function classof(o){
                if(o === null) return "Null";
                if(o === undefined) return "Undefined"; # ECMAScript 5中不需要对null和undefined作处理
                return Object.prototype.toString.call(o).slice(8, -1);
            }
    可扩展性
        表示是否可以给对象添加新属性。ECMAScript 5中 内置对象和自定义对象都显式可扩展
        宿主对象可扩展性由js引擎定义
        api
            # preventExtensions, seal, freeze 都返回传入的对象
            Object.esExtensible()                       # 判断对象是否可扩展
            Object.preventExtensions()                  # 转换对象为不可扩展, 参数为待转换对象, 对象转换不可扩展后,无法再转换回来, 给不可扩展对象原型添加属性, 对象同样会继承新属性
            Object.seal()                               # 对象设置不可扩展, 同时对象自有属性不可配置, 已有属性标记为可写的依然可配置, seal后的对象不能解封
            Object.isSealed()                           # 检测对象是否封闭
            Object.freeze()                             # 除了seal外,将自有数据属性设置为只读, setter方法不受影响
            Object.isFrozen()                           # 检测是否冻结
继承
    介绍
        js对象有自有属性(own property),有从原型继承来的属性
    原型链(prototype chain)                              # 原型,原型的原型 ...
        属性的查询先找自有属性,再找原型链
        属性修改时, 先检查属性是否允许赋值。
            总在自有属性修改或创建,不修改原型链上的对象。这就是属性的覆盖(override)
                继承的对象有setter方法且是accessor属性时,修改属性时会由当前对象(非原型对象)调用setter方法。
                由当前对象调用,所以还是不会修改原型链
                setter方法如setTitle()
    inherit(p)函数
        function inherit(p){
            if(p == null) throw TypeError();
            if(Object.create) return Object.create(p);
            var t = typeof p;
            if(t !== "object" && t !== "function") throw TypeError();
            function f(){};
            f.prototype = p;
            return new f();
        }
        var o = {x: "don't change this value"};
        library_function(inherit(o));                   # 可以防止对o的意外修改

数组 #

介绍
    数字索引                                             # 最大索引 2^32 - 2, 实现经过优化, 数字索引访问比访问常规属性快很多
    元素无类型
    数组是动态, 根据需要它们会增长或缩减
    数组可能是稀疏的, 索引不一定连续, length对于稀疏数组取最大索引+1
原理
    数组对象使用小于0 ~ 2^32 - 2 非负整数属性名时, 自动维护其length属性值
    [] 索引内的数字作为索引创建和访问, 其它作为属性
    a['1'] 同 a[1] 同 a[1.000]
    数组可以原型继承, 可以定义getter, setter方法
    数组元素可以delete, in, for/in                        # delete a[0], 0 in a
稀疏数组
    稀疏数组比稠密数组更慢, 内存利用率更高, 查找元素与常规对象属性查找时间一样长
    for/in时会跳过未有元素

    a = new Array(5)
    a = [, , ,]
    a = [1, , 3]                                        # 旧版本实现中, [1,,3]与[1,undefined, 3]是一样的,不是稀疏数组
    a[1000] = 0
创建与调用
    var misc = [1.1, , true]                            # 第二个是undefined
    new Array()
    new Array(10)                                       # 预分配数组空间
    new Array(5, 4, "testing")
    a[0]        
    a.length    
        length大于每一个索引
        对lenght赋值, 小于length索引的元素将删除, 如length=0清空数组
            Object.defineProperty()让数组的length变成只读
            Object.defineProperty(a, "length", {writable: false})来避免删除元素
            让数组无线不能配置也可以,如Object.seal, Object.freeze方法
添加删除
    a[1] = "a";
    a.push("zero", "one")
    delete a[1]
    a.pop()                                             # 反push
    a.shift()                                           # 头部删除, 重改所有元素索引
    a.unshift()                                         # 反shift, 头部插入元素
    splice()                                            # 通用方法插入, 删除, 替换数组元素, 根据需要修改length属性
遍历
    for(var i = 0; i < a.length; i++)                   # 判断undefined
    for(var index in a){                                # 会遍历出Array.prototype中的方法, 要进行过滤, ECMAScript 允许for/in遍历顺序不同, 一般是升序的, 如果同时有属性和元素,很可能是创建顺序
        if(!a.hasOwnProperty(i)) continue;
        // if(String(Math.floor(Math.abs(Nuber(i)))) !== i) continue;        # 跳过不是正整数的i
    }
    a.forEach(function(x){})                            # ECMAScript 5定义的新方法
多维数组                                                 # js不支持真正的多维数组,可以用数组模拟
    var a = new Array(10)
    a[0] = new Array(10)
    a[0][0]
空位问题
    Array(3)    // [, , , ]                             # 没有0位置, 但length = 3, 不同于有0位置但值为undefined, es5中对空位处理很不一致, 一般是跳过, es6会将空位值转为undefined
类数组对象                                               # 与数组相似的对象, 字符串虽然与数组类似,但length没有限制, 最好不看作类数组对象
    特性
        自动更新length属性, length设置后自动截断数组
        从Array.prototype中继承了一些有用的方法
        类属性(class)为"Array"(Date等类也是"Date")
    创建                                                 # 数组的方法对于自定义的类数组对象是通用的, 虽然不能继承Array.prototype, 但可以间接调用Function.call
        要求
            自动维护length属性
            下标是数字字符串并在数组下标范围内
        var a = {"0": "a", "1": "b"}
作为数组的字符串
    介绍
        ECMAScript 5中,字符串类似只读数组。访问如下
            s.charAt(0)
            s[0]
        Array.isArray(s)是false
        通用字符串方法可以乃至字符串中,如                   # 但字符串是不可变值的,所以中push, sort, reverse, splice在字符串上是无效的, 出错时没有提示
            Array.prototype.join.call('abc', " ")        # "a b c"
二进制数组
    介绍
        ArrayBuffer, TypedArray, DataView
        TypedArray按小端字节序来处理ArrayBuffer, 大端字节序可以自定义DataView
    TypedArray
        溢出
            正向溢出(overflow)
                uint8[0] = 256    // 0                  # 值为 数据类型最小值 + 余值 - 1, 这里为 0 + 1 - 1
                int8[0] = 128    // -128                # -128 + 1 - 1
            负向溢出(underflow)
                uint8[0] = -1    // 255                 # 值为 数据类型最大值 - 余值 + 1, 这里为 255 - 1 + 1
                int8[0] = -129    // 127                # 127 - 1 + 1
            Uint8ClampedArray负向溢出都为0, 正向溢出都为255
    场景
        o->ajax中
        xhr.responseType设置为 'arraybuffer'来接收二进制数据(也可以设blob)

        o-> canvas中
        ctx.getImageData(0, 0, canvas.width, canvas.height)
        uint8ClampedArray = imageData.data;

        o-> websocket中
        socket.binaryType = 'arraybuffer'
        var arrayBuffer = event.data;
        socket.send(new Uint8Array(4).buffer);

        o-> fetch api中
        返回request.arrayBuffer()得到arrayBuffer数据

        o-> file api中
        reader.readAsArrayBuffer(file);
        reader.onload = function() { var arrayBuffer = reader.result; }

集合 #

Set
    数据唯一
    Nan等于自身
WeakSet
    成员只能是对象
    成员弱引用,垃圾回收不考虑其引用,所以不能引用其成员,所以WeakSet不可遍历,因为刚遍历出的成员可能已删除
    可用于储存dom节点,实时判断是否存在,且防止内存泄漏
Map
    各种类型都可作为键, 键唯一覆盖, NaN等于自身, +0 等于 -0
WeakMap
    只接受对象作key
    元素被回收后, 自动移除对应的键值对
    适用于dom节点作键名,部署关联外部的私有属性(外部对象删除后,私有属性同步删除),不会内存泄漏
遍历器
    介绍
        默认三种结构支持, Array, Set, Map。Object不支持,因为不确定遍历顺序
        字符串是类数组,有原生的iterator接口
    内部调用方式
        解构
            let [x, y] = new Set().add(1).add(2);
        扩展运算符
            [...iterable]
        yield* iterable
        参数
            for ... of
            Array.from()
            Map(), Set(), WeakMap(), WeakSet()
            Promise.all()
            Promise.race()
    实现
        iterable[Symbol.iterator] = function* () {
            yield 1;
            yield 2;
        }
        iterable[Symbol.iterator] = function () {
            return {
                next(){},
                return () { return {done: true}}        # return 在for ... of 提前退出(出错, break, continue), 可以用于释放资源, return 方法必须返回一个对象,这是Generator规格规定的
                throw() {}                              # 配合Generator使用
            };

        }
    使用
        var result = iterator.next()
        while(!result.done) {
            var x = result.value;
            result = iterator.next();
        }

proxy #

介绍
    元编程(meta programming), 在对象外层进行代理
    在obj.proxy上设置Proxy对象,该对象的操作会变成对Proxy对象的操作

var obj = new Proxy({}, {
    get: function (target, key, receiver) {
        return Reflect.get(target, key, receiver);
    },
    set: function (target, key, value, receiver) {
        return Reflect.set(target, key, value, receiver);
    }
});

reflect #

介绍
    将Object上一些明显属于语言内部的方法(如Object.defineProperty)放到Reflect上
    修改Object上原有方法,变得更合理, 如Object.defineProperty在无法定义属性时抛出异常, 而Reflect.definePropert则返回false
    让Object操作变成函数作为, 如name in obj, delete obj[name]变成Reflect.has, Reflect.deleteProperty
    让Proxy上方法与Reflect方法对应,让Proxy的对象操作默认行为在Reflect上执行

正则 #

基本字符
    会精确匹配一段字符,如hi。这段字符可以出现多次
字面量
    /^[a-z]+$/.text(str);                   # ^代表开头, $是结尾
转义
    \
元字符                                       # metacharacter
    .                                       # 匹配除换行符以外任意字符
    \b
                                            # 表示单词的开头或结尾,也就是单词的分界。只匹配一个位置\s\S
        \bhi\b                              # hi单词
    \d                                      # 表示数字
    \s                                      # 匹配任意空白符,包括空格、tab、换行、中文全角空格等
        \s\S                                # 匹配包括\n在内的所有字符
    \w                                      # 匹配非特殊字符,包括字母、数字、下划线或汉字
    ^                                       # 匹配开头
    $                                       # 匹配结尾
    反义
        \W                                  # 非字符
        \S                                  # 非空白
        \D                                  # 非数字c
        \B                                  # 非单词位置
非
    [^x]                                    # 非x, [^aeiou] 除了aeiou以外的任意字符
限定字符
    {2}                                     # 表示前面的内容出现2次, {5, 12}内容出现5到12次, {5, }内容出现5或更多次
    ?                                       # 零次或一次
    *                                       # 零个或多个
    +                                       # 表示一个或多个
字符类
    [aeiou]                                 # 匹配其中的一个, [.?!] 匹配.或?或!
    [0-9]                                   # 同\d, [a-z0-9A-Z] 同\w
分枝条件
    |                                       # jpg|png,
        每个分支都从第一个分支开始匹配, 如\d{5}|\d{5}-d{4}只能匹配11111或11111-2222中的11111
分组                                         # 零宽断言只占用不消费
    ()
    语法
        (exp)
        (?<name1>exp)                       # 组命名
        (?:exp)                             # 消费exp, 不捕获匹配的文本,也不分配组号
        (?=exp)                             # 零宽断言,正向前瞻,后面能匹配表达式exp
            \b\w+(?=ing\b)                  # 匹配以ing结尾单词的前面部分,如dancing中的danc
            /(\w)\1{2}(?=(\w)\2{2})/g       # 匹配所有在3个连续相同字符前的相邻3个连续相同字符, aaalllsss0tAAAnnn999结果是aaa, lll, AAA, nnn
        (?<=exp)                            # 零宽断言,正向后瞻,前面能匹配表达式exp
            (?<=\bre)\w+\b                  # 匹配以re开头单词的后半部分,如reading中的ading
        (?!exp)                             # 零宽断言,负向前瞻,后面不匹配exp的位置, js不支持
            \b\w*q(?!u)\w*\b                # 匹配一个单词,该单词包含后面不是字母u的字母q
                
            \d{3}(?!\d)                     # 匹配三位数字,且它们后面不能有数字
            \b((?!abc)\w)+\b                # 匹配不包含连续字符串abc的单词
        (?<!exp)                            # 零宽断言,负向后瞻,前面不匹配exp的位置, js不支持
            (?<![a-z])\d{7}                 # 匹配前面不是小写字母的七位数字
        (?#comment)                         # 注释
后向引用                                     # 分组捕获后会自动编号,从左到右,1234。后向引用用于引用前面匹配到的文本,如 \1 代表分组1匹配的文本
    \b(\w+)\b\s+\1\b                        # 匹配重复的单词, 如go go
    (?<Word>\w+) 或 (?'Word'\w+)             # 把\w+的组名指定为Word, 用\k<Word>引用
贪婪与懒惰
    o-> 包含能接受重复限定符时,会匹配尽可能多的字符。如a.*b
    o-> a.*?b会懒惰匹配
        懒惰限定符
            *? 重复懒惰匹配任意次
            +? 重复懒惰匹配1次或多次
            ?? 重复懒惰匹配0次或1次
            {n, m}? 重复懒惰匹配n到m次
            {n,}? 重复懒惰匹配n次以上
平衡组/递归匹配
    (?'group') 把捕获的内容命名为group,并压入栈(Stack)
    (?'-group') 从栈中弹出最后压入的名为group的捕获内容。如果栈为空,则匹配失效
    (?(group)yes|no) 如果栈中存在名为group的捕获内容,继续匹配yes部分的表达式,否则则继续匹配no部分的表达式
    示例                                      # 平衡组最常见的应用是匹配HTML
        匹配xx<aa<bbb><bbb>aa>yy
            思路
                每碰到左括号,就压入一个Open, 每碰到右括号,弹出一个
                最后看栈是否空,如果否则表示不配对,应该失败
                正则表达式引擎会进行回溯(放弃最前面或最后面一些字符), 尽量使整个表达式得到匹配
        <                                     # 最外层的左括号
        [^<>]*                                # 后面非括号的内容
        (
        (
        (?'Open'<)                            # 又碰到了左括号, 压入一个Open
        [^<>]*                                # 后面非括号内容
        )+
        (
        (?'-Open'>)                           # 碰到了右括号, 擦掉一个Open
        [^<>]*                                # 后面非括号内容
        )+
        )*
        (?(Open)(?!))                         # 负向前瞻,判断栈中还有没有Open, 有则匹配失败
        >                                     # 最外层右括号
        )

特点 #

o-> js中不支持 回顾后发断言
o-> 可以跟三个flag,比如/something/igm
    i表示不区分大小写
    g表示匹配多个
        g会影响String.prototype.match()和RegExp.prototype.exec()的行为
        match中加g会返回数组,不加g返回比较详细的信息
        exec中加g,且正则存在变量中时,该正则变量执行exec后会存储信息, 如
        var re = /h(.*?)\b/g;
        re.exec('hello helloo') 执行三次,匹配内容有变化
    m表示,^$可以匹配每一个的开头和结尾
o-> api
    RegExp
        exec                                    # 执行第一个, exp本身保留执行状态
            exp = /#/
            exp.exec('##')
        test
    String
        replace                                 # 替换第一个, 'abc - 123 - #$*'
            'John Smith'.replace(/(\w+)\s(\w+)/, '$2, $1')
            'abc123#$*'.replace(/([^\d]*)(\d*)([^\w]*)/, function replacer(match, p1, p2, p3, offset, string) {
            return [p1, p2, p3].join(' - ');
            });
        replaceAll
        match                                   # 不能有g选项,只得到第一个匹配

.net中处理选项
    IgnoreCase                                  # 忽略大小写
    Multiline                                   # 多行模式, 更改^$的含义为一行首和行尾, $表示\n之前的位置以及字符串结束前的位置
    Singleline                                  # 单行模式(可以与Multiline通用),更改.的含义,便它与每一个字符匹配(包括\n)
    IgnorePatternWhitespace                     # 忽略空白,会忽略表达式中非转义空白并启用#作为标记注释
    ExplicitCapture                             # 显式捕获,仅捕获已被显式命名的组

常用 #

<a[^>]+>
    # 用尖括号括起来的以a开头的字符串
^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
    # 密码的强度必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间
^[\\u4e00-\\u9fa5]{0,}$
    # 字符串只能是中文
^\\w+$
    # 由数字,26个英文字母或下划线组成的字符串
[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?
    # 校验E-Mail 地址
^[1-9]\\d{7}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}$
    # 校验身份证号码 15位
^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$
    # 校验身份证号码 18位
^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$
    # “yyyy-mm-dd“ 格式的日期校验,已考虑平闰年
^[0-9]+(.[0-9]{2})?$
    # 金额校验,精确到2位小数
^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$
    # 国内 13、15、18开头的手机号正则表达式
^.*MSIE [5-8](?:\\.[0-9]+)?(?!.*Trident\\/[5-9]\\.0).*$
    # 判断IE的版本
\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\b
    # 校验IP-v4地址
(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))
    # 校验IP-v6地址
/^[a-zA-Z]+:\\/\\//
    # 检查URL的前缀
^(f|ht){1}(tp|tps):\\/\\/([\\w-]+\\.)+[\\w-]+(\\/[\\w- ./?%&=]*)?
    # 提取URL链接
^([a-zA-Z]\\:|\\\\)\\\\([^\\\\]+\\\\)*[^\\/:*?"<>|]+\\.txt(l)?$
    # 文件路径及扩展名校验
^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$
    # 提取Color Hex Codes
\\< *[img][^\\\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)
    # 提取网页图片
(<a\\s*(?!.*\\brel=)[^>]*)(href="https?:\\/\\/)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^"]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
    # 提取页面超链接
^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}
    # 查找CSS属性
<!--(.*?)-->
    # 抽取注释
<\\/?\\w+((\\s+\\w+(\\s*=\\s*(?:".*?"|'.*?'|[\\^'">\\s]+))?)+\\s*|\\s*)\\/?>
    # 匹配HTML标签
'12345678901'.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
    # 替换中四位到*
'1111111'.replace(/([\d]{3})(?=[\d]+)/g, '$1-')
    # 替换为 '111-111-1'

元字符扩展 #

\a              # 报警字符
\t              # 制表符
\v              # 竖向制表符
\r              # 回车
\f              # 换页符
\n              # 换行符
\e              # Escape
\0nn            # ASCII码中八进制代码为nn的字符
\xnn            # ASCII码中十六进制代码为nn的字符
\unnnn          # Unicode码中十六进制代码为nnnn的字符
\cN             # ASCII控制字符,如\cC 代表ctrl + c
\A              # 字符串开头,同^但不受多行选项影响
\Z              # 字符串结尾或行尾,不受多行选项影响
\z              # 字符串结尾,同$但不受多行选项影响
\G              # 当前搜索的开头
\p{name}        # Unicode中命名为name的字符类,如\p{IsGreek}
(?>exp)         # 贪婪子表达式
(?<x>-<y>exp)   # 平衡组
(?im-nsx:exp)   # 在子表达式exp中改变处理选项
(?im-nsx)       # 为表达式后面的部分改变处理选项
(?(exp)yes|no)  # 把exp当作零宽正向先行断言,如果能匹配,使用yes作为此组表达式,否则使用no
    (?(exp)yes) 只使用空表达式为no
    (?(name)yes|no) 命名为name的组捕获到内容,使用yes

风格 #

o-> 最好js和html用独立的引号风格,如
        html双引号, js单引号
o-> 始终用var之类来声明变量,不用未声明变量

o-> let和const取代var, 全局常量使用const

o-> 特意将变量声明放在函数体顶部, 而不是使用变量之外, 来反映真实的作用域声明提前

o-> 多用解构
    const [first, second] = arr                 # 数组取元素
    function f({a, b}) {}                       # 对象解构给函数赋值
    function f() {return {a, b}}, const {a, b} = f()                # 函数返回值解构
    var arr2 = [...arr]                         # 扩展运算符拷贝数组

o-> 单行定义对象不逗号结尾(以后不扩展), 多行时逗号结尾(以后可能会扩展), 尽量用简洁的写法
    {a: 1, b}
    {
        [getKey('a')],
    }

o-> Array.from转换类数组到数组

o-> 匿名函数 (() => {})(), 同时绑定了this为当前作用域

o-> 不使用arguments, 使用rest运算符

o-> 函数使用默认值 function f (opts = {})  {}

o-> 用Map取代Object, 因为Map内建遍历机制, key可为对象。只能要数据转换时用Object

o-> 总是用class取代需要的prototype操作, 因为class写法更简洁。extends也更简单, 不会有破坏instanceof运算的危险

o-> 模块使用es6的机制, 模块只能一个输出时用export default, 多输出时用export, 不要export 和export default混合使用

o-> 运算符
var t = o && o.a || ''                          # 有o时取o.a, 无o时取'', 因为&&的优先级比||高
var ifExist = !!o.a                             # 转换成布尔类型, 当然o.a = 0 什么的值时, 会判断失误,所以用来判断对象

o-> 判断类型
typeof a === "string"                           # 数组等其他Object类型通通是Object
a instanceof Array                              # 判断Object类型的具体类型
a.constructor == Array                          # 判断构造函数
Object.prototype.toString.call(o) === '[object Array]'              # 用toString判断

o-> 柯里化
function currying (fn, n) {
    return function (m) {
        return fn.call(this, m, n);
    }
}
function tailFactorial(n, total) {              # 尾递归调用优化
    if(n === 1) return total;
    return tailFactorial (n - 1, n * total);
}
const factorial = currying(tailFactorial, 1);
factorial(5)

o-> 尾递归
function factorial (n, total = 1) {
    if(n === 1) return total;
    return factorial(n - 1, n * total);
}

浏览器 #

js执行顺序
    当页面载入时,会执行位于 body 部分的 JavaScript。
    当被调用时,位于 head 部分的 JavaScript 才会被执行。

常用函数 #

基础扩展 #

循环变量作用域
    function constfunc(v){
        return function(){return v}
    }
    var funcs = []
    for(var i = 0; i < 10; i++){
        funcs[i] = constfunc(i)
    }
闭包序列
    var uniqueInteger = (function(){
        var counter = 0;
        return function(){return counter++;}
    }());
    seq  = uniqueInteger()
    id = seq()
闭包计数器
    function counter(){
        var n = 0;
        return {
            count: function(){return n++;},
            reset: function(){n = 0;}
        };
    }
属性存取器
    function counter(n){
        return{
            get count() {return n++},
            set count(m){
                if(m >= n) {n = m }
                else {throw Error("count can only be et to a larger value")}
            }
        }
    }
    var c = counter(1000);
    c.count;
属性define
    Object.defineProperty(Object.prototype, "extend", {
        writable: true,
        enumerable: false,
        configurable: true,
        value: function(o){
            var names = Object.getOwnPropertyNames(o);
            for(var i = 0; i < names.length; i++){
                if(names[i] in this) continue;
                var desc = Object.getOwnPropertyDescriptor(o, names[i]);
                Object.defineProperty(this, names[i], desc);
            }
        }
    });
私有属性
    function addPrivateProperty(o, name, predicate){
        var value;
        o["get" + name] = function(){return value;}
        o["set" + name] = function(v){
            if(predicate && ! predicate(v)) {throw Error("set" + name + ": invalid value " + v)}
            else {value = v}
        };
    }
    var o = {}
    addPrivateProperty(o, "Name", function(x){ return typeof x == "string";});
    o.setName("A");
    o.setName(o);
嵌套属性名
    function getAllPropertyNames = function(obj){
        var props = [];
        do {
            props = props.concat(Object.getOwnPropertyNames(obj));
        } while (obj = Object.getPrototypeOf(obj));
        return props;
    }
嵌套属性名2
    function keys(o){
        if(typeof o !== "object") throw TypeError();
        var result = [];
        for(var prop in o){
            if(o.hasOwnProperty(prop))
            result.push(prop);
        }
        return result;
    }
嵌套累加
    function flexisum(a){
        var total = 0;
        for(var i = 0; i < arguments.length; i++) {
            var element = arguments[i], n;
            if(element == null){
                continue;
            } else if(isArray(element)){
                n = flexisum.apply(this, element);
            } else if(typeof element === "function"){
                n = Number(element());
            } else{
                n = Number(element);
            }
            if(isNaN(n)){
                throw Error("flexisum(): can't convert " + element + " to number");
            }
            total +=n;
        }
        return total;
    }
泛函代理, monkey-patching 'this'
    function trace(o, m){
        var original = o[m];
        o[m] = function(){
            return original.apply(this, arguments);
        }
    }
兼容ECMAScript 3实现bind
    function bind(f, o){
        if(f.bind) {return f.bind(o)}
        else {
            return function(){
                return f.apply(o, arguments);
            }
        }
    }

函数式 #

thunk
    function thunk (fileName) {
        return function (callback) {
            return fs.readFile(fileName, callback)
        }
    }
extend, 同名覆盖
    function extend(o, p){
        for(prop in p){
            o[prop] = p[prop];
        }
        return o
    }
merge, 同名不覆盖
    function merge(o, p){
        for(prop in p){
            if(o.hasOwnProperty[prop]) {continue}
            o[prop] = p[prop];s
        }
        return o;
    }
restrict, 删除非公共属性
    function restrict(o, p){
        for(prop in o){
            if(!(prop in p)) delete o[prop];
        }
        return o;
    }
substract, 删除公共属性
    function subtract(o, p){
        for(prop in p){
            delete o[prop];
        }
        return o;
    }
union, extend产生新对象
    function union(o, p) { return extend(extend({}, o), p);}
intersection, restrict产生新对象
    function intersection(o, p){ return restrict(extend({}, o), p);}
mixin
    function mix (...mixins) {
        class Mix {}
        for (let mixin of mixins) {
            copyProperties(Mix, mixin);
            copyProperties(Mix.prototype, mixin.prototype);
        }
        return Mix;
    }
    function copyProperties(target, source) {
        for(let key of Reflect.ownKeys(source)) {
            if(key !== 'constructor'
                && key !== 'prototype'
                && key !== 'name') {
                let desc = Object.getOwnPropertyDescriptor(source, key);
                Object.defineProperty(target, key, desc);
            }
        }
    }
混合继承
    class A extends mix(B, C) {}
mixins方法不被覆盖
    let Mixin1 = (superclass) => class extends superclass {
        foo () {if(super.foo) super.foo()}
    }
    let Mixin2 = (superclass) => class extends superclass {
        foo () {if(super.foo) super.foo()}
    }
    class S {
        foo() {}
    }
    class C extends Mixin1(Mixin2(s)) {
        foo() {super.foo()}
    }
    new c().foo()        // C, Mixin1, Mixin2, S
trait
    # 同mixins 额外功能: 防止同名方法冲突, 排除混入某些方法,为混入方法起别名等
    @traits(A, B)
    class C()

generator #

状态机 generator clock
    var clock = function* (_) {
        while(true) {
            yield _;
            console.log('Tick');
            yield _;
            console.log('Tock');
        }
    }
    非generator实现
        var ticking = true;
        var clock = function() {
            if (ticking) {console.log('Tick');}
            else {console.log('Tock');}
            ticking = !ticking
        }
递归next
    function run(fn) {
        var gen = fn();
        function next (err, data) {
            var result = gen.next(data);
            if (result.done) {return result.value;}
            result.value(next);
        }
        next();
    }
    run(gen);
generator, promise, 递归next2
    var readFile = function(fileName) {
        return new Promise(function (resolve, reject) {
            fs.readFile(fileName, function(err, data) {
                if(err) {reject(err);}
                resolve(data);
            })
        })
    }
    var gen = function* () {
        var f1 = yield readFile('/etc/fstab');
    }
    function run(gen) {
        var g = gen();
        function next(data) {
            var result = g.next(data);
            if (result.done) {return result.value;}
            result.value.then(function(data) {
                next(data);
            })
        }
        next()
    }
    run(gen);
co, thunkify
    var readFile = thunkify(fs.readFile);
    var gen = function* () {
        var r1 = yield readFile('/etc/fstab');
        var r2 = yiled readFile('/etc/shells')
    }
    co(gen)
mixins注解
    function mixins (...list) {
        return function (target) {
            Object.assign(target.prototype, ...list)
        }
    }
    const Foo = {
        foo() {}
    }
    @mixins(Foo)
    class MyClass()

api #

全局 #

属性
    Infinity                                # 表示正无穷大
    NaN                                     # 指示是不是数字, Infinity与NaNECMAScript中可读写, ECMAScript修正为只读, Infinity与NaN与任何值不相等(包括自身), 建议用非来判断
    undefined
    console
        log('abc %s', 'd')                  # 'abc d', 格式化输出

方法
    parseFloat                              # 可以解析整数和浮点数, 跳过前导空格, 忽略后面非数字内容。第一个非空格字符是非法数字直接量时,返回NaN
    parseInt                                # 只解析整数, 可接收第二个可选参数,指定数字转换基数
        "0x", "0X"前缀, 解析为16进制数
    isNaN
    isFinite                                # NaN, Infinity 不通过, 非数字报错
    escape                                  # deprecated since ECMAScript v3
    decodeURI                               # 不处理 =, & 等
    decodeURIComponent                      # 会处理 =, & 等
    encodeURI
    encodeURIComponent
    eval                                    # 可以访问调用时的整个作用域,所以编译器不能裁剪作用域, 要间接调用, 如 (0, eval)(src)
    requestAnimationFrame
    fetch
        fetch(url).then(function (request) { return request.arrayBuffer })

构造函数 #

包装对象函数 #

介绍
    基本类型(数字,布尔,字符串)在构建时,会通过new String(s)的方式转换成对象,有了对象的方法,这个过程就是包装对象
undefined没有包装对象,所以访问属性会造成类型错误。

String #

介绍
    是Object类型, 是基本类型string的包装类型
        引用字符串类型的属性时,js会调用new String(s)来转换成对象
            属性引用结束, 该新对象销毁
            实际上有优化
包装测试
    自动包装测试
        1.toString                          # 异常
        (1).toString                        # => "1"
    原始类型属性只读
        var s = "test";
        s.len = 4;                          # 相当于new String("test").len = 4
        s.len   // undefined                # 相当于new String("test").len
    运算
        ==                                  # 原始类型与包装类型相等
        ===                                 # 原始类型与包装类型不相等
语法
    ECMAScript 5中,可以用数组方式访问16位值, 如
        s[0]
属性
    length                                  # 4字节的字符会误判为2

静态方法
    localCompare()                          # 参照本地语言字母表字符次序
    fromCodePoint()                         # 支持4字节字符值转换, 多参数时合并成字符串
    raw                                     # 一个tag函数, 转义模板字符串到字符串
        String.raw`\n${2 + 3}`              # '\\n5'
        String.raw({raw: 'test'}, 0, 1, 2)  # 正常调用时, 第一个参数对象中必要有raw属性,其值为tag函数的第一个字符串数组的参数。其余参数与tag函数其余参数对应
                
方法
    substring(1, 4) // => 返回第2~4个字符     # 与java不同,java是第1~3个
    slice(1, 4)
    indexOf("")
    lastIndexOf("")
    toUpperCase()
    charAt(0)                               # 取2个字节的字符
    charCodeAt()                            # 取2个字节字符的十进制值
    codePointAt()                           # index位的4字节字符当作一个字符,正确处理,得到十进制值, index+1位会取该4字节字符的后2字节, 为了匹配length属性
    at()                                    # 支持4字节字符, 匹配正确长度的方法
    fromCharCode()                          # 2字节字符值转换到字符
    normalize()
        '\u01D1'.normalize() === '\u004F\u030C'.normalize()
            原重音符号与 (字符 + 重音)合成符等价
        不支持3个及以上字符合成
    includes                                # s.includes('o', 6) 从6位置开始搜索o是否出现
    startsWith
    endsWith                                # s.endsWith('o', 6) 前6个字符是否以o结尾
    repeat(3)                               # 字符串重复3次返回
    padStart                                # 'x'.padStart(5, 'ab') 返回 'ababx', padStart(5)会填充空格
    padEnd
    正则                                    # es6中内部调用RegExp.prototype[Symbol.match]等方法
        search(pattern)                     # 返回首次匹配成功的位置
        match(pattern)                      # 所有匹配位置的数组
        replace(pattern, "")                # 所有匹配替换
        split(pattern)                      # 匹配分割

Number #

属性
    NaN
    POSITIVE_INFINITY
    NEGATIVE_INFINITY
    MAX_VALUE
    MIN_VALUE
    EPSILON                                 # 极小的常量 2.22....e-16, 用来设置浮点计算的一个合理误差范围
    MAX_SAFE_INTEGER                        # 越界最大值
    MIN_SAFE_INTEGER                        # 越界最小值
静态方法
    isFinite
    isNaN
    isInteger
    isSafeInteger                           # 判断是否越界
    parseInt
    parseFloat
        
方法
    字符串解析
        构造方法                            # 只基于十进制转换
        调用全局函数parseInt(), parseFloat()
    转换为字符串
        toString()                          # Number类的toString()可接收转换基数, 来转换进制
            如 n.toString(2); n.toStrng(8); n.toString(16)
        toFixed(0)                          # 保留几位小数, 从不使用指数计数法
        toExponential(1)                    # 转换为指数, 参数为指数前保留几位小数
        toPrecision(4)                      # 保留有效数字,多出位数转换成指数, 以上三个方法自动补0

Boolean #

Object #

属性
    __proto__
        用来读取或设置当前对象的prototype对象,只有浏览器必须部署这个属性
        语义上是内部属性,被支持仅因为被广泛使用
动态方法
    hasOwnProperty
         是否有某属性,可判断属性值为undefined的情况
         没prototype的对象, 该方法直接调用失败,需要Object.prototype.hasOwnProperty.call来调用
    propertyIsEnumerable
    isPrototypeOf
        b.isPrototypeOf(c)                  # b是否出现在c的prototype链中
    toString
    toLocaleString
        返回对象的本地化字符,默认时仅调用toString方法
        Date和Number对toLocaleString做了定制
        Array的toLocalString对每个数组元素调用toLocaleString方法
            toString会对每个数组元素调用toString方法
    *toJSON
        Object.prototype没有定义这个方法, JSON.stringigy会调用要序列化对象的toJSON方法,如Date.toJSON()
    valueOf
        要将对象转换为原始值时调用
        如果需要使用原始值的上下文中使用了对象,会自动调用这个方法
静态方法
    create                                  # new会执行构造方法,有副作用
        Object.create(null)                 # 创建的对象没有prototype,不同于{}
    getPrototypeOf                          # 用于判断继承
            Object.getPrototypeOf(B) === A
    getOwnPropertyNames                     # 所有自身属性
    getOwnPropertyDescriptor(obj, 'foo')    # 获得属性的描述对象
    getEnumPropertyNames                    # 可枚举自身属性和继承属性
    setPrototypeOf                          # 标准可靠的方法修改对象prototype的关联
            Object.setPrototypeOf(Bar.prototype, Foo.prototype)     # 同Bar.prototype = Object.create(Foo.prototype)
    keys                                    # 可枚举自身属性
    defineProperty                          # 数据描述符,getter、setter是访问描述符
        # 修改属性,在原型链上层属性为writable: false或有对应属性的setter时,不会发生屏蔽。使用defineProperty可发生屏蔽
        Object.defineProperty(Object, 'is', {
                value: function (x, y) {...},
                configurable: true,         # false时,delete该属性会静默失败
                enumerable: false,
                writable: true,
                get: function(){return 1}
        })
    toLocaleString
    toString                                # toString(16) 转换为16进制
    is('foo', 'foo')                        # 比较两个值是否相等, 基本是===,不同在于, +0 等于 -0, NaN 等于 NaN
    assign(target, source1, source2)
        复制源对象自身可枚举属性到目标对象, source2覆盖source2覆盖target
        Symbol值的属性也会被拷贝
        _.defaultsDeep方法可以深拷贝
        常用于给对象添加静态方法或方法,合并对象,为属性指定默认值
            Object.assign({}, DEFAULTS, options);
    preventExtensions                       # 使对象不可设置属性
    isExtensible
    seal                                    # 创建“密封”对象, 在现有对象上调用preventExtensions并把现在属性标记为configurable: false
    freeze                                  # 调用seal并标记现有属性为writable: false

Array #

静态方法
    isArray(a)                              # ECMAScript 5 判断是否数组
            [] instanceof Array的问题
                多frame中有多个js环境, 都有自己的全局对象与构造函数。一个窗体中的对象是当前窗体构造函数创建,而另外窗体构造函数判断该对象则不成立。
                    # 但窗体间的混淆不常发生
            ECMAScript 3 可以检查对象类属性来判断。
                # 实际上就是ECMAScript 5中Array.isArray的代码
                var isArray = Array.isArray || function(o){
                    return typeof o === "ojbect" && Object.prototype.toString.call(o) == "[object Array]"
                };
    from
        # 类数组对象或可遍历对象(如Set, Map)转为数组,转换后的数组具有了iterator接口
        # 类数组对象同[].slice.call(arraylike), 可遍历对象同[...traversable]
        Array.from(arraylike)
        Array.from([1, , 2, , 3], (n) => n || 0)
        Array.from('abc')
            # 字符串转数组
        Array.from(new Set(array))
            # 去除重复元素
    of
        # 一组值转换为数组, 用于替代Array(), new Array()
        # 弥补Array()的返回不一致问题, 如Array(3) // [, , ,]
        Array.of(1, 2, 3)        // [1, 2, 3]
动态方法
    join, ...                               # firefox1.5 后 动态方法也写入到了静态方法中。但不是标准, 是String.split()的逆向操作
        a.join()                                // => "1,2,3"
        a.join("")                        // => "123"
        new Array(2).join('-')                // => "--"
    reverse                                 # 倒序
        a.reverse()
    sort                                    # 排序
        a.sort()                            # 默认以字母表排序, 自动转字符串 undefined排到最后
        a.sort(function(a, b){
            return a-b;                     # a在前, 返回负数。b在前返回正数。0表示相等,顺序无关紧要, 此处是升序排列
        })
    concat                                  # 连接数组, 创建返回一个新数组, 传入数组, 连接数组元素而非本身, 但不扁平化数组的数组
        a.concat(4, [5, [6, 7]])
    slice                                   # 截取新数组
        var a = [1,2,3,4,5]
        a.slice(0,3)    // 返回 [1,2,3]
        a.slice(3)      // 返回 [4,5]
        a.slice(1, -1)  // 返回 [2,3,4]
        a.slice(-3, -2) // 返回 [3]
    splice                                  # 修改数组
        第一个参数起始位置(包含), 第二个参数删除个数(省略则从起始到结束都删除)
        后面任意个参数指定插入到数组中的元素
        返回由删除元素组成的数组
    push 和 pop                              # 数组作为栈(先进后出)来用, push在结尾添加, pop在结尾删除, 插入元素时不解封数组
    unshift 和 shift                         # unshift在头部添加元素, shift在头部删除。都改变索引, 插入元素时不解封数组
    toString                                # 调用每个元素的toString()方法, 输出有逗号分隔的字符串列表(没有方括号), 与不使用任何参数的join()是一样的
    toLocaleString                          # 调用元素的toLocaleString
    copyWithin                              # 当前数组中复制一段到另一位置
        [1, 2, 3, 4, 5].copyWithin(0, 3)        // [4, 5, 3, 4, 5]
            # 第三个参数是结束位置(不包含), 默认是结尾。把4, 5 复制替换到1, 2
        [1, 2, 3, 4, 5].copyWithin(0, -2, -1)        // [4, 2, 3, 4, 5]
            # 4到5(不包含)复制到1
    find                                    # 返回第一个符合条件的元素, 没有时返回undefined, 可处理NaN, 第二个参数绑定回调函数的this对象
        [1, 4, -5, 10].find((n) => n < 0)
    findIndex                               # 返回第一个符合条件的index, 没有时返回-1
    fill                                    # 用某元素填充数组, 可标识起始位置
        [1, 2, 3].fill(0)        // [0, 0, 0]
        [1, 2, 3].fill(0, 1, 2)        // [1, 0, 3]
    includes                                # 是否包含元素,可识别NaN, 返回布尔值, 第二个参数表示起始位置, indexOf 使用===判断, 会对NaN误判
            [1, 2, 3].includes(2, 0)

    遍历类方法
        对稀疏数组,不存在的元素不调用传递的回调函数
        方法第一个参数是回调函数, 第二个参数是回调函数的this
        多数情况下, 传入的回调函数传递三个参数: 数组元素, 元素的索引, 数组本身
        forEach                             # 没有break语句,用抛出异常替代
            a.forEach(function(value){})
                function foreach(a, f, t){
                try{a.forEach(f, t);}
                catch(e){
                    if(e === foreach.break) return;
                    else throw e;
                }
            }
            foreach.break = new Error("StopIteration");
        map                                 # 映射数组元素, 稀疏数组也返回相同的缺失元素
            [1,2,3].map(function(x){return x * x})  // 返回 [1, 4, 9]
        filter                              #  回调返回true的元素保留,返回新数组, 返回的数组总是稠密的,可用于压缩空缺并删除undefined 和 null元素
            [5, 4, 3, 2, 1].filter(function(x){ return x < 3}) // 返回 [2, 1]
        every和some
            every表示所有, 在都返回true时返回true
            some表示存在, 都返回false时返回false
                在确定返回值时停止遍历
            a.some(func)
        reduce和reduceRight                  # 使用指定函数将数组元素进行组合,称为"注入"和"折叠"
            a.reduce(function(x, y){ return x + y}, 0)
                第一个是回调函数。第二个可选,是初始值,无初始值时一开始直接传入第一第二个元素
                    回调函数中第一个是累积的结果, 第二个是当前元素
                空数组无初始值调用会导致类型错误异常。
                只有一个值并没有初始值时, reduce只简单抬这个值
            reduceRight同reduce,但索引从高到低处理数组
        indexOf和lastIndexOf
            搜索数组元素, 返回第一个匹配元素的索引, 失败则返回 -1
                indexOf从前往后, lastIndexOf从后往前
            第二个参数可选,指定起始索引。负索引代表相对末尾的偏移量
            字符串也有indexOf和lastIndexOf, 针对每个字符
    返回遍历器
            entries
                for(let [ind, ele] of ['a', 'b'].entries()) {}
                    # 得到 0 'a', 1 'b'
                    # 不用for of , entriesIterator.next().value        // [0, 'a']
            keys
            values

Function #

使用
    var f = new Function("x", "y", "return x*y;");
        # 任意数量实参。最后一个实参是函数体,语句间用分号隔开
        # 创建一个匿名函数
特点
    允许js在运行时动态创建并编译函数
    每次调用,都解析函数体并创建新函数对象,效率低
        # 循环中嵌套函数和函数定义表达式不会每次都重新编译
    总在全局作用域创建,可以认为其构造函数是全局作用域中执行eval()
函数体代码内
    arguments
        callee
        caller                              # 调用栈的上层函数, 出于安全考虑,大部分编译器已不支持caller, 用非标准的 fn.caller来取代, fn为当前函数名
属性
    length
        只读属性,代表函数形参数量。不包含设置了默认值的形参,也不包含...rest参数
        arguments.length是实际实参个数, arguments.callee.length是期望实参个数, 同本length
    name
        函数名, es5中只支持具名函数如function a(){}, es6支持var a = function(){}
        (new Function).name        // 'anonymous'
        foo.bind({}).name        // 'bound foo'
    prototype                               # 指向原型对象(prototype object),从该函数创建对象时,从原型对象上继承属性

方法
    call(o, 1, 2)                           # 传入可变调用时参数
    apply(o, [1, 2])                        # 传入调用时参数数组或类数组对象, 这样可以将arguments数组直接传入另一个函数来调用
        ECMAScript 严格模式中,o传入什么,this就是什么。其它情况下,o为null或undefined时替换为顶级对象,原始值会被包装。
    bind(o, ...)
        ECMAScript 5新增方法。在函数a上调用bind, 传入对象o,反回以o调用a的新函数b
            bind返回的是一个闭包, 返回的函数不包含prototype属性
            普通函数固有的prototype属性是不能删除的
            除第一个实参外,其它实参按顺序绑定到调用bind函数f的实参上,称为柯里化(currying), 如
            f = function(x, y); ff = f.bind(o, 1); ff(2);        // 此时x绑定为1, y传入为2
            ECMAScript 5中的bind, 返回的函数对象的length属性,值是返回函数的形参个数减其实参个数
            返回的函数可以用作构造函数,此时以原始函数的形式调用作为构造函数(实参也会原封不动地传入)
                用作构造函数时, 使用原始函数的prototype
    toString()
        ECMAScript规定返回和函数声明语法相关的字符串
        大多数toString()方法返回函数的完整源码,内置函数往往返回类似"[native code]"的字符串作函数体

Date #

var now = new Date()
var then = new Date(2011, 0, 1)
var later = new Date(2011, 0, 1, 17, 10, 30)
var elapsed = now - then;

now.setMonth(now.getMonth - 1);
方法
    getFullYear()
    getMonth()
    getDate()
    getDay()
    getHours()
    getUTCHours()

Error #

RegExp #

构造
    new RegExp('xyz', 'i'); // /xyz/i
    new RegExp(/abc/ig, 'i') // /abc/i
修饰符
    i
    g                                       # 全局多次匹配, 下次匹配从剩余中重新开始
    u                                       # 正确处理4字节字符, 存在u修饰符时, /\u{61}/可以表示unicode字符, 否则会匹配61个连续的u
    y                                       # 粘连,基本同g,不同在于剩余第一个字符开始必须匹配上, 确保匹配之间不会有漏掉的字符
        var s = 'aaa_aa_a', r1 = /a+/g, r2 = /a+/y;
        r1.exec(s), r2.exec(s)              # ['aaa'] ['aaa']
        r1.exec(s), r2.exec(s)              # ['aa'] null
属性
    flags                                   # 修饰符
    lastIndex                               # 从这个index开始匹配
    sticky                                  # 是否设置了y字符
静态方法
        
方法
    test
        /\d+/g.test("testing: 1, 2, 3")
    exec                                    # 返回带有特殊属性的Array match
        match
            属性
                index
                    # 在index上匹配成功

Set #

构造
    new Set()
    new Set([1, 2, 3])
属性
    size                                    # Set实例成员数
方法
    add(x)
    delete(x)
    has(x)                                  # 是否有x
    clear()                                 # 清除所有成员
    keys()
    values()                                # values同keys完全一致, 返回遍历器
    entries()                               # 返回[key, key]的遍历器
    forEach(function (value, key, obj) {}, boundThis)

WeakSet #

构造
    new WeakSet()
    new WeakSet([1, 2, 3])                  # 任何可遍历对象
属性                                         # 没有size
方法
    add(x)
    delete(x)
    has(x)

Map #

构造
    new Map()
    new Map([['a', 1], ['b', 2]])
属性
    size
方法
    set(key, value)
    get(key)
    delete(key)
    has(key)
    clear()
    keys()
    values()
    entries()                               # map[Symbol.iterator] === map.entries
    forEach(function(value, key, map) {}, boundThis)

WeakMap #

方法
    get
    set
    delete
    has

Proxy #

new Proxy(target, handlers)                 # target表示要拦截的对象, handler是回调方法
拦截器
    get(target, propKey, receiver)          # 属性读取。propKey是属性名, receiver是继承该proxy的对象
    set(target, propKey, value, receiver)   # 属性设置
    has(target, propKey)                    # in操作,返回布尔值
    deleteProperty(target, propKey)         # delete操作,返回布尔值
    enumerate(target)                       # for in , 返回遍历器
    ownKeys(target)                         # Object.getOwnPropertyNames, Object.getOwnPropertySymbols, Object.keys, 返回数组
    getOwnPropertyDescriptor(target, propKey)                       # Object.getOwnPropertyDescriptor, 返回描述对象
    defineProperty(target, propKey, propDesc)                       # Object.defineProperty, Object.defineProperties, 返回布尔值
    preventExtensions(target)               # Object.preventExtensions, 返回布尔值
    getPrototypeOf(target)                  # Object.getPrototypeOf, 返回对象
    isExtensible(target)                    # Object.isExtensible, 返回布尔值
    setPrototypeOf(target, proto)           # Object.setPrototypeOf, 返回布尔值
    apply(target, object, args)             # 拦截proxy作为函数调用的操作, 如proxy(), proxy.call, proxy.apply
    construct(target, args, proxy)          # 拦截proxy作用构造函数的操作, 如new proxy
静态方法
    revocable(target, handler)              # 返回有proxy, revoke属性的对象实例, proxy是Proxy实例, 调用revoke()函数可以取消Proxy
        et {proxy, revoke} = Proxy.revocable({}, {})

ArrayBuffer #

构造
    var buf = new ArrayBuffer(32)           # 生成32字节的内存区域,每个字节默认值为0
    if(buf.byteLength === 32)               # 由于内存可能不够大,要检查是否分配成功
属性
    byteLength                              # 内存区字节长度
方法
    slice(0, 3)                             # 拷贝前3个字节,生成新的ArrayBuffer
    isView(v)                               # 检查某视图是否为该buf的视图

(TypedArray) #

9种类型数组
    Int8Array
    Uint8Array
    Uint8ClampedArray                       # 自动过滤溢出。用于处理图像颜色, 只取值0 - 255, 过滤掉高位, ie10不支持该类型
    Int16Array
    Uint16Array
    int32Array
    Uint32Array
    Float32Array
    Float64Array
构造
    var x1 = new Int32Array(buf)
        带符号整形方式读buf
        new Int32Array(buf, 2, 2) 开始于字节2, 长度为2(2 * 32bit)。第3个参数不填则到末尾
            开始字节数要符合视图类型, 如16位类型视图单位是2个字节, 不能从1字节开始, 否则将报错
            用于构建复合视图
    x1[0] = 1;                              # 第0位4个字节赋值
    var x2 = new Uint8Array([0, 1, 2])      # 数组会直接分配内存生成ArrayBuffer
    new Float64Array(8)                     # 直接分配8字节生成ArrayBuffer来创建视图
    new Int8Array(new Uint8Array(4))        # 会开辟新的ArrayBuffer,复制原有数据来建立视图
        new Int8Array(new Uint8Array(4).buffer)可以用同一个buffer
属性
    length
    BYTES_PRE_ELEMENT                       # 表示当前数据类型占用的字节数
    buffer                                  # 该视图的ArrayBuffer对象
    byteLength                              # 该视图中buffer占内存的长度,是只读属性
    byteOffset                              # 该视图从哪个字节开始, 只读属性
静态方法
    of                                      # 将参数转为TypedArray实例
    from                                    # 可遍历数据转TypedArray, 可将TypedArray转为另一种TypedArray。可以接map函数
        Int16Array.from(Int8Array.of(1, 2, 3), x => 2 * x)
方法                                        # 没有concat方法
    set                                     # 复制数组,整段内存覆盖
        b.set(a, 2)                         # 从b的index2开始复制a
    subarray                                # 建立新视图
        a.subarray(2, 3)                    # 从index2复制到index3(不包含), 参数2不填默认复制到结尾
    slice

DataView #

构造
    new DataView(buf)                       # DataView(ArrayBuffer buffer [, startIndex [, length]])
属性
    buffer
    byteLength
    byteOffset
方法
    getInt8(0, true)                        # 以带符号整形格式读第0个字节, 第二个参数默认false, 使用大端字节序解读(两个或以上字节的数据需要), 设置true则为小端字节序
    getUint8
    getInt16
    getUint16
    getInt32
    getUint32
    getFloat32
    getFloat64
    setUint8(0, 1, true)                    # 开始序号, 数据, 小端字节序
    setInt16
    setUint16
    setInt32
    setUint32
    setFloat32
    setFloat64

WebSocket #

构造
    new WebSocket('ws://127.0.0.1:8081')
属性
    binaryType                              # 设置成'arraybuffer'来接收和发送arraybuffer

FileReader #

构造
    var fileInput = document.getElementById('fileInput');
    var file = fileInput.files[0];
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader.onload = function () { var arrayBuffer = reader.result; }
    或
    reader.addEventListener('load', processimage, false);
    function processimage(e) { var buffer = e.target.result; }

Promise #

构造
    var promise = new Promise(function (resolve, reject) {resolve(0); /* reject(err)*/})
方法
    then(func1, func2, func3)               # func1对就fulfilled回调, func2对应rejected回调, func3用于处理进度信息
    catch                                   # 是then(null, rejection)的别名,尽量使用catch而非then(null, rejection), 这样看起来更接近同步写法
静态方法
    all([p1, p2, p3])                       # 成员不是promise对象时,先promise.resolve(data), 全部完成, fullfilled。一个rejected, rejected, 返回第一个reject的错误
    race([p1, p2, p3])                      # 一个完成, fullfiled, 返回该promise
        Promise.race([p1, new Promise((resolve, reject) => {
            setTimeout(() => reject(new Error('time out.')), 5000)
        })])
    resolve
    reject
    done                                    # 不在规范内, 总是在回调链尾端, 保证抛出任何可能出现的错误
    finally                                 # 不在规范内, 接受一个回调函数,永远执行

全局对象 #

顶级全局对象 #

介绍
    js代码最外层的this
    初始化时, 定义所有预定义全局值
    代码中定义的全局变量,实际是该对象的属性
Global
Window
    介绍
        初始化时定义了一部分其他全局属性

Math #

属性
    PI
    E                                       # 自然对数底数
    LN10                                    # 同Math.log(10), 表示以e为低10的对数, Math.log(100)/Math.LN10 消底后表示以10为底100的对数
    LN2
静态方法
    trunc                                   # 去除小数部分
    sign                                    # 判断正负或零
    exp                                     # e的x次方
    log                                     # x的自然对数
    cbrt                                    # 立方根, 同Math.pow(Math.abs(x), 1/3)
    clz32
        二进制下32位无符号整数有多少个前导0。小数会取floor
            count leading zero bits in 32-bit binary representations of a number
        Math.clz32(1000)        // 22
        Math.clz32(1000 << 1)        // 21
    imul                                    # 32位带符号整数的乘积, 在乘积越界时会返回正确的低位数值
    fround                                  # 返回一个数的单精度浮点数表示, 4位无法精确表示的小数,会返回最接近的数, 同new Float32Array([x])[0]
        Math.fround(1.337);        // 1.337000012...
    hypot                                   # 所有参数平方和的平方根
    expm1                                   # 返回Math.exp(x) - 1
    log1p                                   # 返回Math.log(1 + x)
    log10                                   # 返回以10为低x的对数, 同 Math.log(x) / Math.LN10
    log2
    sinh                                    # 双曲正弦 hyperbolic sine
    cosh                                    # 双曲余弦 hyperbolic cosine
    tanh                                    # 双曲正切 hyperbolic tangent
    asinh                                   # inverse hyperbolic sine
    acosh
    atanh
方法
    pow(x, y)                               # x的y次方, pow(x, 1/3) 表示立方根
    round(.6)                               # 四舍五入
    ceil(.6)                                # 向上求整
    floor(.6)                               # 向下求整
    abs(-5)                                 # 绝对值
    max(x, y)                               # 最大值
    min(x, y)                               # 最小值
    random()                                # >=0, < 1.0的伪随机数
    sqrt(3)                                 # 平方根
    sin(0)
    log(10)                                 # 自然对数
    exp(3)                                  # e的3次幂

JSON #

方法
    parse(str)
    stringify(obj)

Reflect #

静态方法
    ownKeys(target)                         # 返回对象自身所有属性
    enumerate(target)                       # 返回Iterator,遍历对象自身和继承的所有可枚举属性, 同for ... in
    apply(target, thisArg, args)
    construct(target, args)
    get(target, name, receiver)
    set(target, name, value, receiver)
    defineProperty(target, name, desc)
    deleteProperty(target, name)
    has(target, name)
    isExtensible(target)
    preventExtensions(target)
    getOwnPropertyDescriptor(target, name)
    getPrototypeOf(target)
    setPrototypeOf(target, prototype)

Symbol #

属性
    hasInstance                             # Obj[Symbol.hasInstance]方法在instanceof运算时调用,如Foo[Symbol.hasInstance](foo)
    isConcatSpreadable                      # arr.concat时是否要展开
        let arr = [1, 2], arr[Symbol.isConcatSpreadable] = false,
        ['a', 'b'].concat(arr, 'c')        // ['a', 'b', [1, 2], 'c']
    species                                 # 如果this.constructor[Symbol.species]存在, 用它来做构造函数
    match                                   # str.match(obj)时, 调用obj[Symbol.match](str)
    replace                                 # str.replace(s, r)时, 调用s[Symbol.replace](s, r)
    search                                  # str.search(obj)时,调用obj[Symbol.search](str)
    split                                   # str.split(separator, limit)时, 调用separator[Symbol.split](str, limit)
    iterator
        for ... of指向调用的默认遍历器
        function A {*[Symbol.iterator] () {
            let i = 0; while(this[i] != undefined) {yield this[i]; i++;}
        }}
    toPrimitive                             # 对象转原始类型值时调用
        {[Symbol.toPrimitive] (hint) {}}        // hint值有 'number', 'string', 'default'
    toStringTag
        toString时拼在后面, 如 '[object xxx]'
    unscopables
        排除with时的属性, Array.prototype[Symbol.unscopables]        // {copyWithin: true, ...}

方法
    s.toString()        // 'Symbol(foo)'    # 可以String(s) 得到字符串'Symbol(foo)'
静态方法
    for('foo')                              # 搜索以'foo'作参数登记的Symbol值, 没有时会新建、登记并返回, 这种登记是全局的
    keyFor(s)                               # 返回s登录的字符串,没有时返回undefined

dom #

window对象 #

document #

属性
    id
    innerHTML                               # 非标准但通用
    body
        方法
            appendChild(domElement)
方法
    getElementById("")

element #

属性
    innerHTML
    style
        display = "none"
        visibility = "hidden"
    className
方法
    createElement("div")
    createTextNode(msg)
    appendChild(ele)

XMLHttpRequest #

var req = new XMLHttpRequest()
方法
    open("GET", url)
    send(null)                              # null表示不带正文地发送这个请求
    onreadystatechange = function(){        # 重写回调函数
        if(req.readyState == 4 && req.status == 200){
            var text = req.responseText;    # 响应的字符串
        }
    }

localStorage #

Worker #

介绍
    it is a javascript running in the background, without affecting the performance of the page.
    dom中的js线程在执行时会阻塞
使用
    var w;
    // start worker
    function startWorker(){
        if(typeof(Worker) !== 'undefined'){
            if(typeof(w) == 'undefined'){
                w = new Worker('demo_workers.js');
            }
            w.onmessage = function(event){
                # worker 's api, will call postMessage()
                document.getElementById('result').innerHTML = event.data;
            };
        }else {
            document.getElementById('result').innerHTML = 'sorry, your browser does not support Web Workers...';
        }
    }
    // stop worker
    w.terminate();                                                        # worker 's api, will trigger w.onmessage();
    w = undefined;

    /* demo_workers.js */                                            # 外部的js文件不能访问window, document, parent对象
    var i = 0;
    function timeCount(){
        i = i + 1;
        postMessage(i);                                            # worker 's api, when onmessage() was triggered.
        setTimeout('timeCount()', 500);
    }
    timedCount();

EventSource #

介绍
    浏览器推送
事件
    onopen
    onmessage
    onerror
使用
    var source = new EventSource("demo_sse.php");
    source.onmessage = function(event){
        document.getElementById('result').innerHTML += event.data + '<br/>';
    };
    // demo_sse.php
    <?php
    header('Content-Type: text/event-stream');
    header('Cache-Control: no-cache');

    $time = date('r');
    echo "data: The server time is: {$time}\n\n";
        # data在上面event.data中引用
    flush();
    ?>

控件 #

ActiveXObject #

new ActiveXObject("Excel.Application");         # Microsoft.XMLHTTP, ie中适用
Server.CreateObject("Microsoft.XMLHTTP")        # 在chrome中不起作用, 可以用 new XMLHttpRequest()创建

canvas #

概念
    原点: canvas左上角
    默认Style为black
    颜色设定
        "red" "blue"
        "#EEEEFF"
        "rgb(1-255, 1-255, 1-255)"
        "rgba(1-255, 1-255, 1-255, 0-1)"
    路径
        可以被填充多个轮廓或图形的操作。
基本使用
    var context =canvas.getContext("2d");

    context.fill()//填充
    context.stroke()//绘制边框
    context.lineWidth//图形边框宽度

    context.fillStyle//填充的样式
    context.strokeStyle//边框样式
绘制
    矩形
        content.fillRect(x, y, width, height)
        strokeRect(x, y, width, height)         # x, y是起点坐标, width, height为宽和高
    清除矩形区域
        context.clearRect(x,y,width,height)
    圆弧
        context.arc(x, y, radius, startAngle,endAngle, anticlockwise)
            x, y是圆心坐标, radius是半径, startAngle, endAngle是开始、结束弧度, anticlockwise=false时顺时针画圆
            一刻钟是零度, 弧度可以用Math.PI来表示
例子
    矩形
        context.fillRect(0, 120, 100, 100);
        context.strokeRect(120, 120, 100, 100);
        context.clearRect(50, 50, 240, 120);
    圆弧
        context.beginPath();
        ctx.arc(100,75,50,0,1.3 * Math.PI, false);
        context.closePath();
        context.fill();                         # 或ctx.stroke()画线, fill()填充开始点与结束点的连线
image
    var image = ctx.getImageData(0, 0, 256, 256);                   # 取画布矩形区域的图像
    ctx.putImageData(image, 10, 70)             # 把图像复制到画布的一个起点
    例子
        var c=document.getElementById("myCanvas");
        var ctx=c.getContext("2d");
        var imgData=ctx.createImageData(100,100);
        for (var i=0;i<imgData.data.length;i+=4)                    # 一个像素有4个值RGB + alpha, alpha=255表示不透明
        {
            imgData.data[i+0]=255;
            imgData.data[i+1]=0;

            imgData.data[i+2]=0;
            imgData.data[i+3]=255;
        }
        ctx.putImageData(imgData,10,10);

优化 #

canvas.width = canvas.width                     # 一种巧妙的方法清除并重置画布

webgl #

介绍
    由Khronos Group维护                          # 还维护了OpenGL和COLLADA
    使用OpenGL渲染语言GLSL ES
    WebGL是在浏览器中实现三维效果的一套规范
    webgl通过增加openGL es 2.0的一个js绑定, 把它们结合在一起
    webgl可以为html5 canvas提供硬件3d加速渲染
        更流畅地展示3d场景和模型
        创建复杂的导航和数据视觉化
名词
    科纳斯组织       Khronos Group
    GLSL ES         OpenGL Shading Language Embedded System
    网格          Mesh
    模型          model
    纹理映射        texture map
    材质          material
    光源          light
    变换          transform
    相机          camera
    视口          viewport
    投影矩阵       projection matrix
    视锥体         view volume
    视平截头体      view frustum
    着色器         shader
    图元          primitive
    三角形带        triangle strip
    类型化数组       typed array
    模型视图矩阵      modelview matrix
    投影矩阵        projection matrix
    顶点着色器        vertex shader
    片元着色器        fragment shader
    像素着色器        pixel shader, 同fragment shader
    自发光         unlit
    预置光照        prelit
    镜面高光        specular highlights
    镜面反射        specular reflection
    alpha混合        alpha blending
    变换层级        transform hierarchy
    帧动画         frame-based animation
    补间动画        tweening
    关键帧         keyframe
    关键帧动画       keyframe animation
    插值          interpolation
    线性插值        linear interpolation
    关节动画        articulated animation
    蒙皮动画        skinned animation
    骨骼          skeleton
    目标变形动画      morph target animation
    程序贴图        procedural texture
    纹理变换        texture transform
    拾取          picking
    面法线        face normal
    程序贴图        procedural texture
    多级渐进纹理过滤        mipmapping / mipmapping filtering
    数码内容创作软件        DCC        digital content creation
    包围盒        bounding box
框架
    three.js
    physi.js
    glMatrix
    GLGE
    philoGL
    sceneJS
    spiderGL
着色器
工具
    webgl inspector
        # chrome的扩展, webgl调试
网站
    www.khronos.org/webgl/
        # Khronos提供的主页
    learningwebgl.com/blog
    blog.tojicode.com
    https://developer.mozilla.org/en/WebGL
        # mozilla的webgl教程
    www.chromeexperiments.com
        # chrome体验
    www.html5rocks.com
        # 提供html5资源
    www.lao3d.com
        # 国内首个webgl网站

Java

基础 #

历史
    1991.4 Oak
    1995.5 Java1.0 "Write Once, Run Anywhere"
    1996.1 JDK1.0, 纯解释型JVM(Sun Classic VM), Applet, AWT
    1996.5 JavaOne大会
    1997.2 JDK1.1, JDBC, JAR文件格式, JavaBeans, RMI, 内部类(Inner Class), 反射(Reflection)
    1998.12 JDK1.2, 分出J2SE、J2EE、J2ME。JVM内置JIT, EJB, Java Plug-in, Java IDL, Swing, Collections, strictfp关键字
    1999.4 JVM HotSpot
    2000.5 JDK1.3, 数学运算, Timer, JNDI成为平台服务, CORBA IIOP实现RMI, 2D API, JavaSound
    2002.2 JDK1.4, 成熟版本,多公司参与。正则, 异常链, NIO, 日志类, XML, XSLT
        # .NET发布
    2004.9 JDK1.5, 自动装箱, 泛型, 动态注解, 枚举, 变长参数, foreach, 改进内存模型JMM(Java Memory Model), concurrent包
    2006.12 JDK1.6, 改名为Java SE 6, Java EE 6, Java ME 6。动态语言支持(内置Mozilla JavaScript Rhino), 编译API, HTTP服务器API。JVM改进(锁、gc、类加载)
    2006.11 JavaOne Java开源。建立OpenJDK
    2009.2 JDK1.7, OpenJDK1.7和Sun JDK1.7几乎一样。Lambda项目, Jigswa项目(虚拟机模块化), 动态语言支持, GarbageFirst收集器, Coin项目(语言细节进化)。Oracle收购Sun后延迟部分项目。支持Mac OS X和ARM
    2009.4 Oracle收购Sun

    o-> JVM历史
    Sun Classic                 # 1.0到1.3
        解释器
        sunwjit                 # 外挂编译器, 还有SymantecJITt shuJIT等
            编译器和解释器不能同时工作,编译器接管后,要对所有代码编译,不能用耗时稍高的优化,效率低
    Exact VM                    # 1.2到1.3
        使用准确内存管理EMM(Exact Memory Management)而得名
            虚拟机知道内存数据类型, gc时好判断数据是否被使用
            抛弃Classic VM基于handler(句柄关联对象移动地址)的对象查找方式, 每次定位对象少一次间接查找
        两级即时编译器
        与解释器混合工作
    Sun HotSpot VM              # 1.2, Sun JDK和OpenJDK, 来源Strongtalk VM
        EMM
        热点代码探测              # 与解释器协同,平衡最优响应时间和最佳执行性能
            执行计数器找出最有编译价值的代码,通知JIT以方法为单位编译
            方法频繁调用或有效循环多,触发标准编译和OSR(栈上替换)
            不用等待本地代码输出就执行,编译时间压力小,可引入更多优化技术,输出更高效本地代码
    KVM                         # 强调简单、轻量、可移植,但运行慢。Android, iOS前手机平台广泛使用
    CDC-HI VM/CLDC-HI VM        # CDC/CLDC(Connected Limited Device Configuration)希望在移动端建立统一java编译接口, 这是它们的参考实现, Java ME的支柱
    Squawk VM                   # 运行于Sun SPOT(small programmable object technology, 一种手持wifi设备)。java本身实现大部分
    JavaInJava                  # 实验,java实现自身元循环(meta-circular), 需要运行在宿主虚拟机上,没有JIT, 解释运行
    Maxine VM                   # 几乎java实现, 有JIT和gc, 没有解释器,宿主或独立运行,效率接近HotSpot Client VM

    BEA JRockit                 # 专注服务器端,不太关心响应时间,没有解释器
        gc和MissionControl领先
    IBM J9 VM                   # IT4J(IBM Technology for Java Virtual Machine), SmallTalk虚拟机扩展而来, 面向各平台,主要应用于IBM产品

    Azul VM                     # HotSpot改进,Azul Systems公司运行于专有硬件Vega
        每个实例管理数十cpu, 数百GB内存,可控gc时间,对硬件优化线程调度
    Zing JVM                    # Azul VM运行于x86平台
    BEA Liquid VM               # 现在的JRockit VE(virtual edition), BEA运行在自己Hypervisor系统上
        实现专用操作系统的必要功能,如文件系统、网络支持
        虚拟机直接控制硬件, 好处如 线程调度不用切换内核态、用户态等
    Apache Harmony              # 虚拟机,兼容Java1.5、1.6, 没得到TCK认证(Technology Compatibility Kit)兼容性测试的授权
        许多代码吸纳进IBM的JDK1.7和Google Android SDK
    Google Android Dalvik VM    # Android平台核心组成部分之一
        不能直接执行class, 执行dex文件可由class文件转化, 可直接使用大部分Java API
        寄存器架构,非栈架构
        Android2.2提供JIT
    Microsoft JVM               # 微软想垄断Java,Sun打官司令开发停止
    其它
        JamVM, cacaovm, SableVM, Kaffe, Jelatine JVM, NanoVM, MRP, Moxie JVM, Jikes RVM

    o->JDK发行版 
    Open JDK
    Oracle JDK
    IBM JDK
概念
    JDK(java development kit)       # java开发的最小环境
        Java语言
        JVM
        Java API类库
    JRE(java runtime environment)
        JVM
        Java SE API
    平台
        Java Card                        # Applets, 运行在小内存设备
        Java ME(Micro Edition)           # 以前叫J2ME。手机, PDA, 精简API
        Java SE(Standard Edition)        # 以前叫J2SE, 桌面应用, 完整API
        Java EE(Enterprise Edition)      # 企业应用(ERP, CRM), 扩充API(javax包, 有些合入了JavaSE), 部署支持

JDK #

5
    自动装箱拆箱
    枚举类型
    import static
    可变参数
    内省
    泛型
    for增强
    注解
6
    AWT新类Desktop、SystemTray
    JAXB2,把Bean变为XML
    StAX XML处理
    Compiler API动态生成class
    Http Server API, 轻量http容器
    Common Annotations补充, Annotations API
    Console类
    脚本语言引擎: js, groovy, ruby
7
    switch支持String
    泛型推断
        new ArrayList<>()
    AutoCloseable interface,对象销毁时自动调用close()
    FileSystem新方法, 取环境变量
        getJavaIoTempDir()      # IO临时文件夹
        getJavaHomeDir()        # JRE目录
        getUserHomeDir()        # 用户目录
        getUserDir()            # 运行目录
    Boolean加方法
        negate()
        and()
        or()
        xor()
    Character加方法
        equalsIgnoreCase()
    Math加方法,安全计算
        safeToInt()
        safeNegate()
        safeSubtract()
        safeMultiply()
        safeAdd()
    switch case可以匹配String
    数值可下划线, 二进制
        int i = 1_000_000
        int i = 0b1001_1001
    多异常类型
        catch(A|B e){}
    try with resource自动关闭资源
        try (FileInputStream s1 = new FileInputStream(""); FileOutputStream o1 = new FileOutputStream("")) {}
8
    interface default方法
    lambda表达式
    lambda作用域可访问实际final变量, 可访问对象字段和静态变量 
    函数式接口
        @FunctionalInterface
    函数引用
        Converter<String, Integer> f = Integer::valueOf
        User::new
    Predicate类, Function接口, Supplier接口, Consumer接口, Comparator接口, Optional接口
    Stream接口
        filter()...
        Collection
            stream()
            parallelStream()
    Date API
        Clock
            static systemDefaultZone()
            millis()
            instant()
        Date.from(instant)
        ZoneId
            static getAvailableZoneIds()
            static of()
            getRules()
        LocalTime
            static now()
            static of()
            static parse
            plust()...
        LocalDate
            static parse()
        LocalDateTime
            static of()
            toInstant()...
        ChronoUnit.HOURS.between()
        DateTimeFormatter
            static ofLocalizedTime(FormatStyle.SHORT)
            static ofPattern()
            withLocale(Locale.GERMAN)
    多重注解, 同一注解使用多次
        @Repeatable
9
    JDK模块化加载,瘦身
    AOT(Ahead of Time Compilation)
    接口私有方法
    jshell
    try with resource改进
        FileInputStream s1 = new FileInputStream("");
        FileOutputStream o1 = new FileOutputStream("");
        try (s1;o1){}
    下划线不能单独成为变量名,后续会成为关键字
    String从char[]改为byte[]
    stream加强,集合加强
        list.of()
        map.of()
        copyof()
10
    引入var, 只能声明局部变量
        var a = "a";
11
    直接运行源码
        java a.java
    String
        strip()             # 可去除unicode空白字符
        isBlank()           # 长度为0或空格
        repeat(4)           # 重复4次生成新串
    lambda var类型推断
        (var a) -> a
    Optional加强
    InputStream
        transferTo()
    HTTP Client API
12
    switch多值(preview)
        switch(a) {
            case 1,2,3 -> a;
        }
13
    switch返回值(preview)
        String s = switch(a) {
            case 1 -> "a";
        }
    文本块(preview)
        String s = """
            abc
            """;
14
    instanceof模式匹配(preview)
        if (o instanceof Integer i){
            i++;
        }
    空指针定位到对象        # a().b().c的情况
        -XX:+ShowCodeDetailsInExceptionMessages
    record类型(preview)
        public record User(String name, Integer age){}
    jpackage
15
    sealed类(preview), 限制子类继承
        public sealed class Animal permits Cat, Dog {}
        public final class Cat extends Animal {}
        public sealed class Dog extends Animal permits Husky {}
        public final class Husky extends Dog {}
    CharSequence interface添加default isEmpty()
    TreeMap添加方法
        putIfAbsent()
        computeIfAbsent()
        computeIfPresent()
        compute()
        merge()
    正式版: 文本块
16
    包装类编译时警告
        Integer i = new Integer(1)
        synchronized(i){}
    获取AM或PM
        DateTimeFormatter.ofPattern("B").format(LocalDateTime.now())
    InvocationHandler添加方法
        invokeDefault()     # 调interface default方法
    JVM优化: ZGC并发栈处理,弹性metaspace
    Stream
        toList()
    正式版: record类型、instanceof模式匹配、jpackage
17, LTS版
    去掉AOT、GraalVM的JIT
    switch模式匹配(preview)
        switch(a) {
            case B b -> b.b();
            case null -> ;
        }
    伪随机数增加interface, 用于使用stream
        RandomGeneratorFactory
        RandomGenerator, 由Random和ThreadLocalRandom继承

    正式版: sealed类
21, LTS版

命令与工具 #

bin
    javac           #  编译器
    java            #  解释器
        -jar a.jar
            --spring.config.location=/application.yml 
            --spring.profiles.active=prod 
                # 指定spring config
            -Xmx2g
            -Dserver.port
                # 覆盖properties
    javadoc         #  生成HTML格式的帮助文档
        javadoc -d docs -sourcepath src/ -subpackages com.ryx -author
    jdb             #  java调试器
    javah           #  反编译成c头文件
    javap           #  反编译成java文件
    jar             #  打包工具
        打包标签
            把包目录和class类放到jnb目录
            jnb/META-INF/tld文件添加<uri>http:# www.xxx.com</uri>
            jar cvf jnb.jar *
        jar cvfm ul.jar manifest.mf com
    native2ascii    #  转换为unicode编码
    serialver       #  返回指定类的序列化号serialverUID
    appletviewer    #  小程序浏览器,执行HTML文件上java小程序类
    htmlconverter   #  转换applet tags成java plug-in
    javap           # 反编译
    jad             # 反编译
        jad -o -a d.java Xxx.class
    jps                                 # 查java进程
    jinfo                               # 输出、修改opts
    jstat                               # 性能分析
        -option                         # 查看分析项
        -class                          # 加载class的数量
        -compiler                       # 实时编译数量
        -gc                             # gc次数,时间
        -gccapacity                     # gc占量: young、old、perm
        -gcnew                          # new对象数量
        -gcnewcapacity                  # new对象占量
        -gcutil                         # gc统计
    jmap                                # 内存分配
    jconsole                            # 图形统计:heap, threads, classes, cpu, VM summary
    jstack                              # 查看线程(如死锁),得到java stack和native stack
工具
    MAT (Memory Analyzer)
        # eclipse MAT插件分析dump文件
    JProfiler
        # 图形化全面性能分析
常见场景
    分析GC效果,内存泄漏
        jstat -gcutil -t -h8 [pid] 1000
    dump内存
        jmap -dump:live,format=b,file=heap.bin [pid]
    查死锁
        jstack |grep deadlock            # deadlock会列在最后
    CPU占用
        top
        top -Hp [pid]
        printf '%x' [tid]
        jstack [pid] | grep [16进制tid] -A 10

语法 #

基础 #

类型
    基本类型
        # 作为面向对象语言,为了方便引入了基本类型
        boolean 1或4字节
            # 没有定义类型的字节码,跟据jvm实现有时用int代替
            # 据说[]boolean是1个,boolean直接用int类型是4个
        byte  1个字节
        short 2个字节
        char  2个字节
            # gbk, gb2312这种2字节编码,一个汉字存一个char。utf-8一个字用3字节
        int   4个字节
        long  8个字节
        float 4个字节
        double 8个字节
    包装类型
        # 不可变(immutable)类
        Boolean, Byte, Short, Character, Integer, Long, Float, Double
        享元
            Integer i1 = 120, i2 = 120, i3 = 130, i4 = 130;
            i1 == i2; i3 != i4
                # 数字小于1字节(-128 -- 127)后 , 内部存在IntegerCache中,这是一种享元模式
        自动折装箱(java5)
            Integer iObj = 3;        # 装箱
            iObj + 12;            # 折箱
    字符串
        # 不可变(immutable)类, 用cahr数组实现
        字面量处理 String str = "abc"
            # String s = new String("abc") 放堆里
            定义引用变量str
            栈中查找"abc", 有则返回地址,没有则开辟地址,再创建String对象,对象指向该地址, 该地址标记对象引用
                # 放在栈的静态区(static segement)里
            str指向地址, 所以str保存了一个指向栈中数据的引用
        "a"+"b" 会编译成使用StringBuilder
            # 循环中会重复创建
    泛型
        字面量
            Map<String, Integer> a = new HashMap<>();               # 后面的菱形操作符做了类型推断
            f(new HashMap<>)                                        # 传值使用菱形操作符

引用
    强引用(strong reference)
        String s = new String("")
    软引用(soft reference)     # 内存不足时回收
        # 用来实现内存敏感的高速缓存, 如object-cache,为了能cache又不会内存不足
        SoftReference<String> softRef = new SoftReference<String>(s)
        回收
            将softRef引用referent(s)设为null,不再引用new String("")
            new String("")设置为可结束(finalizable)
            new String("")运行finalize(),空间释放。softRef添加到它的ReferenceQueue(如果有)
    弱引用(weak reference)     # 表示可有可无, gc扫描到随时回收
        WeakReference<String> weakRef = new WeakReference<String>(s)
    虚引用(PhantomReference)   # 形同虚设,像没引用,用来跟踪垃圾回收活动
        ReferenceQueue<String> queue = new ReferenceQueue<>()
        PhantomReference<String> phantomRef = new PhantomReference<String>(s, queue)
        # 必须和ReferenceQueue联合使用
        # 可以通过判断ReferenceQueue是否有虚引用,来了解被引用对象是否将要被回收
修饰
    volatile    # 类型修饰符,告诉jvm该变量在寄存器/工作内存中值是不确定的
        # 没有原子性
        # 不会造成线程阻塞
        # 读性能几乎不变,写稍慢,因为插入内存屏障来保证不乱序执行
        对所有线程可见(可见性,线程的修改对其它线程可见)
            # 跳过cpu cache,新值立即同步到内存, 使用前从内存刷新
        禁止编译器指令重排序优化
    synchronized    # 锁当前变量、方法、类,只有当前线程可用
        # 保证可见性和原子性
语句
    ==
        # 基础类型比较数值,引用类型比较地址
    +1 与 += 1
        short s1 = 1; s1 = s1 + 1   # 出错,类型变为int
        s1 += 1     # 相当于 s1 = (short)(s1 + 1)
    + ""    # 编译成StringBuilder实现
    goto和const是保留字但没有使用
    标签
        label1:
        for(; true; ) {
            break lable1;
            // continue lable1;
        }
    增强for循环(1.5)
        for(int i : args){
            sum += i;
        }
    同步
        public synchronized void synMethod(){}
        synchronized(a1){}
    switch
        expr类型
            1.5前只能byte, short, char, int
            1.5可以枚举
            1.7可以String
            long目前不可以
表达式
    java赋值语句返回被赋值的对象
    & 与 &&
        &是 按位与,逻辑与(后面会计算)
        &&是 短路与
    | 与 ||
        # 同上
    lambda表达式                                                     # 为了便于并行编程, 提高语法的抽象级别
        字面量
            () -> o.f()
            () -> {
                o.f()
            }
            event -> o.f()
            (x, y) -> x + y
            (Long x, Long y) -> x + y

            f(O::f1)                                                # 简化 f((o) -> o.f1())
        类型
            Predicate<T>
                Predicate<String> condition = (s) -> s.length() > 4);
                if (condition.test(s)) {}

                Predicate<String> a = (s) -> s.length() > 1; b = (s) -> s.length() > 2;
                Predicate<String> c = a.and(b)
            Consumer<T>
            Function<T, R>
            Supplier<T>
            UnaryOperator<T>
            BinaryOperator<T>
        特点
            参数类型推断
            作为匿名内部类
                button.addListener(event -> o.f())
            引用外部变量时,不一定声明final, 但要是即成事实(effectively)的final变量(不能重复赋值)
            重载解析参数类型时,找最具体类型。
                无法推断时报错, 如                                    # 重定义方法名或传入时做强转
                    f(Predicate<Integer> p)
                    f(IntPredicate p)
声明
    静态导入(1.5)
        import static java.lang.Math.max
        import static java.lang.Math.*
            # 导入的是方法,该方法就可以直接使用
方法
    修饰
        开放性
            修饰符     当前类     同包      子类      其他包
            public       √        √        √          √
            protected    √        √        √
            无           √        √
            private      √
        default修饰接口默认方法(虚方法)
    方法参数都是值传递,无法改变外部的参数本身
    可变参数(1.5)
        public void sum(int x, int... args)
    static方法初始化先于构造方法
    overload与override
        重载
            父类、同类、子类中比较
            方法名一致,入参有变化
            返回值不影响
                # 为副作用调用时(忽略返回值)考虑
            修饰符、异常声明不影响
        重写
            入参,出参一致
            构造方法、final方法不能被重写
            static方法不能被重写,可再次声明
            访问权限不能缩小
            异常声明不扩大,可加非强制异常
    finally
        # return前走finally, catch块中也一样
类
    字面量
        public class A {{
            ...
        }}
            这是匿名构造函数,相当于:
                public class A {
                    public A() {
                        ...
                    }
                }
    接口
        不能定义构造函数
        只定义抽象方法
        类成员全部public
        定义的实际上都是常量
        不能定义静态方法
        类可实现多接口
        函数接口,接口声明默认方法
        default方法
            Collection中添加stream()会打破前版本二进制兼容性(原版本找不到stream而报错),默认方法指定找不到时使用的方法, 维护兼容性
            可被其它接口继承重写
            多重继承
                继承代码块,不继承类状态(属性)                         # 有些人认为多重继承的问题在于状态的继承
                冲突报错, 可子类重写解决
            优先级: 子类 > 类 > 接口
    抽象类
        # 有抽象方法的类
        可定义构造函数
        可定义抽象方法和具体方法
        成员可以是private, default, protected, public
        可定义成员变量
        可定义静态方法
        类只继承一个抽象类
    接口与抽象类
        不能实例化
        可作为引用类型
        继承的类要实现所有抽象方法,否则还是抽象类
    抽象方法
        不能static,static方法不能被重写
        不能native,native需要实现
        不能synchronized,synchronized表示一种实现方式
    静态变量
        # 实例变量属于对象实例,有多个
        属于类,只有一个,实现共享内存
    内部类
        静态嵌套类(static nested class), 可不依赖外部类实例被实例化
        内部类,外部类实例化后才能实例化
            new Outer().new Inner()     # 在Outer类中也不能new Innter()
注解
    @FunctionalInterface                        # 检查是否符合函数接口标准
安全性
    安全沙箱机制
        类加载体系
        .class文件检验器
        JVM及语言的安全特性
        安全管理器与java api

异常 #

异常机制
    运行时出现错误,控制权交给异常处理器
    方法立即结束,抛出一个异常对象。调用该方法的程序停止,搜索处理代码

Throwable
    Error
        # JVM相关问题,如系统崩溃、虚拟机错误、内存不足、方法调用栈溢出
    Exception
        # 指可处理的异常
        RuntimeException
            # 非强制(unchecked)。除RuntimeException都是强制异常(checked)
Error
    java.lang.OutOfMemoryError      # 内存溢出
    java.lang.StackOverflowError        # 堆溢出

运行时异常
    ArithmeticExecption     # 算术异常类
    IllegalArgumentException    # 方法传递参数错误
    NullPointerException        # 空指针异常类
    ClassNotFoundException  # 类找不到,加载路径错误
    ClassCastException      # 类型强制转换异常
    NoClassDefFoundException    # 未找到类定义
    ArrayIndexOutOfBoundsException      # 数组越界异常
    ArrayStoreException      # 数组存储异常,操作数组时类型不一致
    BufferOverflowException     # 缓冲溢出异常
    NegativeArrayException      # 数组负下标异常
    NoSuchMethodException       # 方法未找到异常
    IllegalStateException     # servlet过滤器中 chain.doFilter中request,response类型为ServletRequest,ServletResponse时出错
    NumberFormatException   # 字符串转换为数字异常
    SQLException        # sql语句出错
    InstantiationException      # 实例化异常
    DateTimeException   # 无效时间

强制异常
    FileNotFoundException       # 文件未找到异常
    ParseException      # 解析时间字符串到时间类型出错
    ServletException        # servlet转发时出现过该异常
    IOException     # io异常
    java.sql.BatchUpdateException       # sql批处理
    com.mysql.jdbc.MysqlDataTruncation      # mysql 插入数据被截断,插入数据过长时遇到

注解 #

# annotation (1.5特性)
jdk的注解
    @SuppressWarnings("deprecation")        # 压制警告
        # SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,
        # 参数如下
        all to suppress all warnings
        boxing to suppress warnings relative to boxing/unboxing operations
        cast to suppress warnings relative to cast operations
        dep-ann to suppress warnings relative to deprecated annotation
        deprecation to suppress warnings relative to deprecation
        fallthrough to suppress warnings relative to missing breaks in switch statements
        finally to suppress warnings relative to finally block that don’t return
        hiding to suppress warnings relative to locals that hide variable
        incomplete-switch to suppress warnings relative to missing entries in a switch statement (enum case)
        nls to suppress warnings relative to non-nls string literals
        null to suppress warnings relative to null analysis
        rawtypes to suppress warnings relative to un-specific types when using generics on class params
        restriction to suppress warnings relative to usage of discouraged or forbidden references
        serial to suppress warnings relative to missing serialVersionUID field for a serializable class
        static-access to suppress warnings relative to incorrect static access
        synthetic-access to suppress warnings relative to unoptimized access from inner classes
        unchecked to suppress warnings relative to unchecked operations
        unqualified-field-access to suppress warnings relative to field access unqualified
        unused to suppress warnings relative to unused code

    @Deprecated                             # 标记过时
    @Override
元注解(metadata)
    @Retention(RetentionPolicy.RUNTIME)
        # 保留策略 CLASS、RUNTIME和SOURCE这三种,分别表示注解保存在类文件、JVM运行时刻和源代码阶段
        # 只有当声明为RUNTIME的时候,才能够在运行时刻通过反射API来获取到注解的信息。
    @Target用来声明注解作用目标,如类型、方法和域等。如
        @Target(ElementType.TYPE)  //接口、类、枚举、注解
        @Target(ElementType.FIELD) //字段、枚举的常量
        @Target(ElementType.METHOD) //方法
        @Target(ElementType.PARAMETER) //方法参数
        @Target(ElementType.CONSTRUCTOR)  //构造函数
        @Target(ElementType.LOCAL_VARIABLE)//局部变量
        @Target(ElementType.ANNOTATION_TYPE)//注解
        @Target(ElementType.PACKAGE) ///包
    @Document:说明该注解将被包含在javadoc中
    @Inherited:说明子类可以继承父类中的该注解
自定义注解
    # @interface用来声明一个注解
    ## 其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型。可以通过default来声明参数的默认值。
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface Assignment {
        String assignee();
        int effort();
        double finished() default 0;
    }

版本特性 #

java8
    接口中可以定义静态方法与默认方法
        不能重写equals,hashCode或toString的默认实现。
    Lambdas
        # Lambda更好地利用多核处理器
        与匿名内部类
            匿名内部类编译成.class文件,lambda表达式编译成私有方法, 使用invokedynamic(java7)字节码指令动态绑定
                private static java.lang.Object lambda$0(java.lang.String)
            匿名内部类this指向该匿名内部类, lambda的this总指向所有的外部类
        内部变量
            可以使用静态、非静态局部变量
            只能引用final和局部变量,不能修改外部变量     # 不可变闭包
        注解
            @Functionalnterface     # 函数式接口
                有且公有一个抽象方法      # SAM(single abstract method)
                允许定义静态方法、默认方法、Object中的public方法
                不是必须的,接口符合以上定义就算函数式接口
        函数
            (int x, int y) -> { return x + y; }
            Runnable r = () -> { System.out.println("Running!"); }
        SAM
            new Thread(() -> System.out.println(""))
                # Thread有单个抽象方法run()
        列表
            list1.forEach(System::out::println)
    java.util.function包
        # 声明于function包内的接口可接收lambda表达式
        Predicate
        Stream
    Optional
    Jigsaw
        # jdk上的模块系统,使大块的代码更易于管理

java7
    switch中可以使用字符串了
    运用List<String> tempList = new ArrayList<>(); 即泛型实例化类型自动推断
    语法上支持集合,而不一定是数组
        final List<Integer> piDigits = [ 1,2,3,4,5,8 ];
    map集合支持并发请求,且可以写成
        Map map = {name:"xxx",age:18};
java6
    ui增强
        Java应用程序可以和本地平台更好的集成
    web service支持增强:jax-ws2.0与jaxb2.0
        优先支持编写 XML web service 客户端程序。
        用过简单的annotaion将你的API发布成.NET交互的web services.
    jdbc4.0
    Scripting可以在Java源代码中混入JavaScript

java5
    泛型,允许指定集合里元素的类型
    枚举类型
    自动类型包装和拆包
    可变参数
    注解
    增强for循环
    静态引入
    新的线程模型与并发库
        HashMap的替代者ConcurrentHashMap
        ArrayList的替代者CopyOnWriteArrayList

api #

Object #

clone()
    # 开始与new相同分配内存, 然后填充对象的域。是浅拷贝
    深拷贝
        class Body implements Cloneable {
            @Override
            protected Object clone() throws CloneNotSupportedException {
                body = (Body) super.clone()
                body.head = (Head)head.clone()
                return body
            }
        }
equals()
    # 具有自反性、对称性、传递性、一致性
    # 先确定hashCode一致,equals相等的对象hashCode一定相等
    # 没重写时比较地址
    重写equals
        1 == 检查是否引用
        2 instanceof 检查类型
        3 属性是否匹配
        4 是否满足对称性、传递性、一致性
        5 总要重写hashCode
finalize()
    # 垃圾收集时调用
valueOf()   # 转换成自己类型
wait()
notify()
notifyAll()

系统 #

System
    currentTimeMillis();
        # Clock.systemDefaultZone().millis()  # java8
    arraycopy()
File
    String[] list()            # 列出目录下的所有文件名
    String[] list(FilenameFilter filter)            # 列出目录下符合filter规范的文件名(filter用匿名内部类定义)
Scanner
    next()
        例如:
        Scanner input = new Scanner(System.in);
        int data = input.nextInt();
        System.out.println(data);
    得到继承结构
        StackTraceElement [] stackTraces = new Throwable().getStackTrace();
        for(StackTraceElement temp : stackTraces){
        temp.getClassName()
        temp.getFieldName();
        temp.getMethodName();
        }
Cloneable接口
    clone()

包装类型 #

parseXxx(String)    # 从字符串转换
valueOf(String)     # 从字符串转换

String #

# final类,不可继承
length()
    # String length是方法, 数组length是属性
isEmpty()
indexOf()
lastIndexOf()
chatAt()
substring()
trim()
toLowerCase()
toUpperCase()
split()
getBytes()
replaceAll()
    String p = "A0A1A2".replaceAll("([A-Z]{1,1})([A-Z0-9]{1,1})?", "$1=$2 ");
    # A=0 A=1 A=2
    ## $符是组的概念,与"([A-Z]{1,1})([A-Z0-9]{1,1})?"中的两对括号代表两组
    ## {1,1}代表匹配1次, (从1次到1次)
    replaceAll("[A_Z]", "_$0")            # 分组匹配被替换的值到替换字符串中

类
    StringBuffer
        # 线程安全
        append()
        insert()
    StringBuilder
        # 1.5引入
    intern()
        # 返回常量池中的引用(String对象equals池中某对象为true),没有时添加

正则 #

Pattern
[abc]
[^abc]
[a-zA-Z]
[a-z&&[def]]
[a-z&&[^bc]]    =    [ad-z]
[a-z&&[^m-p]]    =    [a-lq-z]
.除了换行符之外的任意字符
\d    [0-9]
\D    [^0-9]
\s    [ \t\n\x0B\f\r]
\S    [^\s]
\w    [a-zA-Z_0-9]
\W    [^\w]

posix的字符
\p{Lower}        [a-z]
\p{Upper}        [A-Z]
\p{ASCII}        [\x00-\x7F]
\p{Alpha}        [\p{Lower}\p{Upper}]
\p{Digit}        [0-9]
\p{Alnum}        [\p{Alpha}\p{Digit}]
\p{Punct}        !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~    之一
\p{Graph}        [\p{Alnum}\p{Punct}]所有可见字符
\p{Print}        [\p{Graph}\x20]    \x20为空格
\p{Blank}        [ \t]    一个空格或tab
\p{Cntrl}        [\x00-\x1f\x7f]    控制字符
\p{XDigit}        [0-9a-fA-F]    十六进制符号
\p{Space}        [ \t\n\x0B\f\r]

代表边界的字符
^        行首
$        行尾
\b        A word boundary
\B        A non-word boundary
\A        input的开始
\G        The end of the previous match
\Z        The end of the input but for the final terminator,if any
\z        The end of the input

Greedy 定量
X?        0或1个
X*        0或多个
X+        1或多个
X{n}        n个
X{n,}    最少n个
X{n,m}    n到m,包含n,m

Logical operators
XY        XY
X|Y        X或Y
(X)        捕获的匹配
\n        得到第n个捕获

Quotation
\        Nothing, but quotes the following character
\Q        Nothing, but quotes all characters until \E
\E        Nothing, but ends quoting started by \Q

Special constructs (non-capturing)
(?某某)

* 方案
* 任意字符

    [\S\s]        # 匹配空格或非空格,就是任意一个字符
        ## [\W\w] 相同

* 匹配多个
    Pattern p1 = Pattern.compile("\\(.*?\\)");
        Matcher m1 = p1.matcher("kjdjdjj(738383)ddk(9999)ppp");
        while (m1.find()) {
            System.out.println(m1.group().replaceAll("[()]", ""));
        }

Math #

round
    # 四舍五入, -11.5得到11

时间 #

java8的新时间类实现JSR-310
    特点
        不变性, 内部状态不变、线程安全
        关注点分离,定义了不同的类:Date, Time, DateTime, timestamp, 时区
        策略模式,所有类定义format()和parse()方法
        实用方法,所有类定义了方便操作的方法
        扩展性,使用ISO-8601日历系统,也可扩展在其它系统
    包
        java.time       # 基础包
        java.time.chrono     # 非ISO日历系统的泛化api
        java.time.format    # 格式化和解析,基本不用(基础包有封装)
        java.time.temporal  # 时态对象,用来改变时间
        java.time.zone      # 时区相关类
    JSR-310
        精确到纳秒
        对应人类观念,也不是像Date一样用零点时间表示日期
        大部分基于Joda-Time,区别:
            包名从org.joda.time到java.time
            不接受null值,Joda-Time视null为0
            机器用Instant和人用DateIme接口差别更明显
            所有异常继承DateTimeException
    方法
        Of  # 静态工厂
        parse   # 静态解析
        get
        is
        with    # 设置时间,不可变
        plus
        minus
        to      # 转换类型
        at      # 组合对象
Calendar
    getInstance()
    get(Calendar.YEAR)   # YEAR, MONTH, DATE, HOUR_OF_DAY, MINUTE, SECOND
    getTimeInMillis()   # 时间戳,毫秒
    getTime()
    set()   # 设置到时间
    使用
        Calendar c = Calendar.getInstance()
        c.set(Calendar.DAY_OF_MONTH, 1)     // 月第一天
        c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH))     // 月最后一天
        System.out.println(format.format(c.getTime(0))
        c.add(Calendar.DATE, -1)    // 昨天
SimpleDateFormat
    format(Date)
    使用
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd")
        System.out.println(formatter.format(new Date()))
LocalDate     # java8, 默认格式(yyyy-MM-dd)
    now()
        LocalDate.now()
        LocalDate.now(ZoneId.of("Asia/Kolkata"))   // 时区时间
    of()    # 指定时间
    ofEpochDay()  # 纪元日(1970.1.1)后多少天
    ofYearDay()   # 年后多少天

    minusDays()
        today.minusDays(1)  # 昨天
    isLeapYear()    # 闰年
    isBefore()  # 比较大小
    atTime()    # 返回LocalDateTime
    plusDays()
    plusWeeks()
    plusMonths()
    minusDays()
    minusWeeks()
    minusMonths()
    with()      # 定位时间
        today.with(TemporalAdjusters.irstDayOfMonth())
        today.with(TemporalAdujsters.lastDayOfYear())
    until()     # 返回Period
    使用
        LocalDate today = LocalDate.now()
        LocalDate firstday = LocalDate.of(today.getYear(), today.getMonth(), 1)     // 月第一天
        LocalDate lastDay = today.with(TemporaAdjusters.lastDayOfMonth())       // 月最后一天
        System.out.println(lastDay)
LocalTime     # java8, 默认格式(hh:mm:ss.zzz)
    now()
    of()
    ofSecondOfDay()     # 从0开始多少秒后
LocalDateTime   # java8,默认格式(yyyy-MM-dd-HH-mm-ss.zzz)
    now()
    of()
        LocalDaeTime.of(LocalDate.now(), LocalTime.now())
        LocalDateTime.of(2014, Month.JANUARY, 1, 10, 10, 30)
    ofEpochSecond()
    ofInstant()
    parse()     # 按格式parse字符串
        LocalDateTime.parse("27::Apr::2014 21::39::48", DateTimeFormatter.ofPattern("d::MMM::uuuu HH::mm::ss"))

    getYear()
    getMonthValue()
    getDayOfMonth()
    getHour()
    getMinute()
    getSecond()
    minusDays()
    plush()
ZonedDateTime
    now()
    parse()
        ZonedDateTime.parse("2013-12-31T23:59:59Z[Europe/Paris]")
Clock     # java8
    systemDefaultZone()
    systemUTC()
    system(ZoneId.of("Europe/Paris"))
    fixed(Instant.now(), ZoneId.of("Asia/Shanghai"))    # 固定时区
    offset(c1, Duration.ofSeconds(2))   # 偏移

    millis()        # 时间戳
Instant     # java8, 机器可读格式,精确到纳秒
    now()
        now(clock1)     # 得到瞬间时间
    ofEpochMilli

    toEpochMilli()
    getEpochSecond()
Duration        # java8, 时间段
    between()
    ofDays()

    toDays()
    toHourse()
Period      # java8
    getMonths()     # 算成月数
DateTimeFormatter   # java8
    BASIC_ISO_DATE
    ofPatter()
    使用
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd")
        System.out.println(LocalDate.now().format(formatter))
Chronology  # java8 年表
    localDateTime(LocalDateTime.now())

    类
        HijrahChronology
            INSTANCE
新旧转换
    // Date, Instant, LocalDateTime
    Instant timestamp = new Date().toInstant()
    LocalDateTime date = LocalDateTime.ofInstant(timestamp, ZoneId.of(ZoneId.SHORT_IDS.get("PST")))
    Date date = Date.from(Instant.now())

    // Calendar, Instant
    Instant time = Calendar.getInstance().toInstant()

    // TimeZone, ZoneId
    ZoneId defaultZone = TimeZone.getDefault().toZoneId()
    TimeZone timeZone = TimeZone.getTimeZone(defaultZone)

    // GregorianCalendar, ZonedDateTime
    ZonedDateTime gCalendarDateTime = new GregorianCalendar().toZonedDateTime()
    GregorianCalendar gCalendar = GregorianCalendar.from(gCalendarDateTime)

数组 #

length
    属性
newInstance()
    泛型数组实例化
        T[] = (T[]) new Object[0];
        (T[]) Array.newInstance(type, size);

枚举 #

# 枚举类型的比较取决于声明顺序
举类的实现类
    java.lang.Enum<E> extends Object
        static <T extends Enum<T>> T valueOf(Class<T> enumType, String name)

    javax.lang.model.element.ElementKind extends java.lang.Enum<ElementKind>
        # 实际创建枚举类型时继承的类
        # 此类的静态方法不是Enum本身的方法,所以它们在java.lang.Enum的javadoc中没有出现。
        static ElementKind valueOf(String name)
            # 为提供的字符串返回一个枚举类型,该枚举类型必须精确地匹配源代码声明。
        static ElementKind[] values()
            # 返回一个枚举类型所有可能值的数组。

定义1
    public enum Color {
    RED, GREEN, BLANK, YELLOW
        # 元素列表必须在最前, 如果元素列表后面没有东西的话,可以省略分号
        // 枚举的构造方法必须是私有的
        // private WeekDay() {
        //}
    }

定义2
    enum Signal {
    GREEN, YELLOW, RED
    }

定义3
    自定义构造(要注意必须在enum的实例序列最后添加一个分号)
    public enum Color {
        RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
        // 成员变量
        private String name;
        private int index;
        // 构造方法
        private Color(String name, int index) {
            this.name = name;
            this.index = index;
        }
        // 普通方法
        public static String getName(int index) {
            for (Color c : Color.values()) {
            if (c.getIndex() == index) {
                return c.name;
            }
            }
            return null;
        }
        // get set 方法
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public int getIndex() {
            return index;
        }
        public void setIndex(int index) {
            this.index = index;
        }
    }
使用
    public enum TrafficLamp {
        RED(30) {

            @Override
            public TrafficLamp nextLamp() {
                return GREEN;
            }
        },
        GREEN(45) {
            @Override
            public TrafficLamp nextLamp() {
                return YELLOW;
            }
        },
        YELLOW(5) {
            @Override
            public TrafficLamp nextLamp() {
                return RED;
            }
        };
        public abstract TrafficLamp nextLamp();

        private int time;

        private TrafficLamp(int time) {
            this.time = time;
        }
    }
    @Test
    public void testHere() {
        WeekDay weekDay = WeekDay.MON;
        weekDay.toString();
        weekDay.name();
        // 排行
        weekDay.ordinal();
        WeekDay.valueOf("SUN");
        WeekDay.values();
    }
自己实现
    public abstract class WeekDay {
        private WeekDay() {
        };

        /*
        * public WeekDay nextDay(){ if(this == SUN){ return MON; }else { return
        * SUN; } }
        */

        public abstract WeekDay nextDay();

        public final static WeekDay SUN = new WeekDay() {

            @Override
            public WeekDay nextDay() {
                return MON;
            }
        };
        public final static WeekDay MON = new WeekDay() {

            @Override
            public WeekDay nextDay() {
                return SUN;
            }
        };

        @Override
        public String toString() {
            return this == SUN ? "SUN" : "MON";
        }
    }
使用接口组织枚举
    public interface Food {
    enum Coffee implements Food{
        BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
    }
    enum Dessert implements Food{
        FRUIT, CAKE, GELATO
    }
    }
用switch判断
    # JDK1.6之前的switch语句只支持int,char,enum类型
    enum Signal {
    GREEN, YELLOW, RED
    }
    public class TrafficLight {
    Signal color = Signal.RED;
    public void change() {
        switch (color) {
        case RED:
        color = Signal.GREEN;
        break;
        case YELLOW:
        color = Signal.RED;
        break;
        case GREEN:
        color = Signal.YELLOW;
        break;
        }
    }
    }
枚举的集合
    java.util.EnumSet    # 集合中的元素不重复
    java.util.EnumMap    # key是enum类型,而value则可以是任意类型。

Collection #

继承结构
    <<Collection>>
        <<Queue>>
            PriorityQueue
            <<Deque>>
                ArrayDeque
        <<List>>
            ArrayList
            LinkedList  # 实现<<Deque>>
            Vector
                Stack
        Set
            HashSet
            EnumSet
            <<SortedSet>>
                TreeSet
    <<Map>>
        HashMap
        LinkedHashMap
        <<SortedMap>>
            TreeMap
Arrays
    fill()                      # 赋初值
    asList()                    # 数组转List
    sort()
    binarySearch()
    equals()                    # 数组比较
    parallelPrefix()            # 前值和,如0, 1, 2, 3 处理后为 0, 1, 3, 6。
    parallelSetAll()            # 修改值
    parallelSort()
ArrayList
    # 用数组实现,查询快,增删慢
    toArray() # 返回list中的所有元素作为一个Object []
    toArray(T[] a)  # 返回泛型类型的list中的所有元素

    trimToSize()    # 优化掉删除出现的空位

    stream()
    parallelStream()  # 并行流
    实现
        public ArrayList() {
            array = EmptyArray.OBJECT;
        }
        public ArrayList(int capacity) {
            if (capacity < 0) {
                throw new IllegalArgumentException("capacity < 0:" + capacity);
            }
            array = (capacity == 0 ? EmptyArray.OBJECT : new Object[capacity]);
        }
        public ArrayList(Collection<? extends E> collection) {
            if (collection == null) {
                throw new NullPointerException("collection == null");
            }

            Object[] a = collection.toArray();
            if (a.getClass() != Object[].class) {
                Object[] newArray = new Object[a.length];
                System.arraycopy(a, 0, newArray, 0, a.length);
                a = newArray;
            }
            array = a;
            size = a.length;
        }
        @Override
        public boolean add(E object) {
            Object[] a = array;
            int s = size;
            if (s == a.length) {
                Object[] newArray = new Object[s +
                (s < (MIN_CAPACITY_INCREMENT / 2) ?
                MIN_CAPACITY_INCREMENT : s >> 1)];
            System.arraycopy(a, 0, newArray, 0, s)
            array = a = newArray;
            }
            a[s] = object;
            size = s + 1;
            modCount++;     // 修改次数
            return true;
        }
        @Override
        public E remove(int index){
            Object[] a = array;
            int s = size;
            if (index >= s) {
                throwIndexOutOfBoundsException(index, s);
            }
            @SuppressWarnings("unchecked")
            E result = (E) a[index];
            System.arraycopy(a, index + 1, a, index, --s - index);
            a[s] = null;
            size = s;
            modCount++;
            return result;
        }
        @Override
        public void clear() {
            if (size != 0) {
                Arrays.fill(array, 0, size, null);
                size = 0;
                modCount++;
            }
        }
LinkedList
    # 循环双向链表实现,增删快,查询慢

    类
        Entry
Vector
    # 数组实现,线程安全,增删慢,查询慢

HashMap
    # hash表实现,支持null的键和值
    实现
        数组存Entry, 位置称为bucket
        Entry为元素,单链表拉链解决碰撞
        hashcode(key)得到bucket索引
        扩容要rehash
    类
        Entry

    computeIfAbsent()                                               # 无值时用计算新值
    forEach()
LinkedHashMap
    # 继承HashMap,hash表和链表实现,保存了插入顺序
HashTable
    # 线程安全,不支持null的键和值
TreeMap
    # 红黑树实现,有序,实现SortedMap接口

HashSet
    # HashMap实现,有时需要重写equals()和hashCode()
    # HashSet先按hashCode分区, 后比较equals的值再存放。修改参与hashCode值运算的属性后, 该元素删除会因无法定位,导致内存泄漏
LinkedHashSet
    # 继承HashSet。LinkedHashMap实现
List、Map、Set区别
    List、Set单列,Map双列
    List有序可重复, 可索引, Map无序,键不重复,值可重复,Set无序,不重复
Queue
    Queue<String> queue = new LinkedList<String>();
    queue.offer("a");            # 添加
    queue.poll();                # 返回第一个元素并删除
    queue.element();            # 返回第一个元素, empty时抛异常
    queue.peek();                # 同element(), 但empty时返回null
Collections
    sort(List, Comparator)
    synchronizedCollection()
        # 线程不安全集合方法调用前加锁
    synchronizedList()
    synchronizedMap()
    synchronizedSet()

#

函数流特点
    Iterator是外部迭代,串行化操作。Stream是内部迭代, 自动并行处理
    方法分惰性和及早执行
    有序集合有序处理,无序集合无序处理
Stream
    of()                                                            # 静态方法,产生流

    forEach()
    collect()                                                       # 用收集器, 转出结构化数据
        collect(Collectors.toList())                                # 转出List
    map()
        map(s -> s.toUpperCase())
    reduce()
        reduce(0, (acc, element) -> acc + element)                  # acc是累加器
    filter()
        filter(s -> isDigit(s.charAt(0)))
    flatMap()                                                       # 平铺多stream
        flatMap(numbers -> numbers.stream())
    min()
        min(Comparator.comparing(track -> track.getLength()))
    max()
    peek()
    get()                                                           # 执行得到结果
    count()

    mapToInt()                                                      # IntStream, LongStream, DoubleStream, 对基本类型做特殊优化(如不装箱占内存)
IntStream
    range(0, N)
    sequential()                                                    # 串行
    parallel()                                                      # 并行, fork-join结构。注意数据结构(arrayList快于linkedList)。有状态操作会线程通信, 如sorted, distinct, limit
    mapToObj()
    summaryStatistics()
IntSummaryStatistics
    getAverage()
Optional
    of("a")
    ofNullable(null)
    empty()

    get()                                                           # 空时抛异常
    isPresent()
    ifPresent((s) -> {})
    orElse("b")                                                     # 空返回b
    orElseGet(() -> "b")
    orElseThrow(ValuesAsentException::new)
    map((s) -> s + "b")                                             # map非空值,返回Optional
    flatMap((s) -> Optinal.of(s + "b"))
    filter((s) -> s.length() > 6)
Collectors
    toList()
    toSet()
    toCollection(TreeSet::new)
    minBy()
    maxBy()
    averagingInt()
    summingInt()
    partitioningBy()                                                # 按true, false分两组
    groupingBy()                                                    # 分多组
    joining(",", "[", "]")                                          # 拼字符串, 传参是分隔符、前缀、后缀

    o-> 自定义收集器
    public class StringCombiner {
        public StringCombiner add(String element) {
            if (atStart()) {
                builder.append(prefix);
            } else {
                builder.append(delim);
            }
            builder.append(element);
            return this;
        }
        public StringCombiner merge(StringCombiner other) {
            builder.append(other.builder);
            return this;
        }
    }
    public class StringCollector implements Collector<String, StringCombiner, String> {
        public Supplier<StringCombiner> supplier(){
            return () -> new StringCombiner(delim, prefix, suffix);
        }
        public BiConsumer<StringCombiner, String> accumulator(){
            return StringCombiner::add;
        }
        public BinaryOperator<StringCombiner> combiner(){
            return StringCombiner::merge;
        }
        public Function<StringCombiner, String> finisher(){
            return StringCombiner::toString;
        }
        characteristics()                                           # 描述特征
    }
    o-> predicate
        void filter(list list, Predicate condition)
        list1.stream().filter((s) -> (condition.test(s))).forEach((s) -> { System.out.println(s)})


io流分类
    输入、输出
    节点流(如FileReader)、处理流(抽象处理方法)
    字节流(InputStream)、字符流(InputStreamReader)
        字节流处理一个字节,字符流包装字节流,设置编码类型映射成字符,处理字符
InputStream
    BufferedInputStream
    FileInputStream
OutputStream
    BufferedOutputStream
    FileOutputStream
Reader
    InputStreamReader
        FilerReader
    BufferedReader
        readLine()
Writer
    OutputStreamWriter
        FileWriter
    BufferedWriter
        newLine()
        write(String)
Serializable接口
    # 对象流化
    需求例如
        spring中配置的bean
        session中用到的类
    为什么实现序列化接口
        为了注册序列化序号(不显式注册会自动注册)来标识java类,区分相同类名不同包名的类
实现深拷贝
    public static <T extends Serializable> T clone(T obj) throws Exception {
        // 不必调close(), 因为gc时流对象释放
        ByteArrayOutputStream bout = new ByteArrayOutputStream()

        ObjectOutputStream oos = new ObjectOutputStream(bout)
        oos.writeObject(obj)

        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray())
        ObjectInputStream ois = new ObjectInputStream(bin)

        return (T)ois.readObject()
    }

并行 #

线程通信
    共享变量
    wait(), notify()实现生产和消费通知
同步线程
    wait(), sleep(), notify(), notifyAll()
ThreadLocal
    # 线程内数据共享,线程隔离
    withInitial(() -> new SimpleDateFormat())                       # 直接get()时返回调用结果
    set(T t)                                                        # 向当前线程对象放入泛型对象
    get()                                                           # 得到当前线程已放入的对象

InheritableThreadLocal<T>
    # 继承ThreadLocal, 子线程可使用父线程变量
Timer
    o->
    class MyTask extends java.util.TimerTask{
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.println("________");
        }
    }
    Timer timer = new Timer()
    timer.schedule(new MyTask(), 1000, 2000)    // 1秒后执行,每两秒执行一次
    timer.cancel();     // 停止任务
Thread
    currentThread().getContextClassLoader().getResource("/").getPath()  # 静态路径
    run()
    start()
    sleep() # 占有锁
    o->
        # 异常抛出不到父线程
    new Thread(){
        @Override
        public void run(){
            while(count > 0){
                synchronized(AboutThread.class){
                    count--;
                }
            }
        }
    }.start();

    o->
        # 异常抛出不到父线程
    new Thread(new Runnable() {
        @Override
        public void run() {
            while(count > 0){
                synchronized(AboutThread.class){
                    count--;
                }
            }
        }
    }).start();

FutureTask  # java5
    o->
        # 有结果和异常
    FutureTask<String> future = new FutureTask(new Callable<String>(){
        @Override
        public String call() {
            return ""
        }
    })
    new Thread(future).start()
    future.get()
java.util.concurrent
    Executors   # 线程池工厂
        策略
            1 创建并设置
            2 execute()时
                1 线程数小于corePoolSize, 创建线程并执行
                2 线程数大于或等于corePoolSize, 任务入队列
                3 队列满,线程数小于maximumPoolSize, 创建线程并执行
                4 队列满,线程数大于maximumPoolSize, 抛出异常
            3 线程完成任务,从队列取任务执行
            4 线程空闲,超过keepAliveTime, 运行线程大于corePoolSize, 线程停掉
        newFixedThreadPool(3)   # 固定数量
            ExecutorService Pool = Executors.newFixedThreadPool(2);
            pool.execute(new MyRunnable())
            pool.shutdown()
        newCachedThreadPool()   # 根据情况创建数量
        newSingleThreadExecutor()   # 数量为1
        newScheduledThreadPool(2)   # 延时
            ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
            Thread r1 = new MyRunnable();
            pool.execute();
            pool.schedule(r1, 10, TimeUnit.MILLISECONDS);    # t1在10秒后执行
            pool.shutdown();
    <<ExecutorService>>
        execute(Runnable)
        submit(Runnable)        # 返回Future
            # submit(Callable)
        invokeAny()     # 返回执行最快的一个结果
        invokeAll()     # 所有执行结束后返回
        shutdown()  #   只interrupt()空闲线程
        shutdownNow()   # interrupt()所有线程
    ThreadPoolExecutor
        corePoolSize    # 最小数量
        maximumPoolSize # 最大数量
        keepAliveTime   # 线程空闲等待时间
    <<ScheduledExecutorService>>
        schedule(r1, 10, TimeUnit.MILLISECONDS) # 10秒后执行
        scheduleAtFixedRate(r1, 1, 2, TimeUnit.MILLISECONDS)    # 1秒后执行,2秒一次,间隔计算开始时间。异常直接关闭
        scheduleWithFixedDelay(r1, 1, 2, TimeUnit.MILLISECONDS)     # 同上,间隔计算结束时间
    ScheduledExecutorPoolService


    ForkJoinPool    # java7
        ForJoinPool(4)  # 并行级别
        invoke()
    RecursiveAction # 没返回值
        MyRecursiveAction extends RecursiveAction {
            @Override
            protected void compute() {
                new MyRecursiveAction().fork()
            }
        }
    RecursiveTask   # 有返回值
        MyRecursiveTask extends RecursiveTask<Long> {
            @Override
            protected Long Compute() {
                MyRecursiveTask t1 = new MyRecursiveTask()
                t1.fork()
                retrun t1.join()
            }
        }


    CopyOnWriteArrayList
        # 列表被修改时,使用旧副本(保护性复制)
    <<BlockingQueue>>   # 锁实现,插入和取值阻塞, 不能插入null
        add()   # 抛异常
        offer() # 超时退出,返回特殊值
        put()   # 阻塞
        remove()    # 抛异常
        poll()      # 超时退出,返回特殊值
        take()      # 阻塞
        element()   # 检查,抛异常
        peek()      # 返回特殊值
    ArrayBlockingQueue  # 固定大小
        size()

        o->
        queue.put(new PoisonPill())     # 毒丸, 标志数据取完
        obj.isPoisonPill()
    LinkedBlockingQueue     # 链式
        # 两个ReentrantLock(可重入锁)分别控制元素入队和出队
        # tomcat用TaskQueue的父类,它重写offer方法减少创建多余线程
    PriorityBkockingQueue   # 无界,排序
        # 一个独占锁控制入队和出队, 通过cas(无锁算法)保证同时只有一个线程扩容成功
    DelayQueue  # 无界, 延迟期满才能提取。内部用PriorityQueue实现
    SynchronousQueue    # 单元素, cas实现
    ConcurrentQueue
        add()
        offer()
        poll()
        peek()
    ConcurrentLinkedQueue   # 无界队列, 使用cas
        isEmpty()
        size()
        remove()
        contains()
    ConcurrentHashMap
        # 并发集合通过复杂的策略提高效率, 用ReentrantLock
        # 加了concurrencyLevel属性,决定锁分段个数,取2的次幂。内部用分段锁技术,每段Segment中再存放Entity[]数组
    ConcurrentSkipListMap   # 非阻塞Hash跳表, 功能同TreeMap,线程安全,用跳表实现
java.util.concurrent.atomic     # 基本数据
    AtomicBoolean
        get()
        set()
        getAndSet()
        compareAndSet()
    AtomicInteger
        get()
        set()
        getAndSet()
        compareAndSet()
        getAndIncrement()
        getAndDecrement()
        getAndAdd()
    AtomicIntegerArray  # 对int[]类型封装,使用Unsafe类通过cas方式实现线程安全
        get()
        length()
        getAndSet()
        compareAndSet()
        getAndIncrement()
        getAndDecrement()
        addAndGet()
    AtomicLong
    AtomicLongArray

    Semaphore
        # 信号量控制并发
        semaphore(5, true)  # 5个信号量,公平(先启动线程大概率先获得锁)
        o->
        Semaphore semaphore = new Semaphore(5, true)
        semaphore.acquire()
        semaphore.release()
java.util.concurrent.locks     # 锁
    <<Lock>>    # 主要是可重入锁,非阻塞结构上下文使用
        ReentrantLock
            # 多线程不可同时访问一个类中2个加Lock的方法, 因为是2个锁。
            lock()
            unlock
                # 用lock, unlock可设置交替锁(hand-over-hand locking), 轮流锁、解锁一部分
            tryLcok()
                # 可设置超时
                # 同时超时,再尝试失败再尝试而进入活锁。设置不同超时时间减少活锁机率
            lockInterruptibly()
                # 突破死锁
            newCondition()
                # 条件变量, 原子地阻塞并解锁,直到条件满足(如有容量,队列非空)
                condition.await()
                condition.signal()
                condition.signalAll()
    <<ReadWriteLock>>   # 读写锁,写独占
    <<Condition>>   # 替代wait(), notify()
        await()
        signal()

内省 #

# IntroSpector,操作javabean
例子
    Point p = new Point();
    PropertyDescriptor pd = new PropertyDescriptor("x", p.getClass());
    Method methodGetX = pd.getReadMethod();
    Method methodSetX = pd.getWriteMethod();
    methodSetX.invoke(p, 7);
    System.out.println(methodGetX.invoke(p));

    BeanInfo beanInfo = Introspector.getBeanInfo(p.getClass());
    PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
    for(PropertyDescriptor pd2 : pds){
        if(pd.getName().equals("x")){
            System.out.println(pd.getReadMethod().invoke(p));
            break;
        }
    }

反射 #

# 类中成分映射为类
字节码
    Class类型对象指向类加载器中加载的字节码
    Class对象不可以new, 因为字节码是类加载器中加载的, 不可能new出来
    虚拟机中同一个类的字节码只有一份
    预定义的class实例对象9个
        # 包装类型中Type就是class,如int.class == Integer.Type
        # void的包装类型为Void
        void
        byte short int long
        float double
        boolean
        char
    获得字节码三种方法
        Class.forName(类名)
        类名.class
        this.getClass()
    内部类
        内部类不为public时,会在前面加上public 的类的类名和$,所以不能用其类名.class来得到它的字节码
    泛型
        父类可以通过反射泛型类得到泛型的class, 通过该class创建泛型实例
        方法中泛型类实例通过传入class创建(如dbutils)
用途
    1. 根据配置文件实例化并注入对象(如spring)
    2. 实现框架
        # 运行时调用自定义类的指定方法(如struts的Action)
代理
    动态代理机制  # 运行时确定, 用来AOP编程
        没有接口的类:CGlib通过派生子类实现。运行时动态修改字节码
        有接口的类:Proxy生成代理,但是生成的类是接口类型
    静态代理    # 代理指定类,编译时确定

Class
    Type        # 该类对应的字节码对象

    isPrimitive()       # 是否是基本类型
    isArray()       # 是否是数组
    getConstructor(Class<?>... parameterTypes)
    newInstance()                    # 用不带参数的构造方法创建对象
    getField("y") : Field                    # 得到属性
        field.get(该class的对象);            # 得到属性的值
    getDeclaredField("x") : Field
        field.setAccessible(true);
        field.get(该class的对象);            # 暴力反射
    getFields() : Field[]
        field.set(该class的对象, 新的值);
    getMethod(方法名, 方法参数类型的字节码对象) : Method
        method.invoke(该class的对象, 该方法的参数);
            # invoke中调用对象为null表是调用静态方法
            # 注意,jdk1.5中为了兼容jdk1.4(jdk1.4中如果用到可变参数传递的是一个参数的数组),
            ## 在invoke中第二个参数为数组时,会把数组拆开成可变参数传递。但是这样的话,当我们传递的参数本身就是数组时,
            ## 如main(String[] args)中的参数, 就会变成多个参数。解决办法是:对要传递的数组参数进行打包,
            ## 如new Object[]{new String[]{"aa", "bb", "cc"}},
                # 注:基本类型的数组是Object对象,String[]不是Object对象,而是Object[]对象
            ## 参数也可以写成(Object)new String[]{"aa", "bb", "cc"};
                # 这里把Object[]强转为是个Object对象, 这样jdk就不会对数组对象Object[]进行拆分了
    getClassLoader()
        getResourceAsStream("")                    # 相对路径从class根目录开始。没有绝对路径,"/"会报错
    getResourceAsStream("")                        # 相对路径从当前包目录开始。"/"绝对路径从class根目录开始

    使用class
        Class cls1 = Data.class;                    # 虚拟机中已经加载过该类的字节码时
        Class cls2 = p1.getClass();
        Class cls3 = Class.forName("java.lang.String");        # 在虚拟机中没有加载过该类的字节码时
    使用constructor新建实例
        Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
        String str1 = (String)constructor1.newInstance(new StringBuffer("abc"));
    数组
        class上的isArray()判断是否数组
            # 不同维度(一维、二维等), 不同类型的数组,不是同一份字节码。只有同维度同类型的数组是相同的字节码
            ## 基本类型的数组是Object对象,如int[]。String[]是一个Object[]对象,不是Object对象
            Arrays.asList()
                # 打印Object[], 不能打印基本类型数组的Object
            Array.getLength(obj)
                # 得到长度
            Array.get(obj, i)
                # 得到数组中的元素
                # 没有办法得到int[] 对象的元素类型(即int), 只能取得其元素之后得到其类型
    泛型
        public class BaseDao<T> 中
            // 得到的是继承类的字节码
            // hibernate.basedao2.HeroDao
            Class subClass = this.getClass();
            // 直接超类
            // hibernate.basedao2.BaseDao<hibernate.domain.Hero>
            Type type = subClass.getGenericSuperclass();
            // 得到参数
            ParameterizedType pt = (ParameterizedType) type;
            // 参数数组
            Type[] types = pt.getActualTypeArguments();
            // hibernate.domain.Hero
            type = types[0];
            //User
            this.clazz= (Class) type;
Proxy   # 只代理有接口的类
    o->
    final List<String> list = newArrayList<String>()
    List<String> proxyInstance = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
            return method.invoke(list, args)
        }
    })
    proxyInstance.add(1)

web service #

常识
    基于socket                # socket可以跨语言访问
        # 单用socket提供网络服务出现的问题:
        1.不能处理不同协议的请求,如http协议发送的是请求头信息
            # http调用socket:127.0.0.1:8888/或action="127.0.0.1:8888"
        2.添加新参数,客户端也要修改
    版本
        jdk6之后的版本开始支持web service
        jdk6不支持soap1.2
    传输标准:xml或json                # 普遍使用xml,RestFul使用json
优点
    易推广、协议匹配、便于升级(加参数)
服务方式
    # 返回的结果均为xml
    http get
    http post
        # get与post方式直接传递参数,参数易混淆,所以有soap发送xml的方式
    soap1.1
    soap1.2
soap
    常识:
        soap:simple object access protocol
        soap是以post方式传输的

    内容
        请求soap
            <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://my.test/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <soapenv:Body>
                <q0:sayHello>
                <arg0>小明</arg0>
                </q0:sayHello>
            </soapenv:Body>
            </soapenv:Envelope>
        响应soap
            <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
            <S:Body>
                <ns2:sayHelloResponse xmlns:ns2="http://my.test/">
                <return>hello,小明</return>
                </ns2:sayHelloResponse>
            </S:Body>
            </S:Envelope>
wsdl
    获得
        http://192.168.10.3:1234/hello?wsdl                # 发布url后面加?wsdl
    内容                        # 查看时从后向前看
        <service>标签
                name属性:默认 发布类名 + Service
            <port>标签
                    name属性:默认有soap1.1 soap1.2 get post(jdk1.6只有soap1.1),默认 类名 + port
                binding属性:真正的实现者    # 指向<binding>标签
                <soap:address>标签
                        location属性:访问的地址
        <binding>标签:是真正的实现类,soap协议,是文本,方法名
        <portType>标签:
            input
            output
        <message>标签 用schema格式来描述参数类型
        xsd:schema关联的schema文件中
            <element>标签  ,约定了参数类型
创建与发布
    发布到eclipse的jetty容器
        @WebService
        MyWebService
            public String showName(Strng name)
                System.out.println("name=" + name);
                return name + "你好!";
            main
                Endpoint.publish("http://localhost:8888/hello",new MyWebService());
                                        # 发布webService
                    ## 1.6.0_13及之前的版本不支持,1.6.0_14之后的版本支持
                    ## 发布之后http://localhost:8888/hello?wsdl中有wsdl文件
    可以发布成服务的方法
            1.非final、static修饰的public方法
            2.@WebMethod(exclude=true)方法前加该注解时不发布该方法
调用
    HttpClient
        get
        post
        soap
    wsdl.xml
        # web service提供给不同平台生成解决方案的配置文件
        ## HttpClient发送soap时充当了:wsdl.xml解决方案调用的过程
        o-> wsimport.exe(jdk1.6)
            解析wsdl.xml文件
                命令:wsimport -s . -p cn.itcast                # -s 保存源码(默认不保存),-p指定包名
                生成类:
                            # jdk1.6中解析时忽略生成soap12服务类文件(jdk1.6不支持)与get post服务类文件(默认忽略)
                    XxxService
                    XxxServicePort
                    Xxx
                    ..
                调用:
                    MyWSService mywsService = new MyWSService();
                    String retVal = mywsService.getMyWSPort().sayHello();
        o-> myeclipse的web service soap浏览器
            # 可以从soap浏览器中查看请求和返回的soap.xml文件的源码
            |-> 右上角wsdl page
            |-> 左边栏 uddi main
            |-> 右边栏按提示输入即可
        o-> ajax
            方式一:直接调用
            缺点
                新版浏览器(ie10等)不支持跨域请求(为了安全),所以只能请求localhost
                会把数据暴露在客户端
注解
    @WebMethod(exclude=true)    # 对此方法不进行发布
    @WebService     # 声明为web service服务类
        ## 可选属性
        name="服务名",
        portName="端口名",
        serviceName="真正服务类的名字",
        targetNamespace="包名a.b.c"
    @WebResult(name="")     # 方法返回值类型前,指定返回值名(如果返回的是集合,则指定的是集合内元素的名)
    @WebParam(name="")     # 方法参数值类型前,指定参数名

框架 #

cglib
    # 构造接口
dbutils
fastjson
    # 淘宝json
beanUtils
ioUtils

jvm #

基础 #

继承
    被继承的对象是会单例,不会新创建。如果被继承的对象没有,则创建一个
多态
    父类(接口)中定义的引用变量,在运行时动态绑定到具体实例的方法执行
内部unicode编码
类
    初始化时机
        new
        访问静态变量,或对静态变量赋值
        调用静态方法
        反射 Class.forName("")
        初始化子类,会先初始化父类
        jvm启动时标明的类 (java com.a.A中的A类)
    步骤
        类加载
        链接
            验证
            准备  # 静态变量分配内存,设置默认初始值
            解析  # 符号引用替换直接引用
        初始化父类(非接口)
        初始化
            父类
            初始化语句   # 如static块和static变量
线程
    运行时都有线程栈,保存变量值信息。访问对象值时,建立变量副本。修改后(线程退出前)副本值写到对象
JIT(just in time)
    # 热点代码检测, 运行时编译和优化

内存 #

# java自动管理堆栈, c++手动分配
组成
    方法区(method area)
        组成
            类信息
                class
            数据区(data segment)
                运行时常量池(constant pool) # 编译期确定,保存在.class中的数据
                    字面量
                    文本形式的符号引用
                        字段名称和描述符
                        方法名称和描述符
                        类和接口的全限定名
                静态区(static segment)
                    静态变量
            代码区(code segement)
                JIT编译后的代码
        特点
            线程共享
            静态分配, 位置不改变
    栈(stack)
        分类
            虚拟机栈(vm stack)
            本地方法栈(native method stack)
        保存
            基础数据类型
            引用类型在栈分配地址, 局部变量生命周期结束后,栈空间立即回收
            方法调用    # 一次调用一个帧(frame)
            方法的形参, 调用完回收
            方法引用参数, 在栈上分配地址, 调用完回收
            方法实参,栈空间分配,调用完释放
        特点
            线程隔离
            逻辑概念,可连续可不连续, 系统自动分配。栈中的字面值可共享,如int i = 3
            StackOverflowError
        实现
            java的stack存放的是frames, frames由heap分配,所以stack内存不连续
            只存在本地变量、返回值、调用方法,不能直接push和pop frams
    堆(heap)
        保存
            引用类型在堆分配类变量, 局部变量生命周期结束后,堆空间等待gc回收
            this
        特点
            线程共享
            以随意顺序,运行时分配和回收空间, 代码申请
            大小、数量、生命期常常在编译时不确定
            细分为新生代和老年代, 再具体为 eden survivor(from survivor、to survivor), tenured
            OutOfMemoryError
        实现
            存放所有runtime data
            heap是jvm启动时创建
    程序计数器(program counter register)
        特点
            线程隔离
机制
    程序计数器、虚拟机栈、本地方法栈 是线程私有空间
        随线程产生和销毁,每个栈帧分配多少内存在随类结构确定。内存分配回收都是确定的
    方法区和堆
        一个接口的各实现类需要内存可能不一样, 所以运行时才知道创建哪些对象,内存分配和回收是动态的,gc主要关注
内存溢出
    原因
        加载数据过大  # 大约10万条以上, 应分页查询
        集合中对象引用未清除
        代码循环产生对象
        第三方软件bug
        启动参数内存设置过小
    方案
        jvm启动参数 -Xms, -Xmx
        jvm错误日志, OutOfMemory前信息
        内存查看工具动态查看

类加载器 #

父亲委派机制(java2)
    # 常用类不被替代
    先试上层类加载器

4种类加载器(加载类文件位置不同)
    层级关系
        # 父级类加载器向下加载子加载
        BootStrap
            ExtClassLoader
                AppClassLoader
                    自己的类加载器
    优先级
        只加载层级关系靠前面的同名类

    BootStrap
        # c++写的二进制代码,jvm中启动时创建,无法获得引用对象
        位置
            JRE/lib/rt.jar  # java9后为jrt-fs.jar
            参数-Xbootclasspath指定
        代码
            System.class.getClassLoader()
                # null
                ## 说明是BootStrap类加载器加载的,不能得到该类加载器
    ExtClassLoader(sun.misc.Launcher$ExtClassLoader)
        位置
            JRE/lib/ext/*.jar
            参数-Djava.ext.dirs指定
    AppClassLoader(sun.misc.Launcher$AppClassLoader)
        位置
            环境变量CLASSPATH 或 系统属性java.class.path
            参数-cp覆盖
        代码
            ClassLoaderText.class.getClassLoader().getClass().getName()
                # AppClassLoader
    自定义     # 如tomcat的StandardClassLoader
        # 继承ClassLoader
api
    TestClass.class.getClassLoader()
        getParent()                        # 得到加载该类加载器的类加载器
        loadClass(String name)                # 找parent委托,没有加载时执行findClass(String name)
                                                ## 模板方法的设计模式,见 note-> 设计模式
        findClass(String name)                # 自己加载
        defineClass(..)                                # 将二进制数据转换为class
    线程
        # 该线程类加载器加载线程中的第一个类
        线程.setContextClassLoader(ClassLoader cl)    # 指定一个线程的类加载器
自己的类加载器
    挂在AppClassLoader下面
    加载指定的目录
        该目录下的class加密后,自己的类加载器解密
    写法
        覆盖findClass(String name)
    例子
        public class MyClassLoader extends ClassLoader{
            private String classDir;
            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException{
                // 传入的name是全限定名
                String classFileName = classDir + "\\" + name.substring(name.lastIndexOf('.') + 1) + ".class";
                // 处理异常
                FileInputStream fis = new FileInputStream(classFileName);
                ByteArayOutputStream bos = new ByteArraOutputStream();
                cypher(fis, bos);
                fis.close();
                byte[] bytes = bos.toByteArray();
                return defineClass(bytes, 0, bytes.length);
                // 抛出异常时 return super.findClass(name);
            }
            public MyClassLoader(){}
            public MyClassLoader(String classDir){this.classDir = classDir;}
            private static void cypher(InputStream ips, OutputStream ops){...}
        }
        // 删掉父类的ClassLoaderAttachment.class
        // new 的MyClassLoader挂在了AppClassLoader这个类加载器上
        Class clazz = new MyClassLoader("itcastLib").loadClass("cn.itcast.day2.ClassLoaderAttachment");
        // 错误写法。因为这样写 jvm编译器要加载ClassLoaderAttachment类,但是该类已经加密
        ClassLoaderAttachment d1 = (ClassLoaderAttachment)clazz.newInstance();
        // 正确写法。用该加密类继承的父类来引用它的实例
        Date d1 = (Date)clazz.newInstance();
servlet部署
    tomcat类加载器
        AppClassLoader
            StandardClassLoader
                WebappClassLoader
    输出Servlet.class的jar与servlet-api.jar到jdk/lib/ext
        # 因为servlet.class加载的时候需要HttpServlet类,该类在tomcat提供的servlet-api.jar

规范 #

命名与写法
    包名 小写、只用一个单词、只用单数
    类名 UpperCamelCase
        类名可以使用复数
        抽象类开头 Abstract或Base
        异常类结尾 Exception
        测试类以要测试类名开始,以Test结尾
        使用的设计模式,可以写在类名上
        接口类形容能力时,用形容词做名字(一般是-able, 如Translatable)
            实现类1: 结尾加Impl
            实现类2: Translatable的实现类名Translator
        枚举类结尾加Enum
            成员全大写,下划线隔开
    方法名、参数名、成员变量、局部变量 lowerCamelCase
        获得单个对象前缀get
        获得多个对象前缀list
        获得统计值前缀count
        插入前缀save或insert
        删除前缀remove或delete
        修改前缀update
        方法按顺序排列
            # 公有或保护 -> 私有 -> getter/setter
    常量 MAX_COUNT
    布尔类型变量不以is开头
    保留字和运算符左右加空格, 参数逗号后加空格
    缩进用4空格
    杜绝不规范的缩写
        如 AbstractClass写成AbsClass、condition写成condi
    换行
        # 单行120要换行
        运算符、点号在下一行
        参数中的逗号在上一行
        括号前不换行,如append("a")的括号前
    空行
        执行语句组、变量定义语句组、业务逻辑或不同语义之间插入空行
            # 相同业务逻辑和语义间不要空行
    领域模型
        # POJO是 DO/DTO/BO/VO 的统称,禁止命名xxxPOJO
        数据对象 xxxDO
        数据传输对象 xxxDTO
        展示对象 xxxVO
    ide的text file encoding设置为utf-8, 文件换行用unix格式
类
    类成员和方法,访问控制从严
    构造方法不加业务逻辑
    POJO类要实现toString (避免继承)
    接口类
        接口类中方法和属性,不要加修饰(如public),
        尽量不定义变量和default实现
    枚举类
        变量值在一范围内变化的,用Enum类,有延伸属性的(如MONDAY(1)),用Enum类
方法
    覆写方法一定加@Override,可判断是否覆盖成功
    过时方法要加@Deprecated,并写明新接口是什么
    可变参数只用在ids之类的地方
    不使用过时方法
变量
    常量
        不要定义一个总常量类,应分类定义单独的类
        共享常量
            跨应用,放在二方库,如client.jar中的constant目录
            应用内,放在一方库modules中的constant目录
            子工程内部,放在子工程的constant目录
            包内,放在包的constant目录
            类内,在类中定义private static final
        不写魔法值,如key="Id#toabao"
        long型赋值用大写L, 如Long a = 2L
    数组 String[] args,而不是String args[]

编程
    方法可以反回null, 但要注释充分
    POJO类属性和RPC方法参数返回值使用包装类型,局部变量使用基本类型
    避免所有NPE(空指针)问题(赋初值或非空检查)
    用"a".equals(object)而不是object.equals("a"),否则容易抛空指针
        # 也可以用java.util.Objects#equals
    String.split时,要检查最后分隔符后有无内容 (如 "a,b,,", 使用arr[3]时异常)
    包装类比较,用equals
        # 只有Integer -128到127在IntegerCache中运用享元,才==
    用StringBuilder扩展字符串
    慎用Object.clone,是浅拷贝,要重写
    final
        不需要重新赋值的变量
        对象参数加final,表示不修改引用
        类方法不重写
    正则要预编译
        # Patern.compile()在外
    Math.random()可以取到0,取整数时用nextInt或nextLong方法
    用System.currentTimeMillis()而不是new Date().getTime()
    任何数据结构的构造或初始化,都要指定大小,避免OOM
    NPE(空指针异常)场景
        返回包装类型为null时,解包NPE
        数据库查询结果
        集合里元素即使isNotEmpty,也可取出null
        远程调用结果要判null
        Session中数据判null
        级联调用 a.b().c()
集合
    初始化时,尽量指定大小
    hashCode与equals
        # 同时重写
        Set存的对象与Map的键,要重写hashCode与equals
    sublist只是个视图,不能转ArrayList
        sublist修改原集合个数,会引起之后使用的CuncurrentModificationException异常
    集合转数组要用toArray(T[])
    Arrays.asList返回的集合不要add/remove/clear
        # 只是适配器,内部还是数组
    <? extends T>接收的对象,不能用add方法
    remove/add用Iterator,并发要加锁,不能foreach
    JDK7以上版本,Comparator要满足3个条件,不然Arrays.sort和Collections.sort会报异常
        x,y比较结果和y,x相反
        x>y, y>z, 则x>z
        x=y则x, z比较结果与y, z比较结果相同
    使用entrySet遍历Map, 而不是KeySet, JDK8使用Map.foreach
        # KeySet遍历了2次,一次转为Iterator对象,一次从hashMap取key的value
    null情况
        集合类                 Key      Value     Super       说明
        Hashtable           非null       非null   Dictionary  线程安全
        ConcurrentHashMap   非null       非null   AbstractMap 分段锁技术
        TreeMap             非null       可null   AbstractMap 线程不安全
        HashMap             可null       可null   AbstractMap 线程不安全
    稳定性和有序性
        ArrayList   order/unsort
        HashMap     unorder/unsort
        TreeSet     order/sort
并发
    单例方法要线程安全, 获取单例要注意线程安全
    线程或线程池指定有意义的名称
        public class TimerTaskThread extends Thread {
            public TimerTaskThread() {
                super.setName("TimerTaskThread")
    线程资源只从线程池取,不要自行创建
    不用Executors而用ThreadPoolExecutor创建
        FixedThreadPool和SingleThreadPool允许请求队列长度为Integer.MAX_VALUE, 可能堆积大量请求OOM(out of memory)
        CachedThreadPool和ScheduledThreadPool允许创建线程数量为Integer.MAX_VALUE,可能创建大量线程,导致OOM
    SimpleDateFormat线程不安全,不要static。应使用DateUtils
        JDK8用Instant代替Date, LOcalDateTime代替Calendar, DateTimeFormatter代替Simpledateformatter
    尽量锁小范围
    多线程中,都对多对象加锁,加锁顺序要一致,否则会死锁
    并发修改时,在应用层加锁或在缓存加锁或在数据库层加乐观锁并使用version作更新依据
        每次访问冲突率小于20%, 使用乐观锁,否则用悲观锁。
        乐观锁重试次数不得小于3
    Timer的多个TimeTask,一个没有捕获异常会同时终止。应使用ScheduledExecutorServcie
    CountDownLatch进行异步转同步时,线程代码注意catch异常,确保countDown执行
        # 子线程异常,主线程catch不到
    Random多线程下,会因竞争同一seed导致性能下降。JDK7后用ThreadLocalRandom
    延迟初始化的双重检查锁隐患。将目标属性声明为volatile
    volatile不能解决多写问题, 使用AtomicInteger或JDK8的LongAdder,它减少了乐观锁的重试次数
    HashMap在容量不够进行resize时,高并发可能会出现死链,导致cpu飙升
    ThreadLocal使用static修饰
控制语句
    switch中,case要么有break/return,要么注释执行到哪个case。switch都要有default
    不要省略大括号
    尽量少用else,用卫语句(只有一个if)或状态模式
    条件判断只调用getXxx/isXxx,运算赋值给布尔变量判断,提高可读性
    循环体中语句考量性能
    参数校验场景
        调用频次低的方法
        执行时间大的方法
        需要极高稳定性和可用性
        对外开放接口
        敏感权限入口
    不需参数校验场景
        可能被循环调用     # 要注明外部参数检查
        底层方法,如DAO
        private方法明确入参已校验
注释
    # 自解释代码少注释,注释要反应设计思想与代码逻辑,描述业务含义
    类、类属性、类方法使用/**内容*/      # Javadoc规范
    抽象方法要Javadoc注释,除返回值、参数、异常说明外,还要指出做什么事,实现什么功能
    类要添加创建者
    枚举类型都要注释
    用中文说清楚
    注释要跟进修改
    注释掉的代码要有说明
    特殊注释,要注明标记人和标记时间
        TODO: (标记人,标记时间,[预计处理时间])
异常
    事先检查值,而不是调用后处理异常
    异常不要用来做流程控制,效率低
    异常要对小段代码, 要细分
    异常要处理或上抛,最外层一定要处理
    注意事务回滚
    finally资源要关闭,异常要处理,JDK7用 try-with-resources
    finally中不要return,否则不执行try中return
    不要捕获异常的父类
    rpc异常定义自己的result,好处一是调用方不会漏查,二是可以加异常栈
    不抛RuntimeException,Exception和Throwable。抛确定异常
日志
    不直接用日志系统,用门面模式的日志框架
    日志保存15天,因为有“周”频次发生的异常
    利用日志文件名和目录 stats/desc/monitor/visit/appName_logType_logName.log
    直接logger.debug(a + b),级别为warn是表达式还会执行。用2种方式避免
        if logger.isDebugEnabled() {...}
        logger.debug("{} {}", id, symbol)
    设置log4j.xml的additivity=false,防止重复打印
    要记录异常堆栈。logger.error(参数或对象toString + "_" + e.getMessage(), e)
    可以用warn记录用户输入参数错误的情况,避免用户投诉时无所适从
    生产环境禁止输出debug日志,有选择地输出info。如果用warn来记录刚上线业务,要注意量的问题
mysql
    类型
        is_xxx  unsigned tinyint    # 1是0否
        唯一索引名 uk_字段名,普通索引idx_字段名        # unique key, index
    表名、字段名
        库名与应用名尽量一致
        小写与数字
        不数字开头
        不能下划线间仅有数字
        不使用复数
        不用保留字
            desc、range、match、delayed等
        必有三字段
            id unsigned bigint,单表时自增,步长为1
            gmt_create date_time
            gmt_modified date_time
        表名 业务名称_表的作用,如tiger_task, mpp_config
        字段含义修改或追加状态时,及时更新注释
    orm
        boolean属性POJO不加is, 数据库前缀is_
            # mybatis generator生成的代码中需要修改
        不能返回resultClass, HashMap, Hashtable
        xml配置用 #{}, #param#, 不要${},容易sql注入
        尽量不用ibatis的queryForList(String statementName, int start, int size)
            # 会查整表
            应在sqlmap.xml中引入#start# #size#
        更新时要同时更新gmt_modified
        不要大而全的更新接口,传入POJO类。会更新无改动字段,易出错,效率低,增加binlog存储
        @Transactional事务不要滥用,影响qps
            事务回滚方案包括缓存回滚、搜索引擎回滚、消息补偿、统计修正等
分层
    开放接口层
    终端显示层
    web层
        对访问控制进行转发,参数校验,不复用业务简单处理
    service层
    manager层
        对第三方封装
        service通用能力下沉,如缓存方案、中间件通用处理
        与dao层交互,对dao业务通用能力封装
    dao层
        直接抛DAOException,由service层处理
    外部接口或第三方平台
    分层领域模型
        DO (Data Object)
        DTO (Data Transfer Object)
        BO (Business Object)
        QUERY
        VO (View Object)
服务器
    JVM设置- XX :+ HeapDumpOnOutOfMemoryError, OOM时输出dump信息