diff --git a/Golang/Golang基础.md b/Golang/Golang基础.md index 545c19e..230f697 100644 --- a/Golang/Golang基础.md +++ b/Golang/Golang基础.md @@ -1,824 +1,824 @@ -# Golang基础 -- ## Golang中的包机制 - - Golang程序是由包组成的,并且在名为main的包中开始运行 - - 包的导入 - - 包可以通过import语句进行导入,在导入多个包时,可以用()将导入的多个包扩起来,并且每个包占据一行 - ```Golang - import ( - “fmt" - "math" - ) - ``` - - 包的导出 - - 在包中,如果一个名字以大写字母开头,那么这个名字将会被导出,如math.Pi会被导出,而math.pi则不会被导出 - - 在导入包时,只能够引用那些包中被导出的变量 -- ## Golang中函数 - - 在Golang中,函数可以接受一个或者多个参数,但是函数参数中参数类型位于形参名称之后 - ```Golang - func f(msg string,n int) { - fmt.Println(msg,n) - } - ``` - - 在Golang中,连续的函数参数如果都是同一种类型,那么这些连续参数的类型都可以省略,但是在相同类型的最后一个参数末尾要指明参数类型 - ```Golang - func f(a,b int,msg string) { - fmt.Println(a,b,msg) - } - ``` - - Golang函数的多值返回 - - Golang函数可以返回任意数量的返回值 - ```Golang - func f() (string,string) { - return "fuck","shit" - } - - a,b:=f() - // a:"fuck",b:"shit" - fmt.Println(a,b) - ``` - - Golang函数可以为返回值进行命名,其会被视作在函数顶部定义的变量,可以在函数体中引用变量并且对其进行修改 - - Golang函数中如果使用了命名返回值,那么在return语句后没有跟随其他值时,会将命名返回值变量当前的值 - ```Golang - func f() (retVal int) { - // retVal值默认是0 - fmt.Println(retVal) - retVal=20 - // return语句会默认返回retVal变量的值,返回值为20 - return - } - ``` -- ## Golang中的变量 - - Golang中变量的声明可以通过var关键字,并且在i变量名之后跟随类型关键字 - ```Golang - var a int - ``` - - Golang在声明变量时,可以为变量指定一个初始化器,在为每个变量指定初始化器后,变量的类型可以被省略 - ```Golang - var a,b,c=1,2,"kazusa" - fmt.Println(a,b,c) - ``` - - Golang允许在函数内,通过:=符号来声明一个变量,并且其变量的默认类型为:=后跟随的值类型 - ```Golang - // inside a func - a := 1 - fmt.Println(a) - // 在函数外部,这种变量声明的方式不被允许 - ``` -- ## Golang中的基本类型 - - Golang中基本类型如下: - - bool - - string - - int int8 int16 int32 int64 - - uint uint8 uint16 uint32 uint64 uintptr - - byte (和uint8相同) - - rune (和uint32相同,用来代表unicode字符码位) - - float32 float64 - - complex64 complex128 (复数) - ```Golang - // 在Golang中,可以采用和import一样的格式来声明 - // 多个不同类型的变量 - var ( - a,b int=1,2 - msg string="fuck" - ) - ``` - - 各类型变量在未赋初始值时的默认值 - - 数值型(整数、浮点数) : 0 - - bool: false - - string : 空字符串 - - Golang中的类型转换 - - 在Golang中,在变量声明时,如果显式指定了变量的类型,那么在后续为该变量指定初始化器或者赋值时,等式右边的类型必须和等式左边的类型相同,否则应该显式制定类型转换 - ```Golang - var a int=1 - var b int8=int8(a) - ``` - - Golang中类型推断 - - 如果在声明变量时,没有为变量显式指定类型,那么将会根据等式右边的值来推断变量类型 - - 通过 := 表达式通过等式右边表达式进行推断 - - 在var关键字右边通过初始化器来推断类型 - ```Golang - // 默认情况下,整数类型的字面量将会被推断为int - // 浮点数类型的字面量将会被推断为float64 - // 复数类型将会被推断为complex128 - var a = 1 // a被推断为int类型 - var f = 1.0 // f被推断为float64类型 - ``` -- ## Golang中的常量 - - Golang中常量的声明和变量类似,但是使用const关键字 - - 常量可以是bool、string、数值、字符 - - 常量的声明无法使用 := 方式 - ```Golang - const ( - a,b int=1,2 - c string="shiro" - ) - fmt.Println(a,b,c) - ``` -- ## Golang中的循环 - - 在Golang中,只存在有一种循环,for循环。 - - Golang中for循环结构如下: - ```Golang - // 其结构类似与java和c中的for循环 - // 其中,init和post部分是可选的 - // for ;condition expression; {} - for init statement;condition expression;post statement { - // loop body - } - ``` - - 在Golang中while循环结构如下: - ```Golang - for expression { - - } - ``` - - 在Golang中,如果想实现无限循环,expression可以被省略 - ```Golang - for { - // infinite loop - - } - ``` -- ## Golang中的条件分支 - - 在Golang中,if的条件表达式不需要用小括号扩起来,但是if后跟的语句块必须用大括号包起来 - ```Golang - if condition-A-expression { - // condition A - } else if condition-B-expression { - // condition B - } else { - // condition else - } - /** - * 此时else if/else和上一个条件的'}'符号必须位于同一行 - **/ - ``` - - 在Golang中的if语句中,可以在条件表达式之前添加一个执行语句,在执行语句中定义的变量只能在if和else if/else块中被访问 - ```Golang - if msg:="msg content";expr1 { - fmt.Println(msg) - } else { - fmt.Println(msg) - } - ``` -- ## Golang中的switch语句 - - 在Golang中,并不需要为switch中的每个case手动添加break,Golang的switch只会执行第一个匹配的case后的语句 - - 在Golang中,case条件后跟的不一定非要是常量,也可以是变量或者是函数调用 - - 在Golang中,case后跟的也不一定是整形,而可以是其他类型 - ```Golang - func f() { - return 0 - } - - // ... - a:=0 - switch a { - case f(): - fmt.Println("matched") - default: - fmt.Println("missed") - } - ``` - - 在Golang中,switch语句可以不跟条件表达式,其默认和switch true相同: - ```Golang - switch{ - case condition-1: - // ... - case condition-2: - // ... - default: - // ... - } - 和 - if condition-1 { - //... - }else if condition-2 { - //... - }else { - //... - } - 相同 - ``` -- ## Golang中的defer - - 在Golang中,可以用defer关键字将函数的执行推迟到当前defer语句所处的函数执行完成之后 - - 在Golang中,defer关键字修饰的函数调用,其参数是立即被计算的,但是函数调用会被推迟到外围函数执行结束之后 - - Golang中defer推迟的函数调用将会被压入到栈结构中,如果在同一个函数中存在多个defer调用,那么在函数执行结束后,后被压入栈结构的defer调用会先被调用 - ```Golang - func f() { - fmt.Println("function begin") - - defer fmt.Println(1) - defer fmt.Println(2) - defer fmt.Println(3) - - fmt.Println("function end") - } - // 在调用f()后,其输出会按如下顺序 - // function begin - // funtion end - // 3 - // 2 - // 1 - ``` -- ## Golang中的指针 - - Golang中指针的声明 - ```Golang - var p *int - ``` - - Golang中的取址操作 - ```Golang - var ( - i int = 1 - p *int = &i - ) - ``` - - Golang中的解引用操作 - ```Golang - var ( - i int = 1 - p *int = &i - ) - fmt.Println(*p) - *p=2 - fmt.Println(*p) - ``` - - Golang中并不存在指针的算数,如通过+或者-一个指针将指针地址向前、向后推移 -- ## Golang中的struct - - Golang中struct的定义 - ```Golang - type Node struct { - val int - next *int - } - - fmt.Println(Node{1,2}) - ``` - - Golang结构体中域的引用 - ```Golang - type Result struct { - retCode int - msg string - } - - var result Result=Result{200 "response success"} - fmt.Println(result.retCode,result.msg) - ``` - - 通过指针访问结构体中的内容 - ```Golang - node := Node{0,nil} - // 要想通过指针访问结构体中的域,可以如下所示 - fmt.Println((*node).val) - // 也可以直接在指针后调用. - fmt.Println(node.val) - ``` - - 结构体字面量 - ```Golang - // 可以通过为每个域按顺序指定值 - var result Result=Result{ - 200, - "请求成功" - } - // 可以通过filedName:value来为域的子集指定值 - // 其他未指定的值为默认值 - var result Result=Result{ - // retCode未指定默认为0 - msg:"请求成功" - } - // 可以不为域指定值,域中所有值都为默认值 - result := Result{} - ``` -- ## Golang中的数组 - - Golang中数组类型为[n]T,代表长度为n的T类型的数组 - - Golang中的数组无法被扩容 - - slice:slice中包含数组中元素的子集,可以作为数组的一个动态视图,通过slice比数组使用的更为广泛 - - slice的类型为[]T,T是元素的类型 - - slice本身并不存储任何元素,其只是一个针对数组中一定范围内元素的引用 - - 在slice中对元素进行的更改在数组中也可见,在数组中对元素进行的更改同样在slice中可见 - - 可以对slice创建slice - - 在创建slice之前无需先创建数组,可以直接创建slice,创建slice的同时会创建数组并且让slice引用创建的数组 - ```Golang - // 声明一个数组 - arr := [5]int{1,2,3,4,5} - // 对数组进行切片,获取数组的slice - // 其中以array[lo : hi]形式来切片 - // slice中包含下标为lo的元素 - // 但是slice不包含下标为hi的元素 - slice := arr[1:3] - - // 直接创建slice - slice_dir=[]int{1,2,3,4,5} - ``` - - 在进行slice操作时,可以对下标的下界和上界进行省略,在省略下界时,默认下界为0,在省略上界时,默认值为数组长度 - ```Golang - arr := []int{1,2,3,4,5,6,7} - fmt.Println(arr[:4][1:]) // 返回[2,3,4] - ``` - - slice的length和capacity - ```Golang - // slice的length是指slice中元素的个数 - // slice的capacity是值从slice中第一个元素开始算起,到 - // array中的最后一个元素,一共有多少个元素 - arr := []int{1,2,3,4,5,6,7,8,9} - - slice := arr[1:4] - fmt.Println(len(arr),cap(arr)) - // 输出length为3 - // 输出cap为8 - ``` - - slice可以对其进行重新切片,虽然无法通过数组下标访问位于slice范围外的元素,但是可以通过重新切片来将slice范围扩大到数组范围外 - ```Golang - arr := []{1,2,3,4,5,6,7,8,9} - - // 切片[2,3,4] - arr = arr[1:4] - // 重新切片为[2,3,4,5] - arr = arr[:4] - ``` - - slice变量的默认值是nil,其cap和len都是0,并且没有底层的数组 - - Golang中创建动态大小的数组 - ```Golang - // make函数类似于c++中的new T[n],返回一个slice - // 返回数组中元素值都是默认值 - - // 创建一个slice,并且指定len和cap为相同值 - // 其中len为5,cap为5 - arr := make([]int,5) - - // 创建一个slice,并分别指定len和cap - // 其中,len为5,cap为10 - arr := make([]int,5,10) - ``` - - Slice中可以包含slice,类似于多维数组 - ```Golang - slice := [][]string { - []string {"touma","kazusa"}, - []string {"kitahara","haruki"} - } - ``` - - Golang中向slice添加元素 - - 可以通过append方法向slice中添加元素,如果slice中位于len后的cap可以容纳添加的所有元素,就在当前数组中修改位于slice之后的元素 - - 如果当前slice的cap无法容纳append中所有的元素,会重新创建一个数组,拷贝当前slice中所有的元素,在添加元素后返回一个指向新分配数组的slice - ```Golang - arr := []int{1,2,3,4} - t := append(arr[:3],-1,2) - fmt.Println(arr,t) - // 输出结果如下 - // arr [1,2,3,4] - // t [1,2,3,-1,2] - // arr和t并不指向同一个底层数组 - ``` -- ## Range的形式迭代slice - - 可以通过range的形式对slice进行迭代: - ```Golang - // 其中i是当前迭代元素的下标 - // v是当前迭代元素值的拷贝 - for i,v := range slice { - fmt.Println(i,v) - } - ``` - - 在只想在range中访问index或是value时,可以使用_作为占位符 - ```Golang - // 省略value - for i,_ := range slice { - fmt.Println(i) - } - - // 省略value时,_也可以省略 - for i := range slice { - fmt.Println(i) - } - - // 省略index - for _,v := range slice { - fmt.Println(v) - } - ``` -- ## Golang中的map - - 在Golang中,map的默认值是nil,既没有键值对,也无法加入键值对 - - 可以通过make函数返回指定类型的map,返回的map已经被初始化并且准备好被使用 - ```Golang - m := make(map[string]string) - m["shiro"]="kana" - m["black"]="kazusa" - fmt.Println(m) - ``` - - map字面量 - ```Golang - m := map[string]string{ - "shiro":"kana", - "black":"kazusa", - } - fmt.Println(m) - ``` - - map中如果字面量中元素的值是struct类型,那么可以省略值类型中的类型名称 - ```Golang - type Point struct { - X float64 - Y float64 - } - - m := map[string]Point{ - "point-a":{1,1}, - "point-b":{2,2} - } - - fmt.Println(m) - ``` - - 对map进行操作 - ```Golang - // 插入或者更新map中元素 - m["touma"]="kazusa" - - // 获取map中元素,如果map中不存在该元素,返回该元素类型的默认值 - elem = m["touma"] - - // 判断map中是否存在key为指定值的键值对 - elem,ok := m["shiro"] - // 如果不存在,elem为默认值,ok为false - - // 从map中删除key为指定值的元素 - delete(m,key) - ``` -- ## Golang中函数的值传递 - - Golang中函数可以作为值传递给变量或者其他函数的参数,也可以作为其他函数的返回值 - ```Golang - func operateOnArgs(f func (float64,float64) float64,a,b float64) float64 { - return f(a,b) - } - - var f=func(a,b float64) float64{ - return math.Sqrt(a*a+b*b) - } - fmt.Println(operateOnArgs(f,3,4)) - ``` - - Golang中函数的闭包 - - Golang中支持函数的闭包,通过将一个函数作为函数的返回值,返回的函数可以访问外层函数中定义的局部变量,位于外层函数之外只能通过返回的函数来访问外层函数内部的局部变量,如此保证了局部变量的安全性 - ```Golang - func adder() func(int) int { - sum := 0 - return func(a int) int { - sum+=a - return sum - } - - } - ``` -- ## Golang中的方法 - - 虽然Golang中并不像其他语言一样存在类(class),但是我们可以在Golang中为类型(type)定义方法 - - 在Golang中,为类型(type)定义方法是定义一个接受特定类型参数的函数 - ```Golang - type Point struct { - X,Y float64 - } - - // 为Point类型定义方法 - func (p Point) Abs() float64 { - return math.Sqrt(p.X*p.X+p.Y*p.Y) - } - - // 可以通过如下形式调用为类型定义的方法 - p := Point{3,4} - fmt.Println(p.Abs()) - ``` - - 在Golang中,不仅可以为struct类型指定方法,而且可以为基本类型指定方法(例如type MyFloat float64后,为MyFloat类型指定方法) - - 在Golang中,只能够为位于同一个包中的类型指定方法,无法为位于其他包中的类型指定方法 - ```Golang - type MyFloat float64 - - func (f MyFloat) fuck() { - fmt.Println("fucking float64") - } - ``` - - 在Golang中,除了可以为类型指定方法外,还可以为类型的指针指定方法,此时特殊参数接受一个指针,可以通过指针修改传输类型的值 - ```Golang - type Point struct { - X,Y float64 - } - - // 定义函数接受一个Point类型的指针 - func (p *Point) modify() { - p.X *= 10 - p.Y *= 10 - } - - // 调用时无需先将类型对象转化为指针,可以直接在对象上调用 - p := Point{3,4} - p.modify() - // 调用后p为{30,40} - - // 接受一个Point类型的拷贝 - func (p Point) modifyCopy() { - p.X *= 10 - p.Y *= 10 - } - - // 调用时传入函数的是对象的一个拷贝,不会修改原先对象的值 - p := Point{3,4} - p.modifyCopy() - // 调用后仍然为{3,4},修改的只是拷贝对象的值 - ``` - - 在Golang中,普通函数参数,必须向接受指针的形参中传入指针,向接受值的形参中传入值;但是在接受特殊参数的位置,如果想要接受的是值类型,那么传入指针和传入值均可;如果想在特殊参数位置接受指针类型,那么传入指针和传入值类型也均可 - ```Golang - func (p *Point) modify() { - // func body - } - - // 对于如下调用形式均可 - p := Point{3,4} - - p.modify() // 可行的调用方式 - (&p).modify() //可行的调用方式 - - func (p Point) modifyCopy() { - // func - } - - p := Point{3,4} - // 对接受值的特殊参数,下列调用方式也均可 - p.modifyCopy() // 可行 - (&p).modifyCopy() //可行 - ``` -- ## Golang中的接口 - - 在Golang中,interface中定义了一系列的方法签名,对于实现了interface中定义所有方法签名的类型,其都可以被赋值给interface类型 - - 如果对一个类型的指针实现了interface接口,那么只能将该类型的指针赋值给interface变量,无法将该类型赋值给interface变量 - ```Golang - type Car interface { - drive() - } - - type AE86 struct { - } - - // 为AE86类型的指针实现接口中drive方法 - func (car *AE86) drive() { - - } - - // 此时,可以将*AE86类型赋值给Car,但是无法将AE86赋值给Car - var car Car - car = AE86{} // 失败 - car = &AE86{} // 成功 - ``` - - 接口中保存的信息通常可以看做一个二元组:(具体的值,值的类型) - ```Golang - // 接口中保存的值如果是nil,但是其类型已经确定,那么接口的值就不为nil - var car Car - car=(*AE86)(nil) - fmt.Println(car==nil) // 输出为false - // 此时,虽然car仍然不指向具体的对象,但是其指向的类型确定为Car,故而其不为nil - // 在明确接口所指向的具体类型后,即使其值仍然为nil,但仍可以调用类型的具体方法 - car.drive() // 调用成功 - // 虽然car作为interface值时car==nil并不成立 - // 但是调用car.drive()时,向drive函数中传递的*AE86类型的特殊参数仍然是nil - // 故而在func (car *AE86) drive() {}函数的实现中,需要显式定义空指针判断 - func (car *AE86) drive() { - if car==nil { - // operations if nil... - } - // operations if non-nil... - } - ``` - - 如果在接口中,及没有保存值,也没有保存类型,那么接口值为nil,在为nil的接口值上调用方法会引发空指针异常 - ```Golang - var car Car - // 此时car接口中既没有值信息,又没有类型信息 - fmt.Println(car==nil) // 输出结果为true - - // 抛出空指针异常 - // 由于car接口中并没有保存当前的值和类型信息 - // 故而不知道应该对那个类型的drive方法进行调用 - car.drvie() - ``` - - 空接口类型interface{} - - 由于interface{}接口中没有定义任何方法,故而任何类型都实现了interface{}中所有的方法,interface{}接口可以持有仍和类型的值 - - 通常,可以在函数形参中接受interface{}类型的变量,代表接受任何类型的值 - ```Golang - // 定义新的类型any,其相当于interface{},可接受任何类型的值 - type any interface{} - ``` - - Golang中的类型断言 - - 在Golang中,接口可以在运行时持有不同类型的值,类似与面向对象中的多态 - - 通过类型断言,可以在运行时动态的判断interface持有值的类型 - ```Golang - // 运行时动态判断接口中持有值的类型 - var car Car=(*AE86)(nil) - // 断言判断 - // 1.如果interface中持有的值不是指定类型,抛出panic - val := car.(*FD) // 此时会抛出panic,终止程序 - - // 2.判断interface中持有的值是否是制定类型,如果不是,不抛出panic继续运行 - val,ok := car.(*FD) - // 如果是,ok为true,如果不是,ok为false - if ok { - // val为持有的值 - } else { - // val为该*FD类型的默认值,指针类型默认值为nil - } - ``` - - Golang中根据接口持有类型来进行switch - ```Golang - // 进行type switch - var car Car=&AE86{} - - switch v := car.(type) { - case *AE86: - // 如果car接口持有的类型是*AE86,则v的类型是*AE86,值为car持有的值 - case *FD: - // 如果car接口持有的类型是*FD,那么v的类型是*FD,值为car持有的值 - default: - // 如果car接口持有的类型不是上述类型,那么v的类型仍然是接口类型,值为car持有的值 - } - ``` - - Golang中的Stringer接口 - - Golang中通常通过Stringer中的String()方法来返回一个描述自身的字符串,而fmt包在打印信息时通常通过调用该接口的String方法来实现的 - ```Golang - type Waifu struct{ - firstName,lastName string - } - - func (waifu Waifu) String() string { - return "my waifu: "+waifu.firstName+" "+waifu.lastName - } - - fmt.Println(Waifu{"touma","kazusa"}) - ``` -- ## Golang中的错误处理 - - Golang中,通常在方法执行时,都会返回一个error值,调用方通过检查error返回值是否为nil来判断执行是否出错 - ```Golang - i,err := strconv.Atoi("1") - if err==nil { - // 转换成功 - fmt.Println(i) - } else { - // 转换失败 - fmt.Println(err) - } - ``` - - 在Golang中,通常通过error接口来获取失败的错误信息 - ```Golang - type error interface { - Error() string - } - ``` -- ## Golang中的字节流 - - Golang中,通过io.Reader接口来完成对文件的读取 - ```Golang - type Reader interface { - // Reader接口中含有一个read方法 - // read方法接受一个字节slice作为参数 - // 并且,其会将读取的字节填充到slice中 - // read方法的返回值为n和err - // n为读取的字节数 - // err为返回的异常信息,如果err返回的值是io.EOF,则代表读取到字节流的末尾 - Read(b []byte) (n int,err error) - } - ``` -- ## Golang中的泛型 - - Golang中,支持泛型函数,可以为函数指定一个类型参数,指定函数接受参数的类型 - ```Golang - // 定义泛型参数,添加对类型的约束条件,要求其可以比较 - func firstIndex[T comparable](arr []T,t T) int { - for i,v := range arr { - if v==t { - return i - } - } - return -1 - } - - fmt.Println(firstIndex[int]([]int{1,3,2,5,4},5))// 输出3 - ``` - - Golang中,除了支持泛型函数,还支持泛型struct - ```Golang - // 通过泛型struct定义单链表节点 - type Node[T any] struct { - val T - next *Node[T] - } - ``` -- ## Golang中的并发 - - Goroutine: - - Goroutine是由Go的运行时环境所管理的轻量级线程 - - Goroutine运行在相同的地址空间中,故而在Goroutinue在对地址中资源进行访问时,需要对其进行同步 - - Goroutine的开启: - ```Golang - // 开启一个新的Goroutine - // 其中,f、x、y、z的计算发生在当前的Goroutine中 - // 但是,f(x,y,z)的执行发生在新创建的Goroutine中 - go f(x,y,z) - ``` - - Channel: - - Channel是一个类型化的管道,通过<-操作符,可以从Channel中接收数据或向Channel发送数据 - - Channel的创建可以通过make函数来实现 - ```Golang - // 创建channel - ch := make(chan int) - - // 与channel的数据传输 - ch<-v // 将v中的数据发送到channel管道 - v := <-ch // 从channel中读取数据,并且将其赋值给v - ``` - - Channel中发送和接收的同步 - - 默认情况下(没有缓冲时),向channel发送数据时,需要确认接受数据的一方已经准备好 - - 在从channel接受数据时,需要确认发送数据的一端已经准备好 - - 通过上述条件,可以让Goroutine在没有显式锁和条件变量的情况下完成同步 - - 在创建channel时,可以为channel指定一个缓冲区大小 - - 当缓冲区中的数据满之后,向缓冲区填充数据的Goroutine将会被阻塞 - - 当缓冲区中的数据为空时,从缓冲区读取数据的Goroutine将会被阻塞 - ```Golang - // 如果在同一个Goroutine中,多次向channel中加入数据导致缓冲区被填满 - // 并且没有其他Goroutine来取出数据,那么当前添加数据的Goroutine将会 - // 被一直阻塞,从而产生死锁 - func main { - ch := make(chan int,2) - ch <- 1 - ch <- 2 - ch <- 3 // 此时缓冲区已满,会阻塞当前Golang,造成死锁 - } - ``` - - Channel的关闭和range迭代 - - Channel的发送方可以调用close函数对channel进行关闭 - - 向已经关闭的channel发送数据,会抛出panic - - 从已经关闭的channel中读取数据时,第二个参数ok返回为false - - 在对panic进行读取操作时,也可以用第二个参数来读取channel是否被关闭 - ```Golang - ch := make(chan int,2) - ch <- 1 - ch <- 2 - - close(ch) - - // 可以通过读取channel时的第二个参数来读取channel是否被关闭 - i,ok := <-ch - // 此时,ok代表是否ch已经关闭,i代表读取的值 - fmt.Println(i,ok) // 1 true - i,ok = <-ch - fmt.Println(i,ok) // 2 true - i,ok =<-ch - fmt.Println(i,ok) // 0 false - - // 可以对channel中的所有数据进行range循环 - // 该循环会遍历channel中所有元素,直到channel被关闭 - for i := range ch { - fmt.Println(i) - } - ``` - - Golang中的select块 - - Golang中select块可含有多个被阻塞的通信操作,当任意一个通信操作结束时,select结束阻塞并且执行其通信操作。 - - 如果在select块中有多个通信操作都处于就绪状态,其随机选择一个执行 - - 如果在select块中存在default,则在其他case均未处于就绪状态时default条件下被执行 - ```Golang - select { - case v:=<-ch: - fmt.Println(v) - case <-quit - return - default: - fmt.Println("waiting...") - time.Sleep(time.Second * 1) - } - ``` - - Golang中的互斥锁 - - Golang中为了保证临界区共享资源的安全,可以通过sync.Mutex来保证多个Goroutine访问临界资源时的并发安全 - - Mutex有Lock和Unlock方法,用于加锁和释放锁 - - 为了保证解锁的方法一定被执行,可以指定Unlock方法为defer,此时即使发生了panic,也会保证defer的Unlock方法一定被执行,锁资源被释放 - ```Golang - mut := sync.Mutex{} - cur := 0 - go func() { - for cur<9 { - mut.Lock() - if cur<9 && cur%3 == 0 { - fmt.Println("Goroutine 1") - cur++ - } - mut.Unlock() - } - }() - go func() { - for cur<9 { - mut.Lock() - if cur<9 && cur%3 == 1 { - fmt.Println("Goroutine 2") - cur++ - } - mut.Unlock() - } - }() - go func() { - for cur<9 { - mut.Lock() - if cur<9 && cur%3 == 2 { - fmt.Println("Goroutine 3") - cur++ - } - mut.Unlock() - } - }() - // 输出会显示如下 - // 1 - // 2 - // 3 - // 1 - // 2 - // 3 +# Golang基础 +- ## Golang中的包机制 + - Golang程序是由包组成的,并且在名为main的包中开始运行 + - 包的导入 + - 包可以通过import语句进行导入,在导入多个包时,可以用()将导入的多个包扩起来,并且每个包占据一行 + ```Golang + import ( + “fmt" + "math" + ) + ``` + - 包的导出 + - 在包中,如果一个名字以大写字母开头,那么这个名字将会被导出,如math.Pi会被导出,而math.pi则不会被导出 + - 在导入包时,只能够引用那些包中被导出的变量 +- ## Golang中函数 + - 在Golang中,函数可以接受一个或者多个参数,但是函数参数中参数类型位于形参名称之后 + ```Golang + func f(msg string,n int) { + fmt.Println(msg,n) + } + ``` + - 在Golang中,连续的函数参数如果都是同一种类型,那么这些连续参数的类型都可以省略,但是在相同类型的最后一个参数末尾要指明参数类型 + ```Golang + func f(a,b int,msg string) { + fmt.Println(a,b,msg) + } + ``` + - Golang函数的多值返回 + - Golang函数可以返回任意数量的返回值 + ```Golang + func f() (string,string) { + return "fuck","shit" + } + + a,b:=f() + // a:"fuck",b:"shit" + fmt.Println(a,b) + ``` + - Golang函数可以为返回值进行命名,其会被视作在函数顶部定义的变量,可以在函数体中引用变量并且对其进行修改 + - Golang函数中如果使用了命名返回值,那么在return语句后没有跟随其他值时,会将命名返回值变量当前的值 + ```Golang + func f() (retVal int) { + // retVal值默认是0 + fmt.Println(retVal) + retVal=20 + // return语句会默认返回retVal变量的值,返回值为20 + return + } + ``` +- ## Golang中的变量 + - Golang中变量的声明可以通过var关键字,并且在i变量名之后跟随类型关键字 + ```Golang + var a int + ``` + - Golang在声明变量时,可以为变量指定一个初始化器,在为每个变量指定初始化器后,变量的类型可以被省略 + ```Golang + var a,b,c=1,2,"kazusa" + fmt.Println(a,b,c) + ``` + - Golang允许在函数内,通过:=符号来声明一个变量,并且其变量的默认类型为:=后跟随的值类型 + ```Golang + // inside a func + a := 1 + fmt.Println(a) + // 在函数外部,这种变量声明的方式不被允许 + ``` +- ## Golang中的基本类型 + - Golang中基本类型如下: + - bool + - string + - int int8 int16 int32 int64 + - uint uint8 uint16 uint32 uint64 uintptr + - byte (和uint8相同) + - rune (和uint32相同,用来代表unicode字符码位) + - float32 float64 + - complex64 complex128 (复数) + ```Golang + // 在Golang中,可以采用和import一样的格式来声明 + // 多个不同类型的变量 + var ( + a,b int=1,2 + msg string="fuck" + ) + ``` + - 各类型变量在未赋初始值时的默认值 + - 数值型(整数、浮点数) : 0 + - bool: false + - string : 空字符串 + - Golang中的类型转换 + - 在Golang中,在变量声明时,如果显式指定了变量的类型,那么在后续为该变量指定初始化器或者赋值时,等式右边的类型必须和等式左边的类型相同,否则应该显式制定类型转换 + ```Golang + var a int=1 + var b int8=int8(a) + ``` + - Golang中类型推断 + - 如果在声明变量时,没有为变量显式指定类型,那么将会根据等式右边的值来推断变量类型 + - 通过 := 表达式通过等式右边表达式进行推断 + - 在var关键字右边通过初始化器来推断类型 + ```Golang + // 默认情况下,整数类型的字面量将会被推断为int + // 浮点数类型的字面量将会被推断为float64 + // 复数类型将会被推断为complex128 + var a = 1 // a被推断为int类型 + var f = 1.0 // f被推断为float64类型 + ``` +- ## Golang中的常量 + - Golang中常量的声明和变量类似,但是使用const关键字 + - 常量可以是bool、string、数值、字符 + - 常量的声明无法使用 := 方式 + ```Golang + const ( + a,b int=1,2 + c string="shiro" + ) + fmt.Println(a,b,c) + ``` +- ## Golang中的循环 + - 在Golang中,只存在有一种循环,for循环。 + - Golang中for循环结构如下: + ```Golang + // 其结构类似与java和c中的for循环 + // 其中,init和post部分是可选的 + // for ;condition expression; {} + for init statement;condition expression;post statement { + // loop body + } + ``` + - 在Golang中while循环结构如下: + ```Golang + for expression { + + } + ``` + - 在Golang中,如果想实现无限循环,expression可以被省略 + ```Golang + for { + // infinite loop + + } + ``` +- ## Golang中的条件分支 + - 在Golang中,if的条件表达式不需要用小括号扩起来,但是if后跟的语句块必须用大括号包起来 + ```Golang + if condition-A-expression { + // condition A + } else if condition-B-expression { + // condition B + } else { + // condition else + } + /** + * 此时else if/else和上一个条件的'}'符号必须位于同一行 + **/ + ``` + - 在Golang中的if语句中,可以在条件表达式之前添加一个执行语句,在执行语句中定义的变量只能在if和else if/else块中被访问 + ```Golang + if msg:="msg content";expr1 { + fmt.Println(msg) + } else { + fmt.Println(msg) + } + ``` +- ## Golang中的switch语句 + - 在Golang中,并不需要为switch中的每个case手动添加break,Golang的switch只会执行第一个匹配的case后的语句 + - 在Golang中,case条件后跟的不一定非要是常量,也可以是变量或者是函数调用 + - 在Golang中,case后跟的也不一定是整形,而可以是其他类型 + ```Golang + func f() { + return 0 + } + + // ... + a:=0 + switch a { + case f(): + fmt.Println("matched") + default: + fmt.Println("missed") + } + ``` + - 在Golang中,switch语句可以不跟条件表达式,其默认和switch true相同: + ```Golang + switch{ + case condition-1: + // ... + case condition-2: + // ... + default: + // ... + } + 和 + if condition-1 { + //... + }else if condition-2 { + //... + }else { + //... + } + 相同 + ``` +- ## Golang中的defer + - 在Golang中,可以用defer关键字将函数的执行推迟到当前defer语句所处的函数执行完成之后 + - 在Golang中,defer关键字修饰的函数调用,其参数是立即被计算的,但是函数调用会被推迟到外围函数执行结束之后 + - Golang中defer推迟的函数调用将会被压入到栈结构中,如果在同一个函数中存在多个defer调用,那么在函数执行结束后,后被压入栈结构的defer调用会先被调用 + ```Golang + func f() { + fmt.Println("function begin") + + defer fmt.Println(1) + defer fmt.Println(2) + defer fmt.Println(3) + + fmt.Println("function end") + } + // 在调用f()后,其输出会按如下顺序 + // function begin + // funtion end + // 3 + // 2 + // 1 + ``` +- ## Golang中的指针 + - Golang中指针的声明 + ```Golang + var p *int + ``` + - Golang中的取址操作 + ```Golang + var ( + i int = 1 + p *int = &i + ) + ``` + - Golang中的解引用操作 + ```Golang + var ( + i int = 1 + p *int = &i + ) + fmt.Println(*p) + *p=2 + fmt.Println(*p) + ``` + - Golang中并不存在指针的算数,如通过+或者-一个指针将指针地址向前、向后推移 +- ## Golang中的struct + - Golang中struct的定义 + ```Golang + type Node struct { + val int + next *int + } + + fmt.Println(Node{1,2}) + ``` + - Golang结构体中域的引用 + ```Golang + type Result struct { + retCode int + msg string + } + + var result Result=Result{200 "response success"} + fmt.Println(result.retCode,result.msg) + ``` + - 通过指针访问结构体中的内容 + ```Golang + node := Node{0,nil} + // 要想通过指针访问结构体中的域,可以如下所示 + fmt.Println((*node).val) + // 也可以直接在指针后调用. + fmt.Println(node.val) + ``` + - 结构体字面量 + ```Golang + // 可以通过为每个域按顺序指定值 + var result Result=Result{ + 200, + "请求成功" + } + // 可以通过filedName:value来为域的子集指定值 + // 其他未指定的值为默认值 + var result Result=Result{ + // retCode未指定默认为0 + msg:"请求成功" + } + // 可以不为域指定值,域中所有值都为默认值 + result := Result{} + ``` +- ## Golang中的数组 + - Golang中数组类型为[n]T,代表长度为n的T类型的数组 + - Golang中的数组无法被扩容 + - slice:slice中包含数组中元素的子集,可以作为数组的一个动态视图,通过slice比数组使用的更为广泛 + - slice的类型为[]T,T是元素的类型 + - slice本身并不存储任何元素,其只是一个针对数组中一定范围内元素的引用 + - 在slice中对元素进行的更改在数组中也可见,在数组中对元素进行的更改同样在slice中可见 + - 可以对slice创建slice + - 在创建slice之前无需先创建数组,可以直接创建slice,创建slice的同时会创建数组并且让slice引用创建的数组 + ```Golang + // 声明一个数组 + arr := [5]int{1,2,3,4,5} + // 对数组进行切片,获取数组的slice + // 其中以array[lo : hi]形式来切片 + // slice中包含下标为lo的元素 + // 但是slice不包含下标为hi的元素 + slice := arr[1:3] + + // 直接创建slice + slice_dir=[]int{1,2,3,4,5} + ``` + - 在进行slice操作时,可以对下标的下界和上界进行省略,在省略下界时,默认下界为0,在省略上界时,默认值为数组长度 + ```Golang + arr := []int{1,2,3,4,5,6,7} + fmt.Println(arr[:4][1:]) // 返回[2,3,4] + ``` + - slice的length和capacity + ```Golang + // slice的length是指slice中元素的个数 + // slice的capacity是值从slice中第一个元素开始算起,到 + // array中的最后一个元素,一共有多少个元素 + arr := []int{1,2,3,4,5,6,7,8,9} + + slice := arr[1:4] + fmt.Println(len(arr),cap(arr)) + // 输出length为3 + // 输出cap为8 + ``` + - slice可以对其进行重新切片,虽然无法通过数组下标访问位于slice范围外的元素,但是可以通过重新切片来将slice范围扩大到数组范围外 + ```Golang + arr := []{1,2,3,4,5,6,7,8,9} + + // 切片[2,3,4] + arr = arr[1:4] + // 重新切片为[2,3,4,5] + arr = arr[:4] + ``` + - slice变量的默认值是nil,其cap和len都是0,并且没有底层的数组 + - Golang中创建动态大小的数组 + ```Golang + // make函数类似于c++中的new T[n],返回一个slice + // 返回数组中元素值都是默认值 + + // 创建一个slice,并且指定len和cap为相同值 + // 其中len为5,cap为5 + arr := make([]int,5) + + // 创建一个slice,并分别指定len和cap + // 其中,len为5,cap为10 + arr := make([]int,5,10) + ``` + - Slice中可以包含slice,类似于多维数组 + ```Golang + slice := [][]string { + []string {"touma","kazusa"}, + []string {"kitahara","haruki"} + } + ``` + - Golang中向slice添加元素 + - 可以通过append方法向slice中添加元素,如果slice中位于len后的cap可以容纳添加的所有元素,就在当前数组中修改位于slice之后的元素 + - 如果当前slice的cap无法容纳append中所有的元素,会重新创建一个数组,拷贝当前slice中所有的元素,在添加元素后返回一个指向新分配数组的slice + ```Golang + arr := []int{1,2,3,4} + t := append(arr[:3],-1,2) + fmt.Println(arr,t) + // 输出结果如下 + // arr [1,2,3,4] + // t [1,2,3,-1,2] + // arr和t并不指向同一个底层数组 + ``` +- ## Range的形式迭代slice + - 可以通过range的形式对slice进行迭代: + ```Golang + // 其中i是当前迭代元素的下标 + // v是当前迭代元素值的拷贝 + for i,v := range slice { + fmt.Println(i,v) + } + ``` + - 在只想在range中访问index或是value时,可以使用_作为占位符 + ```Golang + // 省略value + for i,_ := range slice { + fmt.Println(i) + } + + // 省略value时,_也可以省略 + for i := range slice { + fmt.Println(i) + } + + // 省略index + for _,v := range slice { + fmt.Println(v) + } + ``` +- ## Golang中的map + - 在Golang中,map的默认值是nil,既没有键值对,也无法加入键值对 + - 可以通过make函数返回指定类型的map,返回的map已经被初始化并且准备好被使用 + ```Golang + m := make(map[string]string) + m["shiro"]="kana" + m["black"]="kazusa" + fmt.Println(m) + ``` + - map字面量 + ```Golang + m := map[string]string{ + "shiro":"kana", + "black":"kazusa", + } + fmt.Println(m) + ``` + - map中如果字面量中元素的值是struct类型,那么可以省略值类型中的类型名称 + ```Golang + type Point struct { + X float64 + Y float64 + } + + m := map[string]Point{ + "point-a":{1,1}, + "point-b":{2,2} + } + + fmt.Println(m) + ``` + - 对map进行操作 + ```Golang + // 插入或者更新map中元素 + m["touma"]="kazusa" + + // 获取map中元素,如果map中不存在该元素,返回该元素类型的默认值 + elem = m["touma"] + + // 判断map中是否存在key为指定值的键值对 + elem,ok := m["shiro"] + // 如果不存在,elem为默认值,ok为false + + // 从map中删除key为指定值的元素 + delete(m,key) + ``` +- ## Golang中函数的值传递 + - Golang中函数可以作为值传递给变量或者其他函数的参数,也可以作为其他函数的返回值 + ```Golang + func operateOnArgs(f func (float64,float64) float64,a,b float64) float64 { + return f(a,b) + } + + var f=func(a,b float64) float64{ + return math.Sqrt(a*a+b*b) + } + fmt.Println(operateOnArgs(f,3,4)) + ``` + - Golang中函数的闭包 + - Golang中支持函数的闭包,通过将一个函数作为函数的返回值,返回的函数可以访问外层函数中定义的局部变量,位于外层函数之外只能通过返回的函数来访问外层函数内部的局部变量,如此保证了局部变量的安全性 + ```Golang + func adder() func(int) int { + sum := 0 + return func(a int) int { + sum+=a + return sum + } + + } + ``` +- ## Golang中的方法 + - 虽然Golang中并不像其他语言一样存在类(class),但是我们可以在Golang中为类型(type)定义方法 + - 在Golang中,为类型(type)定义方法是定义一个接受特定类型参数的函数 + ```Golang + type Point struct { + X,Y float64 + } + + // 为Point类型定义方法 + func (p Point) Abs() float64 { + return math.Sqrt(p.X*p.X+p.Y*p.Y) + } + + // 可以通过如下形式调用为类型定义的方法 + p := Point{3,4} + fmt.Println(p.Abs()) + ``` + - 在Golang中,不仅可以为struct类型指定方法,而且可以为基本类型指定方法(例如type MyFloat float64后,为MyFloat类型指定方法) + - 在Golang中,只能够为位于同一个包中的类型指定方法,无法为位于其他包中的类型指定方法 + ```Golang + type MyFloat float64 + + func (f MyFloat) fuck() { + fmt.Println("fucking float64") + } + ``` + - 在Golang中,除了可以为类型指定方法外,还可以为类型的指针指定方法,此时特殊参数接受一个指针,可以通过指针修改传输类型的值 + ```Golang + type Point struct { + X,Y float64 + } + + // 定义函数接受一个Point类型的指针 + func (p *Point) modify() { + p.X *= 10 + p.Y *= 10 + } + + // 调用时无需先将类型对象转化为指针,可以直接在对象上调用 + p := Point{3,4} + p.modify() + // 调用后p为{30,40} + + // 接受一个Point类型的拷贝 + func (p Point) modifyCopy() { + p.X *= 10 + p.Y *= 10 + } + + // 调用时传入函数的是对象的一个拷贝,不会修改原先对象的值 + p := Point{3,4} + p.modifyCopy() + // 调用后仍然为{3,4},修改的只是拷贝对象的值 + ``` + - 在Golang中,普通函数参数,必须向接受指针的形参中传入指针,向接受值的形参中传入值;但是在接受特殊参数的位置,如果想要接受的是值类型,那么传入指针和传入值均可;如果想在特殊参数位置接受指针类型,那么传入指针和传入值类型也均可 + ```Golang + func (p *Point) modify() { + // func body + } + + // 对于如下调用形式均可 + p := Point{3,4} + + p.modify() // 可行的调用方式 + (&p).modify() //可行的调用方式 + + func (p Point) modifyCopy() { + // func + } + + p := Point{3,4} + // 对接受值的特殊参数,下列调用方式也均可 + p.modifyCopy() // 可行 + (&p).modifyCopy() //可行 + ``` +- ## Golang中的接口 + - 在Golang中,interface中定义了一系列的方法签名,对于实现了interface中定义所有方法签名的类型,其都可以被赋值给interface类型 + - 如果对一个类型的指针实现了interface接口,那么只能将该类型的指针赋值给interface变量,无法将该类型赋值给interface变量 + ```Golang + type Car interface { + drive() + } + + type AE86 struct { + } + + // 为AE86类型的指针实现接口中drive方法 + func (car *AE86) drive() { + + } + + // 此时,可以将*AE86类型赋值给Car,但是无法将AE86赋值给Car + var car Car + car = AE86{} // 失败 + car = &AE86{} // 成功 + ``` + - 接口中保存的信息通常可以看做一个二元组:(具体的值,值的类型) + ```Golang + // 接口中保存的值如果是nil,但是其类型已经确定,那么接口的值就不为nil + var car Car + car=(*AE86)(nil) + fmt.Println(car==nil) // 输出为false + // 此时,虽然car仍然不指向具体的对象,但是其指向的类型确定为Car,故而其不为nil + // 在明确接口所指向的具体类型后,即使其值仍然为nil,但仍可以调用类型的具体方法 + car.drive() // 调用成功 + // 虽然car作为interface值时car==nil并不成立 + // 但是调用car.drive()时,向drive函数中传递的*AE86类型的特殊参数仍然是nil + // 故而在func (car *AE86) drive() {}函数的实现中,需要显式定义空指针判断 + func (car *AE86) drive() { + if car==nil { + // operations if nil... + } + // operations if non-nil... + } + ``` + - 如果在接口中,及没有保存值,也没有保存类型,那么接口值为nil,在为nil的接口值上调用方法会引发空指针异常 + ```Golang + var car Car + // 此时car接口中既没有值信息,又没有类型信息 + fmt.Println(car==nil) // 输出结果为true + + // 抛出空指针异常 + // 由于car接口中并没有保存当前的值和类型信息 + // 故而不知道应该对那个类型的drive方法进行调用 + car.drvie() + ``` + - 空接口类型interface{} + - 由于interface{}接口中没有定义任何方法,故而任何类型都实现了interface{}中所有的方法,interface{}接口可以持有仍和类型的值 + - 通常,可以在函数形参中接受interface{}类型的变量,代表接受任何类型的值 + ```Golang + // 定义新的类型any,其相当于interface{},可接受任何类型的值 + type any interface{} + ``` + - Golang中的类型断言 + - 在Golang中,接口可以在运行时持有不同类型的值,类似与面向对象中的多态 + - 通过类型断言,可以在运行时动态的判断interface持有值的类型 + ```Golang + // 运行时动态判断接口中持有值的类型 + var car Car=(*AE86)(nil) + // 断言判断 + // 1.如果interface中持有的值不是指定类型,抛出panic + val := car.(*FD) // 此时会抛出panic,终止程序 + + // 2.判断interface中持有的值是否是制定类型,如果不是,不抛出panic继续运行 + val,ok := car.(*FD) + // 如果是,ok为true,如果不是,ok为false + if ok { + // val为持有的值 + } else { + // val为该*FD类型的默认值,指针类型默认值为nil + } + ``` + - Golang中根据接口持有类型来进行switch + ```Golang + // 进行type switch + var car Car=&AE86{} + + switch v := car.(type) { + case *AE86: + // 如果car接口持有的类型是*AE86,则v的类型是*AE86,值为car持有的值 + case *FD: + // 如果car接口持有的类型是*FD,那么v的类型是*FD,值为car持有的值 + default: + // 如果car接口持有的类型不是上述类型,那么v的类型仍然是接口类型,值为car持有的值 + } + ``` + - Golang中的Stringer接口 + - Golang中通常通过Stringer中的String()方法来返回一个描述自身的字符串,而fmt包在打印信息时通常通过调用该接口的String方法来实现的 + ```Golang + type Waifu struct{ + firstName,lastName string + } + + func (waifu Waifu) String() string { + return "my waifu: "+waifu.firstName+" "+waifu.lastName + } + + fmt.Println(Waifu{"touma","kazusa"}) + ``` +- ## Golang中的错误处理 + - Golang中,通常在方法执行时,都会返回一个error值,调用方通过检查error返回值是否为nil来判断执行是否出错 + ```Golang + i,err := strconv.Atoi("1") + if err==nil { + // 转换成功 + fmt.Println(i) + } else { + // 转换失败 + fmt.Println(err) + } + ``` + - 在Golang中,通常通过error接口来获取失败的错误信息 + ```Golang + type error interface { + Error() string + } + ``` +- ## Golang中的字节流 + - Golang中,通过io.Reader接口来完成对文件的读取 + ```Golang + type Reader interface { + // Reader接口中含有一个read方法 + // read方法接受一个字节slice作为参数 + // 并且,其会将读取的字节填充到slice中 + // read方法的返回值为n和err + // n为读取的字节数 + // err为返回的异常信息,如果err返回的值是io.EOF,则代表读取到字节流的末尾 + Read(b []byte) (n int,err error) + } + ``` +- ## Golang中的泛型 + - Golang中,支持泛型函数,可以为函数指定一个类型参数,指定函数接受参数的类型 + ```Golang + // 定义泛型参数,添加对类型的约束条件,要求其可以比较 + func firstIndex[T comparable](arr []T,t T) int { + for i,v := range arr { + if v==t { + return i + } + } + return -1 + } + + fmt.Println(firstIndex[int]([]int{1,3,2,5,4},5))// 输出3 + ``` + - Golang中,除了支持泛型函数,还支持泛型struct + ```Golang + // 通过泛型struct定义单链表节点 + type Node[T any] struct { + val T + next *Node[T] + } + ``` +- ## Golang中的并发 + - Goroutine: + - Goroutine是由Go的运行时环境所管理的轻量级线程 + - Goroutine运行在相同的地址空间中,故而在Goroutinue在对地址中资源进行访问时,需要对其进行同步 + - Goroutine的开启: + ```Golang + // 开启一个新的Goroutine + // 其中,f、x、y、z的计算发生在当前的Goroutine中 + // 但是,f(x,y,z)的执行发生在新创建的Goroutine中 + go f(x,y,z) + ``` + - Channel: + - Channel是一个类型化的管道,通过<-操作符,可以从Channel中接收数据或向Channel发送数据 + - Channel的创建可以通过make函数来实现 + ```Golang + // 创建channel + ch := make(chan int) + + // 与channel的数据传输 + ch<-v // 将v中的数据发送到channel管道 + v := <-ch // 从channel中读取数据,并且将其赋值给v + ``` + - Channel中发送和接收的同步 + - 默认情况下(没有缓冲时),向channel发送数据时,需要确认接受数据的一方已经准备好 + - 在从channel接受数据时,需要确认发送数据的一端已经准备好 + - 通过上述条件,可以让Goroutine在没有显式锁和条件变量的情况下完成同步 + - 在创建channel时,可以为channel指定一个缓冲区大小 + - 当缓冲区中的数据满之后,向缓冲区填充数据的Goroutine将会被阻塞 + - 当缓冲区中的数据为空时,从缓冲区读取数据的Goroutine将会被阻塞 + ```Golang + // 如果在同一个Goroutine中,多次向channel中加入数据导致缓冲区被填满 + // 并且没有其他Goroutine来取出数据,那么当前添加数据的Goroutine将会 + // 被一直阻塞,从而产生死锁 + func main { + ch := make(chan int,2) + ch <- 1 + ch <- 2 + ch <- 3 // 此时缓冲区已满,会阻塞当前Golang,造成死锁 + } + ``` + - Channel的关闭和range迭代 + - Channel的发送方可以调用close函数对channel进行关闭 + - 向已经关闭的channel发送数据,会抛出panic + - 从已经关闭的channel中读取数据时,第二个参数ok返回为false + - 在对panic进行读取操作时,也可以用第二个参数来读取channel是否被关闭 + ```Golang + ch := make(chan int,2) + ch <- 1 + ch <- 2 + + close(ch) + + // 可以通过读取channel时的第二个参数来读取channel是否被关闭 + i,ok := <-ch + // 此时,ok代表是否ch已经关闭,i代表读取的值 + fmt.Println(i,ok) // 1 true + i,ok = <-ch + fmt.Println(i,ok) // 2 true + i,ok =<-ch + fmt.Println(i,ok) // 0 false + + // 可以对channel中的所有数据进行range循环 + // 该循环会遍历channel中所有元素,直到channel被关闭 + for i := range ch { + fmt.Println(i) + } + ``` + - Golang中的select块 + - Golang中select块可含有多个被阻塞的通信操作,当任意一个通信操作结束时,select结束阻塞并且执行其通信操作。 + - 如果在select块中有多个通信操作都处于就绪状态,其随机选择一个执行 + - 如果在select块中存在default,则在其他case均未处于就绪状态时default条件下被执行 + ```Golang + select { + case v:=<-ch: + fmt.Println(v) + case <-quit + return + default: + fmt.Println("waiting...") + time.Sleep(time.Second * 1) + } + ``` + - Golang中的互斥锁 + - Golang中为了保证临界区共享资源的安全,可以通过sync.Mutex来保证多个Goroutine访问临界资源时的并发安全 + - Mutex有Lock和Unlock方法,用于加锁和释放锁 + - 为了保证解锁的方法一定被执行,可以指定Unlock方法为defer,此时即使发生了panic,也会保证defer的Unlock方法一定被执行,锁资源被释放 + ```Golang + mut := sync.Mutex{} + cur := 0 + go func() { + for cur<9 { + mut.Lock() + if cur<9 && cur%3 == 0 { + fmt.Println("Goroutine 1") + cur++ + } + mut.Unlock() + } + }() + go func() { + for cur<9 { + mut.Lock() + if cur<9 && cur%3 == 1 { + fmt.Println("Goroutine 2") + cur++ + } + mut.Unlock() + } + }() + go func() { + for cur<9 { + mut.Lock() + if cur<9 && cur%3 == 2 { + fmt.Println("Goroutine 3") + cur++ + } + mut.Unlock() + } + }() + // 输出会显示如下 + // 1 + // 2 + // 3 + // 1 + // 2 + // 3 ``` \ No newline at end of file diff --git a/README.md b/README.md index e25862d..b496cf2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,2 @@ -# rikako-note -A Personal Note of Rikako Wu... +# rikako-note +A Personal Note of Rikako Wu... diff --git a/html/html基础.md b/html/html基础.md index 637d7c7..88279e2 100644 --- a/html/html基础.md +++ b/html/html基础.md @@ -1,458 +1,735 @@ -# html基础 -- ## html中知识要点 - - html中空格 - - 不管在html元素中添加了多少空格或者换行,其连续的多个空格都会被替换为一个空格,块元素中的换行符会被取消,除非显式指定
- - html中特殊符号: - - 在html中,< > ' " 都是特殊的符号,其都是html语法的一部分,故而在文本中如果存在这些特殊字符,可以通过特殊的引用来表示该特殊字符 - - 特殊的用来表示该类字符的表达式以&开头,以;结尾,具体如下 - ```shell - < 可以用 < (less than) - > 可以用 > (greater than) - " 可以用 " - ' 可以用 ' - & 可以用 & - - // 例如,可以在

中包含如下内容 -

This is content of element <p>!

- // 其会显示如下内容 - This is content of element

! - ``` - - html中评论: - ```html - - ``` - - html head: - - head标签中的信息并不显示在html页面中,html中包含的是html页面的元信息 - - head中可以包含如下信息: - - title:该页面显示在title标签栏中的标题内容 - - meta:meta标签用来定义元信息 - - 通过meta元信息指定文档使用的字符集: - ```html - - ``` - - 通过meta元信息为页面指定作者和页面描述信息: - ```html - - - - ``` - - 为页面制定favicon图标: - - 在index.html路径下防治ico图标 - - 在head元素中添加如下标签 - ```html - - - 向页面中添加css样式 - - 用rel指定该link为stylesheet - - 用href来指定css样式表的路径 - ```html - - ``` - - 向页面中添加script脚本 - - 指定defer,可以在页面完成解析后再执行引入的js脚本 - - 用src属性指定js脚本路径 - ```html - // 除了可以引入外部脚本外,还可以在script标签中加入 - // js代码 - - ``` - - 为文档指定语言信息 - - 可以在html标签中制定lang属性来为文档指定使用的语言 - ```html - - ``` - - html body中的重要元素 - - 强调某些单词 - - em:通过em标签,通常会通过斜体的效果来加强某些单词 - - strong:通过strong标签,通常会通过加粗的方式来强调某些单词 - - 超链接(hyperlink) - - 超链接语法如下,通常用于在不同的document之间进行跳转 - - 可以通过title属性来为超链接添加一些信息,当鼠标hover时,添加信息将会以tooltip的形式显示 - ```html - link to baidu homepage! - ``` - - 通过hyperlink链接到文档的特定部分,而非是跳转到文档顶部 - ```html - - link to baidu ele-id! - ``` - - 当想要下载链接到的资源而不是在浏览器中打开时,可以在hyperlink中制定download属性,并且为其赋值一个字符串用来表示文件名 - ```html - - download file - ``` - - 描述性列表(description list) - - dl可以为每一个列表项添加dt(description term)和dd(description definition) - - 可以为同一个dt添加多个dd - ```html -

fruits -
apple
-
- fruit with red color! -
-
banana
-
- fruit with yellow color! -
-
- fruit with bar shape! -
-
- ``` - - 引用(quote) - - 引用可以分为块级引用和内联引用 - - blockquote - ```html -
- quote content... -
- ``` - - q - ```html -

This is an inline quote: - quote content...

- ``` - - 缩写(abbr) - - 缩写用来标注缩写,并且可以在title属性中指定全称,全称在hover时以tooltip的形式显示 - ```html -

HTML - is used commonly in web area!

- ``` - - 上标或下标(sub和sup) - - sup标记用来处理上标,sub标记用来处理下标 - ```html -

water is H2O

- ``` - - 标记代码 - - <code>用来表示通用的代码部分 - - <pre>用来保持编辑器中的格式 - - <kbd>用来表示命令行输入 - - <samp>用来表示程序输出 - - <var>用来代表变量 - - html结构 - - header - - <header> - - navigation bar - - <nav> - - main content - - <main> - - <main>标签中通常含有<section>,<div>,<article>等元素 - - side bar - - <aside>通常被放置在<main>中 - - footer - - <footer> - - <hr> - - <hr>会在页面中间创建一条横线,用来分割之前和之后的内容 - ```html -
- Section A -
-
-
- Section B -
- ``` -- ## html中添加多媒体 - - html中添加图片 - - 在html页面中添加图片可以通过<img>元素来实现 - - 可以为图片指定title属性,当鼠标hover时会通过tooltip显示信息 - ```html - - Picture of Waifu - ``` - - <figure>和<figcaption> - - <figure>可以为内容添加说明性文字 - ```html -
- waifu -
- Touma Kazusa in WA2 -
-
- ``` - - html中添加video - - 可以通过<video>来向html中嵌入video - - 在video的tag中可以嵌套内容,当当前的浏览器不支持video tag时,会显示嵌套的内容 - ```html - - ``` - - 为<video>指定多个不同格式的视频源,让视频能够在不同浏览器平台都得到播放 - ```html - - ``` - - video的其他属性: - - autoplay:页面加载时直接开始播放视频 - - width/height:设置宽度和高度 - - loop:视频播放完后循环播放 - - muted:视频以静音的形式播放 - - poster:在视频播放前,poster指定url的图片将会被显示 - - preload:用来缓存文件 - - “none”:不缓存文件 - - “auto”:缓存文件 - - “metadata”:只缓存元信息 - - html中添加audio - - 可以通过<audio>来添加音频数据 - ```html - - ``` - - html中添加字幕 - ```html - -- ## html中嵌入其他元素 - - <iframe>元素的使用 - - <iframe>通常用于向文本中嵌入其他文档或来源于其他网站的视频信息,其有如下属性 - - allowfullscreen:如果存在该属性,iframe元素可以被全屏化 - - src:用于指向想要嵌入元素的url - - width/height:用于指定iframe元素的宽度和高度 - - fallbackContent:如果当前浏览器不支持iframe,会显示fallbackContent中的内容 - - sandbox:沙箱,安全性更加高 - ```html - - ``` - - iframe安全 - - sandbox是一个容器,在容器中的代码可以被正确的使用和测试,但是无法对容器外的其他部分造成任何伤害。 - - 没有在sandbox中运行的内容可以运行js代码、提交表单、弹出窗口,会造成安全问题。故而,在使用sandbox时,应该使用没有参数的sandox属性,应用所有的安全约束 - - 不要同时给予sandbox以allow-script和allow-same-origin权限,否则可以通过allow-same-origin绕过同源策略,并且通过allow-script运行js脚本关闭沙箱 - - 通过X-Frame-Options的HTTP响应头字段,可以设置SAMEORIGIN或者DENY,当设置DENY时,当前页面无法被嵌入到其他页面的iframe中,如果设置为SAMEORIGIN,当前页面可以被嵌入到来自同一origin的其他页面中 -- ## 响应式图像 - - 为不同的屏幕宽度选用不同的分辨率图片 - ```html - img... - ``` - - 为不同物理像素/逻辑像素值的设备来选用不同分辨率图片 - ```html - img... - ``` - - 为不同屏幕宽度的设备选用不同的图片 - ```html - - - - img... - - ``` -- ## html表格 - - <table>:表示table标签 - - <th>:表示表格的行、列标题 - - <tr>:表示表格的行 - - <td>:表示表格的单元行 - ```html - - - - - - - - - - - - - -
NameAge
Touma17
Ogiso17
- ``` - - 可以通过rowspan和colspan属性来控制单元格跨行和列的数目 - ```html - - - - - - - - - - - - - - - - - - - - - - - - - -
- Waifu -
JapanFrance
ToumaCharles
waifu
KazusaJapan
Austria
- ``` - - colgroup和col - - <colgroup>:col的容器 - - <col>:col通常用来指定表格中列的样式 - ```html - - - - - - - - - - - - - -
NameAge
Touma17
- ``` - - caption:添加描述性文本,描述性文本位于表格的正上方 - ```html - - - - - - - - - - -
Waifu Table
NameAge
Touma17
- ``` - - thead,tbody,tfoot - - thead通常用来标注表头的行,即<th>标签所在的行 - - tfoot通常用来标注表尾信息,比如对上述内容之和的SUM统计 - - tbody通常用来标注表格除thead和tfoot之外的其他信息 - ```html - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cost Summary
Term 1Term 2
35
12
23
- ``` - - 可以在td中嵌套table表格 - ```html - - - - - - - - - - - - -
Waifu
- - - - - - - - - -
NameAge
Touma17
-
- - - - - - - - - -
CityJob
TokyoPianoist
-
- ``` - - scope属性:在th标签中,具有scope属性,可以指明该th对应的是行标题、列标题、行组标题、列组标题,scope标签对应如下值: - - row - - col - - rowgroup - - colgroup -- Web表单 - - - - - - - - +# html基础 +- ## html中知识要点 + - html中空格 + - 不管在html元素中添加了多少空格或者换行,其连续的多个空格都会被替换为一个空格,块元素中的换行符会被取消,除非显式指定
+ - html中特殊符号: + - 在html中,< > ' " 都是特殊的符号,其都是html语法的一部分,故而在文本中如果存在这些特殊字符,可以通过特殊的引用来表示该特殊字符 + - 特殊的用来表示该类字符的表达式以&开头,以;结尾,具体如下 + ```shell +
可以用 > (greater than) + " 可以用 " + ' 可以用 ' + & 可以用 & + + // 例如,可以在

中包含如下内容 +

This is content of element <p>!

+ // 其会显示如下内容 + This is content of element

! + ``` + - html中评论: + ```html + + ``` + - html head: + - head标签中的信息并不显示在html页面中,html中包含的是html页面的元信息 + - head中可以包含如下信息: + - title:该页面显示在title标签栏中的标题内容 + - meta:meta标签用来定义元信息 + - 通过meta元信息指定文档使用的字符集: + ```html + + ``` + - 通过meta元信息为页面指定作者和页面描述信息: + ```html + + + + ``` + - 为页面制定favicon图标: + - 在index.html路径下防治ico图标 + - 在head元素中添加如下标签 + ```html + + - 向页面中添加css样式 + - 用rel指定该link为stylesheet + - 用href来指定css样式表的路径 + ```html + + ``` + - 向页面中添加script脚本 + - 指定defer,可以在页面完成解析后再执行引入的js脚本 + - 用src属性指定js脚本路径 + ```html + // 除了可以引入外部脚本外,还可以在script标签中加入 + // js代码 + + ``` + - 为文档指定语言信息 + - 可以在html标签中制定lang属性来为文档指定使用的语言 + ```html + + ``` + - html body中的重要元素 + - 强调某些单词 + - em:通过em标签,通常会通过斜体的效果来加强某些单词 + - strong:通过strong标签,通常会通过加粗的方式来强调某些单词 + - 超链接(hyperlink) + - 超链接语法如下,通常用于在不同的document之间进行跳转 + - 可以通过title属性来为超链接添加一些信息,当鼠标hover时,添加信息将会以tooltip的形式显示 + ```html + link to baidu homepage! + ``` + - 通过hyperlink链接到文档的特定部分,而非是跳转到文档顶部 + ```html + + link to baidu ele-id! + ``` + - 当想要下载链接到的资源而不是在浏览器中打开时,可以在hyperlink中制定download属性,并且为其赋值一个字符串用来表示文件名 + ```html + + download file + ``` + - 描述性列表(description list) + - dl可以为每一个列表项添加dt(description term)和dd(description definition) + - 可以为同一个dt添加多个dd + ```html +

fruits +
apple
+
+ fruit with red color! +
+
banana
+
+ fruit with yellow color! +
+
+ fruit with bar shape! +
+
+ ``` + - 引用(quote) + - 引用可以分为块级引用和内联引用 + - blockquote + ```html +
+ quote content... +
+ ``` + - q + ```html +

This is an inline quote: + quote content...

+ ``` + - 缩写(abbr) + - 缩写用来标注缩写,并且可以在title属性中指定全称,全称在hover时以tooltip的形式显示 + ```html +

HTML + is used commonly in web area!

+ ``` + - 上标或下标(sub和sup) + - sup标记用来处理上标,sub标记用来处理下标 + ```html +

water is H2O

+ ``` + - 标记代码 + - <code>用来表示通用的代码部分 + - <pre>用来保持编辑器中的格式 + - <kbd>用来表示命令行输入 + - <samp>用来表示程序输出 + - <var>用来代表变量 + - html结构 + - header + - <header> + - navigation bar + - <nav> + - main content + - <main> + - <main>标签中通常含有<section>,<div>,<article>等元素 + - side bar + - <aside>通常被放置在<main>中 + - footer + - <footer> + - <hr> + - <hr>会在页面中间创建一条横线,用来分割之前和之后的内容 + ```html +
+ Section A +
+
+
+ Section B +
+ ``` +- ## html中添加多媒体 + - html中添加图片 + - 在html页面中添加图片可以通过<img>元素来实现 + - 可以为图片指定title属性,当鼠标hover时会通过tooltip显示信息 + ```html + + Picture of Waifu + ``` + - <figure>和<figcaption> + - <figure>可以为内容添加说明性文字 + ```html +
+ waifu +
+ Touma Kazusa in WA2 +
+
+ ``` + - html中添加video + - 可以通过<video>来向html中嵌入video + - 在video的tag中可以嵌套内容,当当前的浏览器不支持video tag时,会显示嵌套的内容 + ```html + + ``` + - 为<video>指定多个不同格式的视频源,让视频能够在不同浏览器平台都得到播放 + ```html + + ``` + - video的其他属性: + - autoplay:页面加载时直接开始播放视频 + - width/height:设置宽度和高度 + - loop:视频播放完后循环播放 + - muted:视频以静音的形式播放 + - poster:在视频播放前,poster指定url的图片将会被显示 + - preload:用来缓存文件 + - “none”:不缓存文件 + - “auto”:缓存文件 + - “metadata”:只缓存元信息 + - html中添加audio + - 可以通过<audio>来添加音频数据 + ```html + + ``` + - html中添加字幕 + ```html + +- ## html中嵌入其他元素 + - <iframe>元素的使用 + - <iframe>通常用于向文本中嵌入其他文档或来源于其他网站的视频信息,其有如下属性 + - allowfullscreen:如果存在该属性,iframe元素可以被全屏化 + - src:用于指向想要嵌入元素的url + - width/height:用于指定iframe元素的宽度和高度 + - fallbackContent:如果当前浏览器不支持iframe,会显示fallbackContent中的内容 + - sandbox:沙箱,安全性更加高 + ```html + + ``` + - iframe安全 + - sandbox是一个容器,在容器中的代码可以被正确的使用和测试,但是无法对容器外的其他部分造成任何伤害。 + - 没有在sandbox中运行的内容可以运行js代码、提交表单、弹出窗口,会造成安全问题。故而,在使用sandbox时,应该使用没有参数的sandox属性,应用所有的安全约束 + - 不要同时给予sandbox以allow-script和allow-same-origin权限,否则可以通过allow-same-origin绕过同源策略,并且通过allow-script运行js脚本关闭沙箱 + - 通过X-Frame-Options的HTTP响应头字段,可以设置SAMEORIGIN或者DENY,当设置DENY时,当前页面无法被嵌入到其他页面的iframe中,如果设置为SAMEORIGIN,当前页面可以被嵌入到来自同一origin的其他页面中 +- ## 响应式图像 + - 为不同的屏幕宽度选用不同的分辨率图片 + ```html + img... + ``` + - 为不同物理像素/逻辑像素值的设备来选用不同分辨率图片 + ```html + img... + ``` + - 为不同屏幕宽度的设备选用不同的图片 + ```html + + + + img... + + ``` +- ## html表格 + - <table>:表示table标签 + - <th>:表示表格的行、列标题 + - <tr>:表示表格的行 + - <td>:表示表格的单元行 + ```html + + + + + + + + + + + + + +
NameAge
Touma17
Ogiso17
+ ``` + - 可以通过rowspan和colspan属性来控制单元格跨行和列的数目 + ```html + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Waifu +
JapanFrance
ToumaCharles
waifu
KazusaJapan
Austria
+ ``` + - colgroup和col + - <colgroup>:col的容器 + - <col>:col通常用来指定表格中列的样式 + ```html + + + + + + + + + + + + + +
NameAge
Touma17
+ ``` + - caption:添加描述性文本,描述性文本位于表格的正上方 + ```html + + + + + + + + + + +
Waifu Table
NameAge
Touma17
+ ``` + - thead,tbody,tfoot + - thead通常用来标注表头的行,即<th>标签所在的行 + - tfoot通常用来标注表尾信息,比如对上述内容之和的SUM统计 + - tbody通常用来标注表格除thead和tfoot之外的其他信息 + ```html + + + + + + + + + + + + + + + + + + + + + + + + + + +
Cost Summary
Term 1Term 2
35
12
23
+ ``` + - 可以在td中嵌套table表格 + ```html + + + + + + + + + + + + +
Waifu
+ + + + + + + + + +
NameAge
Touma17
+
+ + + + + + + + + +
CityJob
TokyoPianoist
+
+ ``` + - scope属性:在th标签中,具有scope属性,可以指明该th对应的是行标题、列标题、行组标题、列组标题,scope标签对应如下值: + - row + - col + - rowgroup + - colgroup +- Web表单 + - <form>标签 + - form标签一般会有两个属性,action和method + - action:用来指定表单数据提交的目标url + - method:用来指定提交数据用的方法,一般是get或post + ```html +
+ + + +
+ ``` + - label、input和textarea + - <label>元素用来表示标签 + - <input>用来获取用户向表单输入的值 + - <textarea>用来获取用户输入的文本,可输入多行 + ```html +
+ + + +
+ ``` + - 提交表单 + - 提交表单按钮可通过如下两种按钮实现 + - <input type="submit"> + - <button type="submit"> + - 上述两种方法都能提交表单,但是<input>元素中按钮内容只能通过向text属性中传入一个文本,但是<button>元素中可以嵌套更多的内容 + ```html +
+
+ + + + +
+
+ + +
+
+ ``` + - 表单结构 + - <filedset>和<legend> + - <filedset>通常用于将表单中用于同意目的的一系列控件整合在一起 + - <lengend>通常被视为filedset中所有label的一部分 + ```html +
+ + Pen Lip Bold +

+ + +

+

+ + +

+

+ + +

+
+
+ ``` + - 表单元素 + - <input> + - 该元素包含纯文本,不可以调整格式等 + - 该元素具有如下属性: + - readonly:用户无法修改该input元素的内容,但是input内容会随着表单的提交被发送 + - disabled:用户同样无法修改input元素的内容,并且input元素的内容也无法随着表单的提交而提交 + - placeholder:占位符,用来描述该input元素中应该输入的信息 + - size:该input text的物理宽度 + - maxlength:用户可以输入到该input text中的字符数上限 + - input标签的种类 + - text:输入纯文本 + - password:password并不会对input中输入内容加以限制,但是其会隐藏用户输入的内容 + - hidden:type为hidden的元素,在表单中是不可见的,但是内容会在表单提交时一同被提交 + - Checkable组件 + - Checkable组件和其他组件不同,只有当该组件被选中时,才会在表单提交时被发送,如果该组件没有被选中,那么该组件的值并不会被发送,即使该组件的name属性并不为空,如果该组件被选中,而且没有value属性,那么value属性默认为"on";其他组件只要存在name属性,都会被发送 + - checked属性:checked属性可以用来控制该Checkable组件是否默认被选中 + ```html + + + ``` + - 类型: + - checkbox + - radio:一组按钮,具有相同的name属性,一组中只能选中一个按钮,被选中的name/value键值对会被发送给服务端 + - 按钮组件 + - <input>组件可以指定type为如下值之一: + - submit:提交表单 + - reset:重置表单中所有组件值为其默认值 + - button:没有自动提交的效果,但是可以通过js来指定回调 + - 通过为<button>元素的type属性赋值也可以指定button类型为如上三个值之一。在没有为button的type属性指定值或指定无效值时,默认情况下type属性值为submit。 + - image组件: + - 可以为type属性赋值为image,将会显示一个图像,点击图像可以执行提交表单的操作 + - 当点击image按钮执行提交操作时,点击按钮位置相对于按钮左上角的坐标会被添加到提交表单信息中,分别为${nameAttr.x}=xxx和${nameAttr.y}=yyy + - 即使image组件没有name属性,其x和y坐标也会被提交,提交的name就为x和y + ```html + + + - 文件传输组件 + - 可以将type属性指定为file,此时可通过file picker来选择文件上传 + - 相关属性: + - accept:约束选择文件的种类,如image/* + - multiple:如果想要选择多个文件,可以指定multiple属性(可以通过ctrl+left_click来完成多选) + ```html + + ``` + - 组件中的公共属性: + - autofocus:自动获得焦点 + - 在一个document中,可设置表单中的一个组件自动获得焦点,如果一个document中有多个组件设置了autofocus,那么第一个设置autofocus的组件获得焦点 + ```html + + ``` + - form:设置该组件关联的form表单 + - 组件可以被放置在表单外,表单外的组件和表单通过form属性想关联,form属性的值为form的id,当表单被提交时,表单外数据也被包含 + ```html +
+
+ + ``` + - html5新引入的input类型 + - email + - 接受email格式的输入文本,在用户点击表单submit按钮时,会验证是否文本符合email格式,不符合会弹出警告 + - 可以通过指定multiple属性来允许接受多个email地址,多个email地址之间通过逗号分隔 + ```html + + ``` + - search + - 搜索框,用于提供特定样式的搜索框 + - tel + - 接受电话号码,由于全世界不同地区有各种各样的电话号码形式,故而对输入文本的格式没有约束,输入文本中可以包含字母 + - url + - 接受url,当输入文本缺乏协议名(如http、ftp)或者格式不正确时,浏览器会发出警告 + - number: + - 接受一个浮点数格式的文本,可以设置最小值、最大值和文本 + - 在step属性没有指定时,step属性的默认值为1,因而该input只接受整数;要想让该input接受浮点数,可以设置step属性为any,此时可以接受任何浮点数 + ```html + + ``` + - range + - range可以提供一个滑动条来供用户选择数字 + ```html + + ``` + - 日期 + - datetime-local + - 选择时间,无需指定时区信息,采用本地时区,包含年、月、日、时间 + ```html + + ``` + - month + - 选择一个月份,包含年和月信息 + ```html + + ``` + - time + - 选择一个时间 + ```html + + ``` + - week + - 选择一个星期 + ```html + + ``` + - 上述属性还可以包含min,max,step等信息,在不包含时间的日期组件中,可以通过设置step属性来设置步长 + - color: + - color控件提供了用来选取颜色的功能 + - 选取颜色的value值一直是hex形式,6位16进制数 + ```html + + ``` + - 其他表单控件类型 + - <textarea> + - textarea标签可以用于输入多行文本,并且输入文本为纯文本的形式 + - textarea的主要属性: + - cols:用于指定宽度,单位为字符平均宽度,默认为20 + - rows:用于指定高度,默认情况下为2 + - wrap:指定textarea的换行方式 + - soft:在渲染时,文本超过textarea的最大宽度时会换行,但是提交表单时并不会将换行符添加到内容中 + - hard:渲染时,文本超过textarea的最大宽度会黄行,并且提交表单时也会将换行符添加到内容中(在指定wrap为hard时必须显式指定cols的值) + - off:不换行,而是为textarea提供水平滚动条 + - css resize属性: + - 可以通过css中的resize属性来控制textarea的横向和纵向拉伸 + - resize属性可赋予的值: + - both:横向纵向均可 + - horizontial:可横向拉伸 + - veritical:可纵向拉伸 + - none:不可以resize + - 下拉框 + - 下拉框可以通过<select>标签来表示 + - option标签用来表示select标签的内容 + - option标签的selected属性用来设置默认选中的值 + ```html + + ``` + - <optgroup>标签可以为option进行分组,optgroup标签的label属性可以为同一option组的标记设置描述 + - 若option标签具有value属性,那么在表单被提交时,键值对中的value是value属性的值,若option不具有value属性,option标签内包含的内容则会随着表单提交而发送 + - select标签支持multiple属性,可以选中多个option + - select标签支持size属性,可以设置下拉框同时可看见多少个option + ```html + + ``` + - 带自动补全的控件 + - <datalist>标签可以为input元素提供自动补全的数据,当用户在input中输入数据时,可以在datalist中匹配数据并且给用户以补全提示 + ```html + + + + + + + + ``` + - 如果为type=“range”的input标签指定datalist,那么datalist对应的值上都会有一个小刻度 + - 进度条 + - 进度条可以通过<progress>标签来展示 + ```html + + ``` + - <meter> + - meter元素长常用来表示磁盘的占用量等,并且用green、yellow、red等颜色来表明当前状态 + - meter元素的主要属性 + - min:最小值 + - max:最大值 + - low + - high + - optimum:最佳值 + - optimum值位置: + - 位于min和low之间时,(low,hight)为avg,[hight,max]为wrost + - 位于low和high之间时,[min,low]和[high,max]都为avg + - 位于high和max之间时,[min,low]为wrost,(low,high)为avg + - 颜色: + - preferred为绿色 + - wrost为红色 + - avg为黄色 + ```html + 255GB/256GB + ``` + + + + + + + + + + + + + diff --git a/javascript/dom.md b/javascript/dom.md index af8005c..a340120 100644 --- a/javascript/dom.md +++ b/javascript/dom.md @@ -1,61 +1,61 @@ -# dom -- ## js中dom模型的简介 - - js的dom中常用对象: - - window:浏览器用来载入页面的tab,通过js中的window对象,用户可以通过调用window对象中的方法完成如下操作: - - 返回窗口大小 - - 操作导入window中的document - - 存储特定页面的数据 - - 在当前document中添加handler - - navigator:可以通过该对象来检索浏览器的状态和身份信息 - - document:代表载入window的html文档 - - dom树形结构: - - root node:在dom树结构中,根节点总是html节点 - - 子节点:直接位于另一个节点内的节点 - - 后代节点:如果一个节点位于另一个节点内,不管是直接位于还是间接被包含 - - 父节点:如果一个节点直接包含另一个节点 - - 兄弟节点:如果两个节点位于dom树中的同一层,并且具有相同的父节点,那么他们就是兄弟节点 -- ## document api查找节点元素 - - querySelector: - - document.querySelector()会返回第一个匹配的元素 - ```javascript - document.querySelector("p") - ``` - - querySelector: - - 返回所有满足条件的元素,按照NodeList的形式返回 - ```javascript - document.querySelectorAll("p") - ``` -- ## document api创建新元素 - - document.createElement: - ```javascript - let node=document.createElement('p') - let p_node=document.querySelector('p') - p_node.apendChild(node) - ``` - - node.appendChild:通过该方法可以为节点插入新的子元素 - - document.createTextNode:创建新的文本节点(类似与#text的子节点) -- ## document api 移除元素 - - parentNode.removeChild:移除子元素 - ```javascript - let par_node=document.querySelector("div") - let child_node=document.querySelector("div > p") - par_node.removeChild(child_node) - ``` - - childNode.remove:对子元素可以直接调用remove - ```javascript - let child_node=document.querySelector("div > p") - child_node - ``` -- ## js修改css样式 - - 可以通过修改HTMLElement.style中的属性来通过js修改html页面中元素的样式,其会通过inline style(html元素的style属性)来修改页面样式 - ```javascript - let node=document.querySelector("p") - node.style.background="grey" - ``` - - 除了可以通过修改inline style来动态修改元素属性外,还可以预先在css中为各个class指定样式,然后在运行时动态的通过js来修改元素的class属性,此时会为元素应用不同的样式 - ```javascript - let node=document.querySelector("p") - node.setAttribute('class','white-style') - ``` - - +# dom +- ## js中dom模型的简介 + - js的dom中常用对象: + - window:浏览器用来载入页面的tab,通过js中的window对象,用户可以通过调用window对象中的方法完成如下操作: + - 返回窗口大小 + - 操作导入window中的document + - 存储特定页面的数据 + - 在当前document中添加handler + - navigator:可以通过该对象来检索浏览器的状态和身份信息 + - document:代表载入window的html文档 + - dom树形结构: + - root node:在dom树结构中,根节点总是html节点 + - 子节点:直接位于另一个节点内的节点 + - 后代节点:如果一个节点位于另一个节点内,不管是直接位于还是间接被包含 + - 父节点:如果一个节点直接包含另一个节点 + - 兄弟节点:如果两个节点位于dom树中的同一层,并且具有相同的父节点,那么他们就是兄弟节点 +- ## document api查找节点元素 + - querySelector: + - document.querySelector()会返回第一个匹配的元素 + ```javascript + document.querySelector("p") + ``` + - querySelector: + - 返回所有满足条件的元素,按照NodeList的形式返回 + ```javascript + document.querySelectorAll("p") + ``` +- ## document api创建新元素 + - document.createElement: + ```javascript + let node=document.createElement('p') + let p_node=document.querySelector('p') + p_node.apendChild(node) + ``` + - node.appendChild:通过该方法可以为节点插入新的子元素 + - document.createTextNode:创建新的文本节点(类似与#text的子节点) +- ## document api 移除元素 + - parentNode.removeChild:移除子元素 + ```javascript + let par_node=document.querySelector("div") + let child_node=document.querySelector("div > p") + par_node.removeChild(child_node) + ``` + - childNode.remove:对子元素可以直接调用remove + ```javascript + let child_node=document.querySelector("div > p") + child_node + ``` +- ## js修改css样式 + - 可以通过修改HTMLElement.style中的属性来通过js修改html页面中元素的样式,其会通过inline style(html元素的style属性)来修改页面样式 + ```javascript + let node=document.querySelector("p") + node.style.background="grey" + ``` + - 除了可以通过修改inline style来动态修改元素属性外,还可以预先在css中为各个class指定样式,然后在运行时动态的通过js来修改元素的class属性,此时会为元素应用不同的样式 + ```javascript + let node=document.querySelector("p") + node.setAttribute('class','white-style') + ``` + + diff --git a/javascript/export和import.md b/javascript/export和import.md index 72475ab..3540a7c 100644 --- a/javascript/export和import.md +++ b/javascript/export和import.md @@ -1,55 +1,55 @@ -# js中的import和export -* ## export - * js中的导出方式可以分为两类 - * named export: 同一个文件中可以导出多个named export - ```javascript - // 导出预先定义的变量,按列表的形式 - export {myFunction,myVariable} - - // 导出重命名的变量,以列表形式 - export {var1 as name1,var2 as name2...} - ``` - * default export:每一个module只允许有一个default export - ```javascript - export {var as default} - export default function () {} - export default class - ``` - * export from 语法: - ```javascript - export {default as name1,name2} from './other_modules.js' - // 等效于 - import {default as name1,name2} from './other_modules.js' - export {name1,name2} - ``` -* ## import - * import特性: - * import用来导入被其他module导出的read-only绑定值 - * import无法在嵌入的脚本(script标签中)使用,除非其script标签的type属性为module - * import语法 - ```javascript - // 导入default export - import defaultExport from './other_module.js' - - // 导入module中所有输出到命名空间 - import * as other_module from './other_module.js' - // 引用时可以将other_module视为引用导入module中导出元素的命名空间 - other_module.exportFunction() - - // 导入单个元素 - import {myExport} from './other_module.js' - - // 导入时进行重命名 - import {myLongVariableName as shortName} from './other_module.js' - - // 导入default export - import defaultExport from './other_module.js' - ``` -- ## dynamic import - - 动态加载: - - 静态加载会在启动时加载大量不会马上被用到的module,这回花费大量的时间 - - 有些module在启动时可能并不存在 - - 动态加载相比与静态加载,其可以通过import()函数在需要的时候才对module进行加载 - - import函数详情 - - import函数是一个异步函数,其接收一个module路径字符串并且返回一个promise,并且,该方法支持await关键字 - +# js中的import和export +* ## export + * js中的导出方式可以分为两类 + * named export: 同一个文件中可以导出多个named export + ```javascript + // 导出预先定义的变量,按列表的形式 + export {myFunction,myVariable} + + // 导出重命名的变量,以列表形式 + export {var1 as name1,var2 as name2...} + ``` + * default export:每一个module只允许有一个default export + ```javascript + export {var as default} + export default function () {} + export default class + ``` + * export from 语法: + ```javascript + export {default as name1,name2} from './other_modules.js' + // 等效于 + import {default as name1,name2} from './other_modules.js' + export {name1,name2} + ``` +* ## import + * import特性: + * import用来导入被其他module导出的read-only绑定值 + * import无法在嵌入的脚本(script标签中)使用,除非其script标签的type属性为module + * import语法 + ```javascript + // 导入default export + import defaultExport from './other_module.js' + + // 导入module中所有输出到命名空间 + import * as other_module from './other_module.js' + // 引用时可以将other_module视为引用导入module中导出元素的命名空间 + other_module.exportFunction() + + // 导入单个元素 + import {myExport} from './other_module.js' + + // 导入时进行重命名 + import {myLongVariableName as shortName} from './other_module.js' + + // 导入default export + import defaultExport from './other_module.js' + ``` +- ## dynamic import + - 动态加载: + - 静态加载会在启动时加载大量不会马上被用到的module,这回花费大量的时间 + - 有些module在启动时可能并不存在 + - 动态加载相比与静态加载,其可以通过import()函数在需要的时候才对module进行加载 + - import函数详情 + - import函数是一个异步函数,其接收一个module路径字符串并且返回一个promise,并且,该方法支持await关键字 + diff --git a/javascript/js canvas.md b/javascript/js canvas.md index 2eee5a6..e608cc1 100644 --- a/javascript/js canvas.md +++ b/javascript/js canvas.md @@ -1,74 +1,74 @@ -# js canvas -- ## canvas api - - 获取canvas元素: - ```javascript - let canvas=document.querySelector(canvas_name) - ``` - - 获取canvas上下文: - ```javascript - // 获取2d上下文,之后可以通过ctx操作canvas元素 - let ctx=canvas.getContext("2d") - ``` - - 填充矩形: - ```javascript - ctx.fillStyle='rgb(255,0,0)' - ctx.fillRect(0,0,100,100) - ``` - - 如果画了多个图形,那么按照画的顺序,后画的元素将会覆盖在先画的图形之上 - - 通过为ctx.fillStyle指定rgba,可以画半透明的元素,alpha的值为0~1,值越接近0越透明 - - 只画矩形轮廓 - ```javascript - ctx.strokeStyle='rgb(255,0,0)'; - ctx.strokeRect(x,y,width,height); - - // 默认情况下轮廓宽度是1px,但是可以通过ctx.lienWidth来调整宽度 - ctx.lineWidth=5 - ``` - - 画Path:画Path主要可以通过如下api - - ctx.beginPath:在当前所处的位置开始path - - ctx.moveTo:移动当前位置到指定位置,而不记录移动的线条 - - ctx.lineTo:在path中记录线条 - - ctx.fill:通过先前的path创建fill图形 - - ctx.stroke:通过先前的path创建stroke图形 - - 画圆形:通过ctx.arc画圆形 - ```javascript - // arc有6个参数,分别如下 - // 1~2: 圆心的x和y坐标 - // 3:半径的像素 - // 4~5:开始的角度和结束的角度(弧度制) - // 6:是否按逆时针画 - // arc的0度是水平向右 - ctx.arc(100,100,100,0,2*Math.Pi,true) - // 默认情况下0度位于水平向右,但是角度增长默认是顺时针方向,在没有指定第六个参数时其默认也是顺时针方向绘制(第六个参数为false)。但是可以指定第六个参数为true,指定为true会逆时针方向绘制 - // 当path不是封闭图形时,调用fill时会将开始位置和结束位置连接后填充 - ``` - - 在canvas中绘制text文本 - - 可以通过ctx.fillText来绘制填充文本 - - 可以通过ctx.strokeText来绘制文本边框 - - 可以通过ctx.font来修改字体的种类和大小 - ```javascript - // fillText接受3个参数 - // 1.想要绘制的文本 - // 2.绘制文本的开始x位置 - // 3.绘制文本的开始y位置 - // 绘制文本的开始位置是左下角位置,并不是左上角 - ctx.fillText(str,x,y) - ``` - - 在canvas中绘制图片 - - 可以通过ctx.drawImage在canvas中绘制图片,其接受如下参数: - - 一个image对象的引用 - - 想要绘制的图片的裁剪部分左上角的x坐标和y坐标 - - 想要绘制的图片的裁剪部分的width和height - - 想要将裁剪部分绘制在canvas上的位置,相对于(0,0)的x和y坐标 - - 指定想要绘制裁剪部分的width和height,可以与裁剪部分的width和height相同,也可以将裁剪部分resize - ```javascript - ctx.drawImage(image,image_x,image_y,image_width,image_height,0,0,image_x,image_y) - ``` - - 在canvas中创建动画: - - 常用的api: - - ctx.translate: 移动canvas和其origin point,水平方向移动x像素,垂直方向移动y单位 - - ctx.rotate:旋转整个canvas,以origin point为中心 - - 创建动画的api: - - window.requestAnimationFrame(func)来令动画以特定的帧率刷新(60帧/s) - - 通过向requestAnimationFrame来传递一个函数刷新canvas,并且func中继续调用requestAnimationFrame来获取下一帧 - - 当不想继续动画时,可以不再在func中调用requestAnimationFrame,或者可以调用cancelAnimationFrame来停止获取下一帧动画 +# js canvas +- ## canvas api + - 获取canvas元素: + ```javascript + let canvas=document.querySelector(canvas_name) + ``` + - 获取canvas上下文: + ```javascript + // 获取2d上下文,之后可以通过ctx操作canvas元素 + let ctx=canvas.getContext("2d") + ``` + - 填充矩形: + ```javascript + ctx.fillStyle='rgb(255,0,0)' + ctx.fillRect(0,0,100,100) + ``` + - 如果画了多个图形,那么按照画的顺序,后画的元素将会覆盖在先画的图形之上 + - 通过为ctx.fillStyle指定rgba,可以画半透明的元素,alpha的值为0~1,值越接近0越透明 + - 只画矩形轮廓 + ```javascript + ctx.strokeStyle='rgb(255,0,0)'; + ctx.strokeRect(x,y,width,height); + + // 默认情况下轮廓宽度是1px,但是可以通过ctx.lienWidth来调整宽度 + ctx.lineWidth=5 + ``` + - 画Path:画Path主要可以通过如下api + - ctx.beginPath:在当前所处的位置开始path + - ctx.moveTo:移动当前位置到指定位置,而不记录移动的线条 + - ctx.lineTo:在path中记录线条 + - ctx.fill:通过先前的path创建fill图形 + - ctx.stroke:通过先前的path创建stroke图形 + - 画圆形:通过ctx.arc画圆形 + ```javascript + // arc有6个参数,分别如下 + // 1~2: 圆心的x和y坐标 + // 3:半径的像素 + // 4~5:开始的角度和结束的角度(弧度制) + // 6:是否按逆时针画 + // arc的0度是水平向右 + ctx.arc(100,100,100,0,2*Math.Pi,true) + // 默认情况下0度位于水平向右,但是角度增长默认是顺时针方向,在没有指定第六个参数时其默认也是顺时针方向绘制(第六个参数为false)。但是可以指定第六个参数为true,指定为true会逆时针方向绘制 + // 当path不是封闭图形时,调用fill时会将开始位置和结束位置连接后填充 + ``` + - 在canvas中绘制text文本 + - 可以通过ctx.fillText来绘制填充文本 + - 可以通过ctx.strokeText来绘制文本边框 + - 可以通过ctx.font来修改字体的种类和大小 + ```javascript + // fillText接受3个参数 + // 1.想要绘制的文本 + // 2.绘制文本的开始x位置 + // 3.绘制文本的开始y位置 + // 绘制文本的开始位置是左下角位置,并不是左上角 + ctx.fillText(str,x,y) + ``` + - 在canvas中绘制图片 + - 可以通过ctx.drawImage在canvas中绘制图片,其接受如下参数: + - 一个image对象的引用 + - 想要绘制的图片的裁剪部分左上角的x坐标和y坐标 + - 想要绘制的图片的裁剪部分的width和height + - 想要将裁剪部分绘制在canvas上的位置,相对于(0,0)的x和y坐标 + - 指定想要绘制裁剪部分的width和height,可以与裁剪部分的width和height相同,也可以将裁剪部分resize + ```javascript + ctx.drawImage(image,image_x,image_y,image_width,image_height,0,0,image_x,image_y) + ``` + - 在canvas中创建动画: + - 常用的api: + - ctx.translate: 移动canvas和其origin point,水平方向移动x像素,垂直方向移动y单位 + - ctx.rotate:旋转整个canvas,以origin point为中心 + - 创建动画的api: + - window.requestAnimationFrame(func)来令动画以特定的帧率刷新(60帧/s) + - 通过向requestAnimationFrame来传递一个函数刷新canvas,并且func中继续调用requestAnimationFrame来获取下一帧 + - 当不想继续动画时,可以不再在func中调用requestAnimationFrame,或者可以调用cancelAnimationFrame来停止获取下一帧动画 diff --git a/javascript/js storage.md b/javascript/js storage.md index 349b17d..ab65d42 100644 --- a/javascript/js storage.md +++ b/javascript/js storage.md @@ -1,100 +1,100 @@ -# js storage -- ## js在客户端存储数据的方式 - - Web Storage api:通常用来存储简单的数据,以name-value的形式存储 - -- ## Web Storage api - - 存储种类: - - localStorage - - 该种方式即使浏览器被关闭,数据仍然不会丢失,下次重新打开浏览器时数据仍然存在 - - 无论刷新还是关闭页面,数据仍然不会丢失 - - sessionStorage: - - 该种方式只会在浏览器打开时存储数据,一旦浏览器被关闭,存储的数据会消失 - - 该方式存储的数据在刷新页面后仍然会存在,但是当页面关闭后,数据会丢失 - - 存储信息和删除信息方式: - - localStorage: - ```javascript - localStorage.setItem(name,value) - localStorage.getItem(name) - localStorage.removeItem(name) - ``` - - sessionStorage: - ```javascript - sessionStorage.setItem(name,value) - sessionStorage.getItem(name) - session.removeItem(name) - ``` - - 对于不同的域名,Storage是分别储存的,位于同一域名下的页面可以共享Storage中存储的信息,但是位于不同域名的页面Storage信息无法共享 -- ## indexedDB - - 数据库操作(数据库操作都是异步的,不必在数据库操作进行时阻塞,可以为数据库操作请求添加handler来处理完成的请求) - - 打开db: - ```javascript - // 该方法会打开name指定的数据库,如果该数据库不存在, - // 会创建一个新的数据库 - let db_request=window.indexedDB.open(name,version) - ``` - - 为数据库操作添加handler: - ```javascript - // 可以为数据库操作添加success、error的handler - db_request.addEventHandler('success',handler) - db_request.addEventHandler('error',error_handler) - - // 为upgradeneeded事件指定handler - // 如果一个数据库还没有被设置,或者该数据库打开 - // 的版本号大于其本身版本号 - db_request.addEventHnalder((e)=>{ - db=e.target.result - obj_store=db.createObjectStore(name,{keyPath:"id",autoIncrement:true}) - - obj_store.createIndex(name,value,{unique:false}) - }) - ``` - - 如果打开数据库操作完成,会触发success事件,打开的数据库对象可以通过db_request.result来访问 - - 如果打开数据库操作失败,会触发error事件 - - 数据库如果没有被设置,会抛出upgradeneeded事件,并且upgradeneeded事件在success事件之前 - - 向数据库的ObjectStore中添加记录: - - 首先要开启一个事务,通过db.transaction([objectStoreName...],mode:"readwrite") - ```javascript - let tr=db.transaction([obj_store...],"readwrite") - ``` - - 通过事务获取object store对象 - ```javascript - let obj_store=tr.objectStore(obj_store) - ``` - - 调用add操作向object store中添加记录,并且为返回的request对象的事件添加监听器 - ```javascript - let add_request=obj_store.add({ - key1:value1, - key2:value2, - ... - }) - // 为request的success事件添加handler - add_request.addEventHanlder('success',success_handler) - - // 为transaction的complete事件添加handler - tr.addEventHandler('complete',handler) - // 为事务的error事件添加handler - tr.addEventHandler('error',err_handler) - ``` - - 遍历objectStore对象中的记录 - ```javascript - let object_store=db.transaction(object_store_name).objectStore(obj_store_name) - object_store.openCursor().addEventHandler('success',(e)=>{ - // 获取request.result的结果值 - const cursor=e.target.result - if(cursor) { - // 操作数据 - - // 迭代到下一个项目 - // 如果还存在下一个记录,那么request的success - // 事件会再次被触发 - cursor.continue() - } - }) - ``` - - 删除objectStore中的记录 - ```javascript - objectStore.delete(primary_key) - tr.addEventHandler('complete',handler) - ``` - - +# js storage +- ## js在客户端存储数据的方式 + - Web Storage api:通常用来存储简单的数据,以name-value的形式存储 + +- ## Web Storage api + - 存储种类: + - localStorage + - 该种方式即使浏览器被关闭,数据仍然不会丢失,下次重新打开浏览器时数据仍然存在 + - 无论刷新还是关闭页面,数据仍然不会丢失 + - sessionStorage: + - 该种方式只会在浏览器打开时存储数据,一旦浏览器被关闭,存储的数据会消失 + - 该方式存储的数据在刷新页面后仍然会存在,但是当页面关闭后,数据会丢失 + - 存储信息和删除信息方式: + - localStorage: + ```javascript + localStorage.setItem(name,value) + localStorage.getItem(name) + localStorage.removeItem(name) + ``` + - sessionStorage: + ```javascript + sessionStorage.setItem(name,value) + sessionStorage.getItem(name) + session.removeItem(name) + ``` + - 对于不同的域名,Storage是分别储存的,位于同一域名下的页面可以共享Storage中存储的信息,但是位于不同域名的页面Storage信息无法共享 +- ## indexedDB + - 数据库操作(数据库操作都是异步的,不必在数据库操作进行时阻塞,可以为数据库操作请求添加handler来处理完成的请求) + - 打开db: + ```javascript + // 该方法会打开name指定的数据库,如果该数据库不存在, + // 会创建一个新的数据库 + let db_request=window.indexedDB.open(name,version) + ``` + - 为数据库操作添加handler: + ```javascript + // 可以为数据库操作添加success、error的handler + db_request.addEventHandler('success',handler) + db_request.addEventHandler('error',error_handler) + + // 为upgradeneeded事件指定handler + // 如果一个数据库还没有被设置,或者该数据库打开 + // 的版本号大于其本身版本号 + db_request.addEventHnalder((e)=>{ + db=e.target.result + obj_store=db.createObjectStore(name,{keyPath:"id",autoIncrement:true}) + + obj_store.createIndex(name,value,{unique:false}) + }) + ``` + - 如果打开数据库操作完成,会触发success事件,打开的数据库对象可以通过db_request.result来访问 + - 如果打开数据库操作失败,会触发error事件 + - 数据库如果没有被设置,会抛出upgradeneeded事件,并且upgradeneeded事件在success事件之前 + - 向数据库的ObjectStore中添加记录: + - 首先要开启一个事务,通过db.transaction([objectStoreName...],mode:"readwrite") + ```javascript + let tr=db.transaction([obj_store...],"readwrite") + ``` + - 通过事务获取object store对象 + ```javascript + let obj_store=tr.objectStore(obj_store) + ``` + - 调用add操作向object store中添加记录,并且为返回的request对象的事件添加监听器 + ```javascript + let add_request=obj_store.add({ + key1:value1, + key2:value2, + ... + }) + // 为request的success事件添加handler + add_request.addEventHanlder('success',success_handler) + + // 为transaction的complete事件添加handler + tr.addEventHandler('complete',handler) + // 为事务的error事件添加handler + tr.addEventHandler('error',err_handler) + ``` + - 遍历objectStore对象中的记录 + ```javascript + let object_store=db.transaction(object_store_name).objectStore(obj_store_name) + object_store.openCursor().addEventHandler('success',(e)=>{ + // 获取request.result的结果值 + const cursor=e.target.result + if(cursor) { + // 操作数据 + + // 迭代到下一个项目 + // 如果还存在下一个记录,那么request的success + // 事件会再次被触发 + cursor.continue() + } + }) + ``` + - 删除objectStore中的记录 + ```javascript + objectStore.delete(primary_key) + tr.addEventHandler('complete',handler) + ``` + + diff --git a/javascript/js.md b/javascript/js.md index f279cd3..b28ac2a 100644 --- a/javascript/js.md +++ b/javascript/js.md @@ -1,203 +1,203 @@ -# JavaScript基础 -- ## js特性: - - js是一门动态语言,包含类型、运算符、标准内置对象和方法 - - js支持函数是编程 - - js通过原型链来实现面向对象编程 -- ## js类型 - - js中包括如下类型: - - Number:数字 - - String:字符串 - - Boolean:布尔 - - Function:函数 - - Object:对象 - - Symbol:符号 - - 其他类型: - - undefined - - null - - Array - - Date - - RegExp -- ## js变量的声明 - - js可通过如下关键字来声明变量: - - let: - - 块级作用域内有效,只能在声明该变量的块中使用 - - 在let声明变量之后,变量只能在声明之后被使用 - - const: - - 声明一个不可变的变量,该变量在定义域中总是可见的 - - const变量也只能在块定义域中被使用,在声明块之外无法访问 - - var: - - 通过var关键字声明变量之后,变量在整个函数的范围内都是可见的 - - 在定义var变量的方法之外,均无法访问var变量 - - 但是在声明var变量的方法中,即使在声明var变量的语句之前,也可以使用var变量,变量值为undefined - - js变量作用域特性: - - 在js语言中,原本是没有块作用域的,变量只有函数范围的作用域。但是,通过引入const和let关键字,js支持声明块作用域的变量。 -- ## js运算符 - - ==运算符和===运算符 - - ==运算符具有类型自适应的功能 - ```java - # 对于==运算符,如果运算符两边的类型不一致的话, - # 会尝试进行类型转换并比较 - 123==“123” true - 1==true true - ``` - - ===相对于==,比较前并不会进行强制类型转换 - ```java - 1===‘1’ false - 1===true false - ``` - - 相对应的,对于比较不相等的操作,也存在!=和!==操作,其区别类似于==和===的区别 -- ## js流程控制 - - js中for循环可以分为如下两种 - - for in循环: - - 对于for in循环,会遍历索引项(对数组来说是序号,对map来说是key,set为空) - - for of循环: - - 对于for of循环,会遍历值(value)而不是键(key) - - js中的switch流: - - 相比于c中的switch只支持数字,js中的switch既支持数字又支持字符串,switch和case之间是通过===运算符来判断是否严格相等的 -- ## js对象 - - js对象类似与map结构,由key和value组成的键值对构成 - - js对象的创建有如下两种方式 - - 字面量创建 - ```javascript - let obj={ - name:"touma", - id:"A001", - husband:{ - name:"haruki", - id:"A002" - } - } - ``` - - 通过对象原型来创建对象 - ```javascript - function Person(name,id) { - this.name=name - this.id=id - } - - let person=new Person("touma","A001") - ``` - - 访问对象元素的方式 - ```javascript - let person={ - name:"touma", - id:"A001" - } - // 通过.来访问 - cosnole.log(person.name) - // 通过[]来访问 - console.log(person["name"]) - ``` -- ## js数组 - - js中允许通过下标在超过当前数组长度的位置插入元素,其中,中间未插入元素的部分元素值均为undefined - ```javascript - let arr=[1,2]; - arr[100]=101; - // 其中,下标位于2~99之间的元素均为undefined,数组长度为101 - ``` - - js中数组可以通过forEach方法对数组中每个值执行调用 - ```javascript - let arr=[1,2]; - // 将数组中的每个元素平方 - arr.forEach((value,index,arr)=>{ - arr[index]=value*value; - }); - ``` -- ## js中的函数 - - 函数在调用结束之后都会返回一个值,如果函数在结束时没有return语句,或是return语句后没有跟随值,都会返回一个undefined - - 在js函数中,可以通过展开运算符...来接受任意个数的参数,并且,对于数组,...也可以将其展开为被逗号分隔的参数列表 - ```javascript - let arr = [1, 2, 3]; - - function sum(...arr) { - let result = 0; - for (let ele of arr) { - result+=ele; - } - return result; - } - - console.log(sum(...arr)); - ``` -- ## js中的嵌套函数 - - 如果在js中,一个函数依赖与其他函数,但是依赖的其他函数并不会在其他地方被使用,那么可以将依赖的函数放在函数内部 - ```javascript - function outer_func() { - function inner_func() { - // 除了被outer_func调用外不会在其他地方被调用 - } - } - ``` - - 通过嵌套函数,可以有效的减少全局作用域中的函数名称,可以防止污染全局作用域的命名 -- ## js中的闭包 - - 每当js中调用一次函数时,都会创建一个作用域对象,用来保存在函数中创建的局部变量。 - - 当返回值为函数时,返回的函数中将会指向先前被创建的作用域对象,这样作用域对象在函数结束后就不会被回收 - - 由于闭包可以保存状态,并且对外部隐藏状态,故而闭包可以代替对象来使用。闭包通过向外部返回一个操作内部局部变量的函数,保证位于内部的局部变量只能通过返回的函数来访问,保证了变量的安全 -- ## js继承和原型链 - - 和面向对象的编程语言不同,js的继承是通过原型来实现的。每个对象都有一个原型对象,以原型为模板,从原型中继承方法和属性。原型对象也拥有原型,一层一层,以此类推,构成了原型链。 - - 每一个对象都有内置的属性,其中,可以通过内置的__proto__属性来访问一个对象的prototype对象 - - 原型链中属性的查找规则: - - 如果在一个对象中想要查找的属性不存在,那么将会在当前对象的prototype对象中查找属性 - - 如果prototype对象中属性仍然找不到,那么就在prototype对象的prototype对象中查找属性 - - 一直向前回溯,直到属性被找到或者回溯到原型链尾部 - - 原型链结构: - - 对于所有的对象,默认__proto__指向的原型对象都是Object.prototype - - Obejct.prototype是位于原型链尾端的对象,Object.prototype的原型对象是null - - 为对象指定原型对象: - - 通过Object.create函数指定原型对象,该方法会创建一个新对象并为其指明原型对象 - ```javascript - let proto_obj={ - name: "kazusa", - greeting() { - console.log("hello, "+this.name); - } - }; - let child_obj=Object.create(proto_obj); - child_obj.greeting(); - ``` - - 通过构造函数 - - 在js中,所有函数都有一个prototype属性,当该函数被作为构造函数调用时,构造函数创建的所有新对象的__proto__属性都会被设置为该函数的prototype属性 - - 在将构造函数的protype属性设置为制定的对象后,prototype对象中内置属性constructor发生了变化,需要重新将原型对象的constructor制定为构造函数 -- ## 在js中实现类的继承 - - js中,有如下关键字可以简化类的继承,其底层仍然使用原型链来实现类的继承关系 - - class:用于类的声明 - - extends:用于类的继承 - - constructor:用于声明构造函数 - - super():调用父类构造函数来实现子类构造函数 - - js中,可以通过#字符来将变量或者方法标明为类私有的 - - js中继承实现 - ```javascript - class People { - #name - - constructor(name) { - this.#name = name - } - - greeting() { - console.log("hello, i am " + this.#name) - } - } - - - class Student extends People { - #grade - - constructor(name, grade) { - super(name) - this.#grade = grade - } - - greeting() { - console.log("hi, fucking bitch, miss your dad?") - } - } - - let p=new Student("touma",6) - console.log(Object.getPrototypeOf(p)) - ``` - - js通过原型链实现继承的细节: - - js可以首先为父类创建构造函数 - - js在子类的构造函数中,可以先调用ParentConstructor.call(this,args)方法来对子类的对象添加父类的成员变量 - - 在完成子类对象成员变量的赋值后,可以通过Object.create创建一个以ParentConstructor.prototype为__proto__的新对象,并且将ChildConstructor.prototype设置为新对象 +# JavaScript基础 +- ## js特性: + - js是一门动态语言,包含类型、运算符、标准内置对象和方法 + - js支持函数是编程 + - js通过原型链来实现面向对象编程 +- ## js类型 + - js中包括如下类型: + - Number:数字 + - String:字符串 + - Boolean:布尔 + - Function:函数 + - Object:对象 + - Symbol:符号 + - 其他类型: + - undefined + - null + - Array + - Date + - RegExp +- ## js变量的声明 + - js可通过如下关键字来声明变量: + - let: + - 块级作用域内有效,只能在声明该变量的块中使用 + - 在let声明变量之后,变量只能在声明之后被使用 + - const: + - 声明一个不可变的变量,该变量在定义域中总是可见的 + - const变量也只能在块定义域中被使用,在声明块之外无法访问 + - var: + - 通过var关键字声明变量之后,变量在整个函数的范围内都是可见的 + - 在定义var变量的方法之外,均无法访问var变量 + - 但是在声明var变量的方法中,即使在声明var变量的语句之前,也可以使用var变量,变量值为undefined + - js变量作用域特性: + - 在js语言中,原本是没有块作用域的,变量只有函数范围的作用域。但是,通过引入const和let关键字,js支持声明块作用域的变量。 +- ## js运算符 + - ==运算符和===运算符 + - ==运算符具有类型自适应的功能 + ```java + # 对于==运算符,如果运算符两边的类型不一致的话, + # 会尝试进行类型转换并比较 + 123==“123” true + 1==true true + ``` + - ===相对于==,比较前并不会进行强制类型转换 + ```java + 1===‘1’ false + 1===true false + ``` + - 相对应的,对于比较不相等的操作,也存在!=和!==操作,其区别类似于==和===的区别 +- ## js流程控制 + - js中for循环可以分为如下两种 + - for in循环: + - 对于for in循环,会遍历索引项(对数组来说是序号,对map来说是key,set为空) + - for of循环: + - 对于for of循环,会遍历值(value)而不是键(key) + - js中的switch流: + - 相比于c中的switch只支持数字,js中的switch既支持数字又支持字符串,switch和case之间是通过===运算符来判断是否严格相等的 +- ## js对象 + - js对象类似与map结构,由key和value组成的键值对构成 + - js对象的创建有如下两种方式 + - 字面量创建 + ```javascript + let obj={ + name:"touma", + id:"A001", + husband:{ + name:"haruki", + id:"A002" + } + } + ``` + - 通过对象原型来创建对象 + ```javascript + function Person(name,id) { + this.name=name + this.id=id + } + + let person=new Person("touma","A001") + ``` + - 访问对象元素的方式 + ```javascript + let person={ + name:"touma", + id:"A001" + } + // 通过.来访问 + cosnole.log(person.name) + // 通过[]来访问 + console.log(person["name"]) + ``` +- ## js数组 + - js中允许通过下标在超过当前数组长度的位置插入元素,其中,中间未插入元素的部分元素值均为undefined + ```javascript + let arr=[1,2]; + arr[100]=101; + // 其中,下标位于2~99之间的元素均为undefined,数组长度为101 + ``` + - js中数组可以通过forEach方法对数组中每个值执行调用 + ```javascript + let arr=[1,2]; + // 将数组中的每个元素平方 + arr.forEach((value,index,arr)=>{ + arr[index]=value*value; + }); + ``` +- ## js中的函数 + - 函数在调用结束之后都会返回一个值,如果函数在结束时没有return语句,或是return语句后没有跟随值,都会返回一个undefined + - 在js函数中,可以通过展开运算符...来接受任意个数的参数,并且,对于数组,...也可以将其展开为被逗号分隔的参数列表 + ```javascript + let arr = [1, 2, 3]; + + function sum(...arr) { + let result = 0; + for (let ele of arr) { + result+=ele; + } + return result; + } + + console.log(sum(...arr)); + ``` +- ## js中的嵌套函数 + - 如果在js中,一个函数依赖与其他函数,但是依赖的其他函数并不会在其他地方被使用,那么可以将依赖的函数放在函数内部 + ```javascript + function outer_func() { + function inner_func() { + // 除了被outer_func调用外不会在其他地方被调用 + } + } + ``` + - 通过嵌套函数,可以有效的减少全局作用域中的函数名称,可以防止污染全局作用域的命名 +- ## js中的闭包 + - 每当js中调用一次函数时,都会创建一个作用域对象,用来保存在函数中创建的局部变量。 + - 当返回值为函数时,返回的函数中将会指向先前被创建的作用域对象,这样作用域对象在函数结束后就不会被回收 + - 由于闭包可以保存状态,并且对外部隐藏状态,故而闭包可以代替对象来使用。闭包通过向外部返回一个操作内部局部变量的函数,保证位于内部的局部变量只能通过返回的函数来访问,保证了变量的安全 +- ## js继承和原型链 + - 和面向对象的编程语言不同,js的继承是通过原型来实现的。每个对象都有一个原型对象,以原型为模板,从原型中继承方法和属性。原型对象也拥有原型,一层一层,以此类推,构成了原型链。 + - 每一个对象都有内置的属性,其中,可以通过内置的__proto__属性来访问一个对象的prototype对象 + - 原型链中属性的查找规则: + - 如果在一个对象中想要查找的属性不存在,那么将会在当前对象的prototype对象中查找属性 + - 如果prototype对象中属性仍然找不到,那么就在prototype对象的prototype对象中查找属性 + - 一直向前回溯,直到属性被找到或者回溯到原型链尾部 + - 原型链结构: + - 对于所有的对象,默认__proto__指向的原型对象都是Object.prototype + - Obejct.prototype是位于原型链尾端的对象,Object.prototype的原型对象是null + - 为对象指定原型对象: + - 通过Object.create函数指定原型对象,该方法会创建一个新对象并为其指明原型对象 + ```javascript + let proto_obj={ + name: "kazusa", + greeting() { + console.log("hello, "+this.name); + } + }; + let child_obj=Object.create(proto_obj); + child_obj.greeting(); + ``` + - 通过构造函数 + - 在js中,所有函数都有一个prototype属性,当该函数被作为构造函数调用时,构造函数创建的所有新对象的__proto__属性都会被设置为该函数的prototype属性 + - 在将构造函数的protype属性设置为制定的对象后,prototype对象中内置属性constructor发生了变化,需要重新将原型对象的constructor制定为构造函数 +- ## 在js中实现类的继承 + - js中,有如下关键字可以简化类的继承,其底层仍然使用原型链来实现类的继承关系 + - class:用于类的声明 + - extends:用于类的继承 + - constructor:用于声明构造函数 + - super():调用父类构造函数来实现子类构造函数 + - js中,可以通过#字符来将变量或者方法标明为类私有的 + - js中继承实现 + ```javascript + class People { + #name + + constructor(name) { + this.#name = name + } + + greeting() { + console.log("hello, i am " + this.#name) + } + } + + + class Student extends People { + #grade + + constructor(name, grade) { + super(name) + this.#grade = grade + } + + greeting() { + console.log("hi, fucking bitch, miss your dad?") + } + } + + let p=new Student("touma",6) + console.log(Object.getPrototypeOf(p)) + ``` + - js通过原型链实现继承的细节: + - js可以首先为父类创建构造函数 + - js在子类的构造函数中,可以先调用ParentConstructor.call(this,args)方法来对子类的对象添加父类的成员变量 + - 在完成子类对象成员变量的赋值后,可以通过Object.create创建一个以ParentConstructor.prototype为__proto__的新对象,并且将ChildConstructor.prototype设置为新对象 - 最后,将新对象的constructor属性设置为ChildConstructor \ No newline at end of file diff --git a/javascript/js事件.md b/javascript/js事件.md index 3cddcc4..91bdaad 100644 --- a/javascript/js事件.md +++ b/javascript/js事件.md @@ -1,44 +1,44 @@ -# js事件 -- ## js event - - 对于可以触发事件的对象,其会有一个addEventListener方法,通过该方法,可以为对象的特定事件注册handler。addEvnetListener接受两个参数: - - event name - - event handler - - 对于js语言,在不同的环境下,event model可能会有所不同,例如在web浏览器环境下和nodejs环境下,event model就不完全相同 - - 可以通过removeEventHandler来移除handler,该方法同样接收两个参数,event name和handler -- ## 在js中为事件添加复数个handler - - 通过多次调用addEventHandler,可以为同一个事件添加多个handler,在事件发生后,多个handler都会被调用 -- ## Event Handler Properties - - 在js中,如果一个对象能够触发某个事件,通常该对象会有一个onxxx属性,例如onclick、onmouseover等。可以通过为该属性赋值一个函数来为该事件添加handler - ```javascript - let p=document.querySelector("#bt") - p.onclick=()=>{ - alert("button is clicked") - } - ``` - - 但是,通过为对象的onclick属性赋值,无法为该对象的同一个事件添加多个handler,对onclick属性的多次赋值,之后的赋值操作会覆盖前面的赋值操作 -- ## inline event handler(不推荐) - - 可以在html文件中为标签的onxxx属性指定调用的js方法来为事件添加handler,但是这种方法永远不应该被使用 - - 使用inline event handler时,如果多个元素都为相同事件添加相同的handler,那么相同的函数调用代码将会在html文件中重复多次,修改会花费大量时间 - - 并且,使用inline event handler会令js代码和html代码糅合在一起,最好将js代码和html代码分开 -- ## event对象 - - handler的参数中可以含有一个event对象,用来记录触发事件的信息,例如event.target记录了指向触发事件的对象的引用 - - 可以通过event.preventDefault()方法来取消浏览器为该事件定义的默认处理。 - - 可以通过event.stopProgation()方法阻止该事件的传播 - - 通过return false,默认会同时调用event.preventDefault和event.stopProgation -- ## 事件传播的三个阶段 - - capturing阶段: - - 捕获阶段首先会检查触发事件元素的最外层元素(html),检查其是否注册了capture阶段的handler,如果注册了就运行handler - - 然后其会移动到html内部元素并做相同的事情,如果元素有注册capture阶段handler就执行,并依次向内移动,直到遇到触发事件元素的直接父元素 - - target阶段: - - 首先,target阶段会检查EventTarget是否有为event注册的handler,如果有就运行它 - - 如果,event的bubbles为true,其会将event事件传播给EventTarget元素的父元素,并以此向上传播,直到到达html元素;如果bubbles为false,则event不会被向上传播给EventTarget的任何父元素 - - bubbling阶段: - - 检查是否EventTarget的直接父元素为bubbling阶段注册了handler,如果有就运行 - - 对EventTarget父元素的父元素做同样的事,检查是否为bubbling阶段注册有handler,如果有就执行,依次向上传播,直到到达html元素 - - >对于所有的js事件,都会经历capturing阶段和target阶段,但是只有bubbles属性为true的事件才会经历bubbling阶段 - - > 对于target阶段,对于EventTarget,无论是为capturing阶段注册的handler还是为bubbling阶段注册的handler都会被执行 - - > addEventListener默认情况下注册的阶段是bubbling,可以为其制定useCapture为true(默认为false)来指定注册的listener为capturing阶段 - - > 可以在event handler中调用event.stopPropagation来阻止事件在bubbling过程中向上传播 -- ## event.target和event.currentTarget - - event.target:触发事件的元素 +# js事件 +- ## js event + - 对于可以触发事件的对象,其会有一个addEventListener方法,通过该方法,可以为对象的特定事件注册handler。addEvnetListener接受两个参数: + - event name + - event handler + - 对于js语言,在不同的环境下,event model可能会有所不同,例如在web浏览器环境下和nodejs环境下,event model就不完全相同 + - 可以通过removeEventHandler来移除handler,该方法同样接收两个参数,event name和handler +- ## 在js中为事件添加复数个handler + - 通过多次调用addEventHandler,可以为同一个事件添加多个handler,在事件发生后,多个handler都会被调用 +- ## Event Handler Properties + - 在js中,如果一个对象能够触发某个事件,通常该对象会有一个onxxx属性,例如onclick、onmouseover等。可以通过为该属性赋值一个函数来为该事件添加handler + ```javascript + let p=document.querySelector("#bt") + p.onclick=()=>{ + alert("button is clicked") + } + ``` + - 但是,通过为对象的onclick属性赋值,无法为该对象的同一个事件添加多个handler,对onclick属性的多次赋值,之后的赋值操作会覆盖前面的赋值操作 +- ## inline event handler(不推荐) + - 可以在html文件中为标签的onxxx属性指定调用的js方法来为事件添加handler,但是这种方法永远不应该被使用 + - 使用inline event handler时,如果多个元素都为相同事件添加相同的handler,那么相同的函数调用代码将会在html文件中重复多次,修改会花费大量时间 + - 并且,使用inline event handler会令js代码和html代码糅合在一起,最好将js代码和html代码分开 +- ## event对象 + - handler的参数中可以含有一个event对象,用来记录触发事件的信息,例如event.target记录了指向触发事件的对象的引用 + - 可以通过event.preventDefault()方法来取消浏览器为该事件定义的默认处理。 + - 可以通过event.stopProgation()方法阻止该事件的传播 + - 通过return false,默认会同时调用event.preventDefault和event.stopProgation +- ## 事件传播的三个阶段 + - capturing阶段: + - 捕获阶段首先会检查触发事件元素的最外层元素(html),检查其是否注册了capture阶段的handler,如果注册了就运行handler + - 然后其会移动到html内部元素并做相同的事情,如果元素有注册capture阶段handler就执行,并依次向内移动,直到遇到触发事件元素的直接父元素 + - target阶段: + - 首先,target阶段会检查EventTarget是否有为event注册的handler,如果有就运行它 + - 如果,event的bubbles为true,其会将event事件传播给EventTarget元素的父元素,并以此向上传播,直到到达html元素;如果bubbles为false,则event不会被向上传播给EventTarget的任何父元素 + - bubbling阶段: + - 检查是否EventTarget的直接父元素为bubbling阶段注册了handler,如果有就运行 + - 对EventTarget父元素的父元素做同样的事,检查是否为bubbling阶段注册有handler,如果有就执行,依次向上传播,直到到达html元素 + - >对于所有的js事件,都会经历capturing阶段和target阶段,但是只有bubbles属性为true的事件才会经历bubbling阶段 + - > 对于target阶段,对于EventTarget,无论是为capturing阶段注册的handler还是为bubbling阶段注册的handler都会被执行 + - > addEventListener默认情况下注册的阶段是bubbling,可以为其制定useCapture为true(默认为false)来指定注册的listener为capturing阶段 + - > 可以在event handler中调用event.stopPropagation来阻止事件在bubbling过程中向上传播 +- ## event.target和event.currentTarget + - event.target:触发事件的元素 - event.currentTarget:当前handler所附加到的元素(在bubbling阶段时间传播到的上层祖先节点) \ No newline at end of file diff --git a/javascript/js异步.md b/javascript/js异步.md index 90d833c..702d72c 100644 --- a/javascript/js异步.md +++ b/javascript/js异步.md @@ -1,85 +1,85 @@ -# js异步编程 -- ## js异步简介 - - 异步是潜在的长时间运行的方法,在调用异步方法时,并不需要阻塞等到长任务运行完成,而是可以在长任务执行时同时执行其他方法,在异步方法执行完后会显示执行结果 - - 异步方法的使用场景: - - 当在同步方法中执行长任务时,在同步方法执行完成之前,对界面中元素进行的操作都会被阻塞 - - 实现异步操作的方式: - - event handler: - - 通过为事件注册一个函数,可以在异步方法完成后调用 - - 早期异步api会通过event handler来实现异步操作,如XMLHttpRequest - - callback: - - 当需要向callback中传入callback时,代码将会十分的难以阅读 - - promise: - - 在基于promise实现的异步操作中,可以在调用异步方法后立刻返回promise对象,如果异步方法没有执行完成,此时promise中的status为pending,显示异步方法还在执行。可以为promise指定一个callback,当异步操作调用完成,会执行callback -- ## fetch方法的使用 -```javascript -function fetch_baidu() { - let fetch_obj = fetch("https://www.baidu.com") - console.log(fetch_obj) - fetch_obj.then(response => { - console.log('status: '+response.status) - console.log("data: " + response.body) - }) - console.log("fetch finished...") - } -``` -- ## 链式异步调用和错误处理 - - 如果想要为异步方法的handler中添加异步方法,不要在then函数中添加then函数,而是采用promise chain的方式 - ```javascript - // 例如,response.json()方法也是异步方法,返回promise - let http_promise=fetch("https://baidu.com") - http_promise.then(response=>{ - if(!response.ok) { - throw new Error("return code error") - } - let json_promise=response.json() - json_promise.then(json=>{ - console.log(json) - }) - }) - // 不要在then方法中嵌套then方法,而是将其转化为promise chain - let http_promise=fetch("https://baidu.com") - http_promise.then(response=>{ - if(!resposne.ok) { - throw new Error("return code error") - } - return response.json() - }).then(json=>{ - console.log(json) - }) - // 通过该方法可以防止then方法中多层嵌套 - ``` - - 如果想要为promise定义错误处理的handler,可以在末尾catch方法中传递handler - ```javascript - let http_promise=fetch("https://baidu.com") - http_promise.then(response=>{ - if(!resposne.ok) { - throw new Error("return code error") - } - return response.json() - }).then(json=>{ - console.log(json) - }).catch(error=>{ - console.log(error) - }) - ``` -- ## Promise - - Promise的状态 - - pending:该promise已经被创建并且关联了异步方法,但是该方法还没有执行完成 - - fulfilled:该异步方法执行成功,then()被调用 - - rejected:异步方法执行失败,catch()被调用 - > 此处,promise成功和失败是取决与讨论的api的,例如,对于fetch()方法,即使服务端返回404错误,该promise也会被认为是成功的,但是如果是网络问题导致请求发送失败,该方法会被认为是失败的 - - Promise.all和Promise.any - - 如果不想同步的执行异步方法,可以使用Promise.all或者Promise.any来组织promise - - Promise.all接收一个promise数组,只有当数组所有的promise执行成功之后,then()中的方法会被执行,如果其中任何一个promise执行失败,catch()方法被执行 - - Promise.any接收一个promise数组,当数组中任何一个promise执行成功之后,then()方法会被执行,如果所有的promise都失败,catch会被执行 - - ## async和await关键字 - - 在方法开头加上async关键字,可以标识该方法为异步方法,在async方法内部,可以使用awiat关键字。await关键字可以放在一个返回promise方法调用之前,被await标识的方法不再返回promise而是会返回fulfilled value。 - - 通过await/async关键字,可以像编写同步代码一样编写异步代码。 - - async标识的方法会返回promise - - ## Promsie构造函数 - - Promise构造函数接受一个函数(resolve,reject)=>{},该函数被作为Promise对象的执行器,resolve和reject都是只接受一个参数的函数 - - ## Worker - - 默认情况下,整个window是单线程的,如果在同步执行一个长任务的情况下,其他所有的操作都会被阻塞,可以开启多线程来来实现并行执行 - - async/await和promise并不是通过多线程来实现异步操作的,通过async和await并不会创建一个新的线程,故而想要通过多线程提高性能,不能通过简单使用await/promise来实现 +# js异步编程 +- ## js异步简介 + - 异步是潜在的长时间运行的方法,在调用异步方法时,并不需要阻塞等到长任务运行完成,而是可以在长任务执行时同时执行其他方法,在异步方法执行完后会显示执行结果 + - 异步方法的使用场景: + - 当在同步方法中执行长任务时,在同步方法执行完成之前,对界面中元素进行的操作都会被阻塞 + - 实现异步操作的方式: + - event handler: + - 通过为事件注册一个函数,可以在异步方法完成后调用 + - 早期异步api会通过event handler来实现异步操作,如XMLHttpRequest + - callback: + - 当需要向callback中传入callback时,代码将会十分的难以阅读 + - promise: + - 在基于promise实现的异步操作中,可以在调用异步方法后立刻返回promise对象,如果异步方法没有执行完成,此时promise中的status为pending,显示异步方法还在执行。可以为promise指定一个callback,当异步操作调用完成,会执行callback +- ## fetch方法的使用 +```javascript +function fetch_baidu() { + let fetch_obj = fetch("https://www.baidu.com") + console.log(fetch_obj) + fetch_obj.then(response => { + console.log('status: '+response.status) + console.log("data: " + response.body) + }) + console.log("fetch finished...") + } +``` +- ## 链式异步调用和错误处理 + - 如果想要为异步方法的handler中添加异步方法,不要在then函数中添加then函数,而是采用promise chain的方式 + ```javascript + // 例如,response.json()方法也是异步方法,返回promise + let http_promise=fetch("https://baidu.com") + http_promise.then(response=>{ + if(!response.ok) { + throw new Error("return code error") + } + let json_promise=response.json() + json_promise.then(json=>{ + console.log(json) + }) + }) + // 不要在then方法中嵌套then方法,而是将其转化为promise chain + let http_promise=fetch("https://baidu.com") + http_promise.then(response=>{ + if(!resposne.ok) { + throw new Error("return code error") + } + return response.json() + }).then(json=>{ + console.log(json) + }) + // 通过该方法可以防止then方法中多层嵌套 + ``` + - 如果想要为promise定义错误处理的handler,可以在末尾catch方法中传递handler + ```javascript + let http_promise=fetch("https://baidu.com") + http_promise.then(response=>{ + if(!resposne.ok) { + throw new Error("return code error") + } + return response.json() + }).then(json=>{ + console.log(json) + }).catch(error=>{ + console.log(error) + }) + ``` +- ## Promise + - Promise的状态 + - pending:该promise已经被创建并且关联了异步方法,但是该方法还没有执行完成 + - fulfilled:该异步方法执行成功,then()被调用 + - rejected:异步方法执行失败,catch()被调用 + > 此处,promise成功和失败是取决与讨论的api的,例如,对于fetch()方法,即使服务端返回404错误,该promise也会被认为是成功的,但是如果是网络问题导致请求发送失败,该方法会被认为是失败的 + - Promise.all和Promise.any + - 如果不想同步的执行异步方法,可以使用Promise.all或者Promise.any来组织promise + - Promise.all接收一个promise数组,只有当数组所有的promise执行成功之后,then()中的方法会被执行,如果其中任何一个promise执行失败,catch()方法被执行 + - Promise.any接收一个promise数组,当数组中任何一个promise执行成功之后,then()方法会被执行,如果所有的promise都失败,catch会被执行 + - ## async和await关键字 + - 在方法开头加上async关键字,可以标识该方法为异步方法,在async方法内部,可以使用awiat关键字。await关键字可以放在一个返回promise方法调用之前,被await标识的方法不再返回promise而是会返回fulfilled value。 + - 通过await/async关键字,可以像编写同步代码一样编写异步代码。 + - async标识的方法会返回promise + - ## Promsie构造函数 + - Promise构造函数接受一个函数(resolve,reject)=>{},该函数被作为Promise对象的执行器,resolve和reject都是只接受一个参数的函数 + - ## Worker + - 默认情况下,整个window是单线程的,如果在同步执行一个长任务的情况下,其他所有的操作都会被阻塞,可以开启多线程来来实现并行执行 + - async/await和promise并不是通过多线程来实现异步操作的,通过async和await并不会创建一个新的线程,故而想要通过多线程提高性能,不能通过简单使用await/promise来实现 - 为了保证线程安全,worker之间是隔离的,相互之间无法访问其他worker的变量,也无法访问dom(window、document、page),workder之间只能通过message交流 \ No newline at end of file diff --git a/javascript/从服务端获取数据.md b/javascript/从服务端获取数据.md index fb868c7..dcd4c89 100644 --- a/javascript/从服务端获取数据.md +++ b/javascript/从服务端获取数据.md @@ -1,23 +1,23 @@ -# js fetch data from server -- ## js fetch和前后端分离 - - 在传统前后段项目中,通常会用jsp技术来生成动态页面。用户想要与服务端进行请求时,服务端会重新向客户端发送整个页面,即使页面中的大部分数据都和之前的页面相同。用户端会重新对页面进行载入。 - - 通过js的fetch api,客户端可以在向服务端发送请求后,仅仅接受服务端返回的需要更新的数据,而不是整个新页面。用户在接受数据后可以通过dom api根据接受数据对页面进行修改。这样用户不用接受并且重载整个全新的页面。 - - 实现前后端分离的技术通常称之为ajax(asynchronous javascript and xml,之前通常通过xml格式来传输数据,但是现在一般使用json格式来传输数据,但该技术名称仍然叫做ajax) -- ## 具体从服务端接收数据的api - - fetch - - XMLHttpRequest - ```javascript - let request=new XMLHttpRequest(); - try { - request.open('GET',url_path); - request.responseType='json'; - // 为load和error事件添加事件handler - // load事件在response完全完成之后才会被触发 - // error事件在请求发生错误时被触发 - request.addEventHandler('load',load_handler); - request.addEventHandler('error',error_handler); - request.send(); - }catch(err) { - console.log(err); - } +# js fetch data from server +- ## js fetch和前后端分离 + - 在传统前后段项目中,通常会用jsp技术来生成动态页面。用户想要与服务端进行请求时,服务端会重新向客户端发送整个页面,即使页面中的大部分数据都和之前的页面相同。用户端会重新对页面进行载入。 + - 通过js的fetch api,客户端可以在向服务端发送请求后,仅仅接受服务端返回的需要更新的数据,而不是整个新页面。用户在接受数据后可以通过dom api根据接受数据对页面进行修改。这样用户不用接受并且重载整个全新的页面。 + - 实现前后端分离的技术通常称之为ajax(asynchronous javascript and xml,之前通常通过xml格式来传输数据,但是现在一般使用json格式来传输数据,但该技术名称仍然叫做ajax) +- ## 具体从服务端接收数据的api + - fetch + - XMLHttpRequest + ```javascript + let request=new XMLHttpRequest(); + try { + request.open('GET',url_path); + request.responseType='json'; + // 为load和error事件添加事件handler + // load事件在response完全完成之后才会被触发 + // error事件在请求发生错误时被触发 + request.addEventHandler('load',load_handler); + request.addEventHandler('error',error_handler); + request.send(); + }catch(err) { + console.log(err); + } ``` \ No newline at end of file