2016年7月29日 星期五

Hello World (Gradle 2)

在build.gradle打上apply plugin: 'java'然後執行gradle tasks會看到有更多的task出現了,多出來的參考45.3. Tasks

※產生資料夾

apply plugin: 'java'
task xxx << {
    sourceSets*.java.srcDirs*.each{ it.mkdirs() }
    sourceSets*.resources.srcDirs*.each{ it.mkdirs() }
}

※打上 gradle xxx 就執行了,如果不確定,可以先不要mkdirs(),先print it看一下

※srcDirs和resources.srcDirs在Table 45.9. Java plugin - source set properties有寫

※第一行產生src/main(test)/java

※第二行產生src/main(test)/resources,可根據需要再加


※build、clean

打上gradle build會產生build資料夾,clean會刪除

※build的架構如下:

build有兩個子資料夾libs和tmp,libs就一個jar檔,名稱是專案名稱
tmp下還有資料夾叫jar,裡面放的就一個檔案,叫MANIFEST.MF,內容也只有一行
Manifest-Version: 1.0

也可以像maven那樣,用gradle clean build,只用build會顯示11個,用了clean build,第一行會出現clean,如下:

假設下的是build,那麼他會從compileJava一直到build
又假設下的是test,那麼他會從compileJava一直到test
各個功能在做什麼事,要看Table 45.1. Java plugin - tasks,但這張表沒照順序,以我上面的圖,或你自己執行的為準
Example 44.2. Building a Java project還有
clean:刪除build資料夾
assemble:編譯但不測試
check:編譯並測試
所以我知道的總共15個

還有三個在dos沒有看到,javadoc、uploadArchives、cleanTaskName,javadoc會在build底下產生一個子資料夾就docs,其他兩個我試的結果都是找不到task


※測試

1.在src\main\java裡加上一個package,叫ZYX,裡面放一支Class,叫App.java,自己寫一支Hello World

2.下gradle build,會產生build資料夾,裡面有classes和libs等,classes最裡面真的有class檔,而libs裡有jar檔,jar檔裡也看得到class

3.下java -cp build\libs\gradle_test.jar ZYX.App即可看到結果,如下圖:



2016年7月25日 星期一

基本 Build Script (Gradle 1)

gradle官網下載解壓後,設定環境變數,指到bin目錄,然後path加一下
最後到第16章練習,以下是一些心得

在命令提示字元輸入gradle,就會在「當前目錄」和「C:\Users\使用者名稱」增加一個目錄,叫「.gradle」

要練習的檔案都存成build.gradle,程式碼最後有沒有「;」都可以

打上gradle直接按enter會有提示說要gradle 後要加上task才能執行
如果要看全部的task就要下gradle tasks
gradle --help 看說明
gradle help --task task名稱,可以看到Task的包在org.gradle.api,是個介面
-q是只要印log的意思

※基本task

task hello1 {
    doLast {
        println 'Hello world1!'
    }
}
    
task hello2 {
    doLast {
        println 'Hello world2!'
    }
}

※gradle hello1
gradle hello2

※把task想成一個method較好理解

※doLast不寫也ok,是最後執行的意思,還有doFirst,下面還會有範例


※<<

task hello1 << {
    println 'Hello world1!'
}
    
task hello2 << {
    println 'Hello world2!'
}

※也可以用「<<」


※dependsOn

task hello << {
    println 'Hello world!'
}
    
task intro(dependsOn: hello) << {
// task intro(dependsOn: 'hello') << {
// task intro(dependsOn: "hello") << {
    println "I'm Gradle"
}

※intro依賴hello,所以gradle intro時,會先呼叫hello,然後再呼叫自己

※「'」「"」都可以,在這裡沒差別,下面還有範例會說明


※迴圈

task count << {
    10.times { print "$it " }
}

※print沒有ln,所以不會換行

※只要是變數,就一定要用「"」,用「'」不行,會把它當字串

※it是內鍵的變數,10.times表示跑10次,一樣從0開始


※自定迴圈變數

task hello1 {
    10.times {
        xxx -> print "$xxx "
    }
}

10.times { c ->
    task "xxx$c" << {
        println "I'm task number $c"
    }
}

※要使用變數,要用「$」開頭

※gradle -q xxx0會印出I'm task number 0

※xxx0~xxx9也會個別印出自己的

※呼叫xxx是不行的,因為task定的名稱後面有變數


※迴圈的依賴

10.times { c ->
    task "xxx$c" << {
        println "I'm task number $c"
    }
}
xxx2.dependsOn xxx4, xxx6, xxx9

※gradle -q xxx2
I'm task number 4
I'm task number 6
I'm task number 9
I'm task number 2
自己會最後執行

※如果下其他的,如gradle -q xxx6不會有依賴,只會印出自己


※執行順序1

task hello << {
    println '$hello.name 2'
}
    
hello.doFirst {
    println '$hello.name 1'
}
    
hello.doLast {
    println "$hello.name 3"
}
    
hello << {
    println '$hello.name 4'
}

※以doFirst最先,然後自己,最後是doLast

※如果再呼叫,再排最後,如2和4一樣,但2寫的比較前面,會先執行

※要注意變數用「'」和「"」的差別


※執行順序2

task hello {
    doLast {
        println '$hello.name 3'
    }
    
    doFirst {
        println "$hello.name 2"
    }
    
    println "$hello.name 1"
}

※執行順序1,是用hello去「.」,這裡直接寫doLast、doFirst

※此時自己是最先執行的,結果如下:
hello 1
hello 2
$hello.name 3


※ext變數

task ooo {
    ext.p = "ppp"
}
    
task xxx << {
    println ooo.p
}

※呼叫xxx,可以得到ppp


※預設task

defaultTasks 'ooo', 'xxx'
    
task xxx << {
    println 'I\'m xxx'
}
    
task ooo << {
    println 'I\'m ooo'
}
    
task other << {
    println "I'm not a default task!"
}

※gradle -q會自動呼叫ooo和xxx的task,順序是左邊最先,右邊最後,other當然不會執行


※呼叫不同task,取得不同的version

task ooo << {
    println "I\'m $version"
}
    
task xxx(dependsOn: 'ooo') << {
    println 'I\'m xxx'
}
    
gradle.taskGraph.whenReady {taskGraph ->
    if (taskGraph.hasTask(xxx)) {
        version = 'xxx'
    } else {
        version = 'ooo'
    }
}

※結果:
gradle -q ooo
I'm ooo

gradle -q xxx
I'm xxx
I'm xxx

※version是內鍵的,不能改


※內鍵的project

task hello {
    println project.name
    println project.buildDir
}

※project直接點就有一些功能了,還有很多,可按下圖綠色的DSL Reference,然後選右邊的Core types的Project查詢


上面是Properties,下面還有Methods,當然也是可以,以下寫一個瀏覽目錄的程式(修改14.14的範例)
task hello {
    // ConfigurableFileTree file = fileTree('C:\\Users\\bruce_java\\Downloads\\mybatis-3.3.0');
    // fileContent(file.getDir());
    
    File file = file('C:\\Users\\bruce_java\\Downloads\\mybatis-3.3.0');
    println file
    fileContent(file);
}
    
void fileContent(File f) {
    fileContent(f, '')
}
    
void fileContent(File f, String indent) {
    def fs = f.listFiles().sort()
    fs.each { File file ->
        if(file.isDirectory()) {
            println indent + "d-$file.name"
            fileContent(file, indent + "\t")
        } else if(file.isFile()) {
            println indent + "l-$file.name"
        }  
    }
}

※Project的file方法回傳java.io.File;而fileTree回傳ConfigurableFileTree,裡面的getDir方法也是回傳java.io.File,所以註解的部分也是可以,只是看起來比較不像純java

加Eclipse (Maven 3)

Eclipse新版的都已經有內鍵Maven了
Window-->Preferences

除了 User Settings 外,Installations 也要看一下是不是自己下載的版本

Eclipse已經自動抓到了,因為前兩篇已說過一些觀念,所以錯了要會改

再來的操作的方式我之前寫Struts2有寫過,看這篇

然後Run-->Run Configurations...

※右邊綠框取完名字,按下Apply後,會到左邊綠框的位置,以後可直接點取拿來修改或執行

※雖然叫Goals,但phases、options、goals都可以,反正它就是下指令的地方

※Browse Workspaces...和 Browse File System就是選maven 專案用的,擇其一
Add按鈕是增加-D時用的參數
以上一篇第三方jar檔為例

我試的是Browse File System按鈕,將上一篇的maven加進來,要選到pom.xml那一層
Add按鈕的key,「-D」不用打
執行後,真的在local repository新增了

有一些的checkbox,
Offline=mvn -o,不使用網路更新依賴
Update snapshots=mvn -U,強制下載
Debug Output=mvn -X,執行mvn …發生錯誤時,錯誤資訊不夠多,可加上-X
skipTests=mvn -DskipTests,可以忽略測試
Non-recursive=mvn -N,這有可能是有父專案時,不要更新到父專案吧!我沒用過
Resolve Workspace artifacts:如果專案p1依賴p2和p3專案,那只要勾這個,就會將p2和p3下載到p1裡


如果用的是專案,那在專案按右鍵Run as已經有內鍵的clean、test、install了,generate-sources感覺像是validate

※build...(有點點點的)永遠都會跳出Run-->Run Configurations...的畫面,但沒有左邊的部分

※build只有第一次會跳出Run-->Run Configurations...的畫面,而每次都會幫你存個名字,就是
Run-->Run Configurations...圖右邊的綠框,會跳出你要執行哪一個的畫面

※Run Configurations...等同Run-->Run Configurations...


打上第三方的GAV後,會看到jar檔已經進來了

但maven只會幫我們下載一次,如果下載失敗(網路斷線之類的),這招就沒用了,在命令模式可加上「-U」強制重新下載,在Eclipse可在專案按右鍵Maven,然後用如下的設定

※執行的時候就簡單了,Eclipse會提示


※java版本

在專案按右鍵Properties

預設是1.5,當然可以用eclipse改,但如果用maven改的話,要在mvn repository網站找關鍵字「Apache Maven Compiler Plugin」,只要GAV就好,我選目前最新的3.5.1
然後在pom.xml加設定build(和dependencies同層)

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.5.1</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>

※source和target裡面都是1.8版,所以也可以在<properties>裡面設定變數來用,只要改完pom.xml就要按-U的畫面強制更新,此時再看Java Compiler就會改改了

※我有試過把target刪除,發現還是1.8,但那個勾就沒有了

※一般專案可以轉換成maven專案,但架構就不一樣了,就不會是src/main/java之類的了



2016年7月24日 星期日

POM、第三方jar檔 (Maven 2)

POM.xml 設定


這裡選擇左邊的POM Reference,右邊的5個紅框會對應下面的5個紅框

※dependencies

依賴就是說我寫了一支程式,有用到spring-core裡的東西,那就表示我這支程式依賴spring-core,如果我取得不到spring-core,那這支程式當然有問題
mvn dependency:list 可看目前的依賴
mvn dependency:tree 可看依賴的樹狀結構

一般要下載某些jar檔,都是到MVN Repository去搜尋的

scope

scope 預設是 compile
.compile:編譯、測試、執行都有效,一般都用這個
.test:測試有效,上一篇建出來的JUnit就是這一個
.provided:類似 compile,但打包時不包括,如servlet-api
.runtime:測試、執行有效,如JDBC的driver,因為是廠商提供的,不需要編譯
.system:類似 provided,但 jar 檔是系統路徑,所以還要設定<systemPath>自己從系統提供 jar 檔
.import:只能用在 dependencyManagement 裡的 dependency,maven 只能有一個 parent 標籤,也就是只能有一個父 pom,加這個表示此 dependency 自己會去抓,不會抓 parent 的檔案

exclusions

排除依賴
可以設定哪些檔案不要加入,搜尋exclusions,然後複製貼上即可


※properties

1.可以用${env.xxx}取得環境變數,如${env.JAVA_HOME}
想知道其他屬性要切到pom.xml的路徑,然後下mvn help:system,但要小心help:system裡面不能有空格

2.可以用${project.xxx}取得POM裡的屬性,如${project.version}
如果路徑有父子關係,如<build><sourceDirectory>xxx</sourceDirectory></build>
可以用「.」隔開,如${project.build.sourceDirectory}

3.可以用${settings.xxx},取得的是settings.xml裡資料,如${settings.localRepository}

4.在java印出java.lang.System.getProperties().list(System.out)可以取得java系統屬性
如:${java.home}、${file.separator}…等

5.如果以上都沒有適合的,那就自己定變數了,可以亂打
如<xxx.ooo>UTF-8</xxx.ooo>
要用變數的值時,就用${xxx.ooo}就會得到UTF-8了



※第三方jar檔

大部分都可以在上面講的MVN Repository下載到jar檔,但有一些沒辦法,如微軟的SQL Server
這時就要有一些設定才能抓的到
我是自己隨便寫一隻java,然後打包成jar檔,重點就是已經有jar檔了,才能如下的設定


※將第三方jar檔放到local repository

※第一步

這裡左邊選中的是Index(category),其中有個第三方jar到Local Repository

我用Enter看起來好看些,但執行時要用空格分開
mvn install:install-file
-Dfile=D:/xxx.jar
-DgroupId=abc
-DartifactId=def
-Dversion=2
-Dpackaging=jar

執行時,因為我的-Dfile是用絕對路徑,所以在哪個路徑下指令都沒有關係,成功後會在.m2\repository\abc\def\2看到def-2.jar


※第二步

在上一篇的App.java寫一些import這一支的程式碼
然後mvn package會build fail
此時在pom.xml的dependencies下加上如下的設定,local repository有個pom檔,可拿來複製

<dependency>
    <groupId>abc</groupId>
    <artifactId>def</artifactId>
    <version>2</version>
</dependency>

※這些資訊都是剛剛的GAV,因為是自己設的,所以一定會知道

※再次執行mvn package,就會發現build success了

※要執行可以用java -cp ...\xxx.jar;...\ooo.jar ooo.xxx.App


※將第三方jar檔放到pom.xml那層

指令如下方法找

就是上面放到local repository那一頁,有個maven-install-plugin



※其實也就比剛剛多了-DlocalRepositoryPath而已

我將路徑打成以下的樣子
mvn install:install-file
-Dfile=D:/xxx.jar
-DgroupId=abc
-DartifactId=def
-Dversion=2.2
-Dpackaging=jar
-DlocalRepositoryPath=hahaha

※執行好會在pom.xml那一層和local repository出現hahaha(注意要在pom.xml那層執行)

※想執行pom檔也要複製,執行mvn package會發現build fail,因為local repository並沒有產生hahaha,所以還得在pom.xml和dependencies同層增加上如下的設定:

<repositories>
    <repository>
        <id>zzz</id>
        <url>file://${project.basedir}/hahaha</url>
    </repository>
</repositories>

※id隨便打,因為我不打,它有提示

※此時mvn package會發現build success

※執行可用java -cp C:\Users\bruce_java\testMaven\p1.p2\hahaha\abc\def\2.2\def-2.2.jar;
target\p1.p2-1.jar ooo.xxx.App

2016年7月23日 星期六

安裝、設定、觀念 (Maven 1)

Maven官網


按下右邊的超連結


左邊的光標會變成在Index(category),可以選這兩個超連結來學習,以5分鐘的為例


可以看到一定要有java,然後下載maven(我下的是3.3.9),maven會找叫「JAVE_HOME」的環境變數,所以
JAVA_HOME設定成如「C:\Program Files\Java\jdk1.8.0_73」,依自己的版本決定
然後,在PATH後面加上「;%JAVA_HOME%\bin」,這樣子不管到哪個目錄才能執行bin裡的程式
然後maven也是類似上面的設定,假設叫MAVEN,路徑指到bin路徑,如「C:\Users\javaBruce\Downloads\apache-maven-3.3.9\bin」
最後再PATH後面加上「;%MAVEN%」

設定完後,就可以在命令提示字元打mvn --version,其他命令打mvn -h

橘框的超連結有說執行命令後,Windows會在${user.home}/.m2/repository/變成maven的local repository
想改的話,要設定settings.xml,可看官網
裡面有說
設定所有使用者的路徑: ${maven.home}/conf/settings.xml
設定當前使用者的路徑: ${user.home}/.m2/settings.xml(要從上面的路徑複製)
如果兩個都有會合併,而內容一樣的會以使用者的為主

第一個綠框我是自己設定,首先我在C:\Users\javaBruce\Downloads建立一個資料夾叫「Maven_Test」,然後命令提示字切換到Maven_Test,然後下

>cd Downloads\Maven_Test
>mvn archetype:generate

一按下去.m2會建立,會跑一段時間,然後出現如下的畫面


810這個數字表示它想幫你下載數字810的架構,但我的緩衝區太小看不到了,所以可以打第一個紅框搜尋,然會發現只找到1個,一般有兩個較重要的目錄,如下:
maven-archetype-quickstart:JAVA SE用這個
maven-archetype-webapp:JAVA EE用這個

第二個紅框左邊有一個1表示他想幫我們下數字1的架構(前面的1628個已經不算了),可以直接按Enter或打1都可以,然後版本通常都選最新的

然後groupId、artifaceId、version三個加起來是唯一的,先亂打看看待會出現什麼
package是java的套件名,最後會問你要不要執行

完成後如下圖

因為tree這個指令看不到檔案,所以我用紅字標出來
和src同層有一個檔案pom.xml是設定檔,很重要
其他兩個檔案是讓我們測試用的java檔和測試檔

架構還有很多沒有列出來

一樣是剛剛的網頁,圖和我的是一樣的,紅框裡面有列出標準的專案架構
通常開發還會用到resources這個目錄,通常放多國語言properties和xml的設定檔,有需要就自己新增了

現在要執行App.java裡的Hello World!,一些指令不知道沒關係,待會會講解
>cd ccc.ddd
>mvn package-->會build success,也會在pom.xml的同一層產生target目錄,而且裡面有jar檔
然後使用java指令執行jar裡的class
>java -cp target\ccc.ddd-1.0.jar eee.fff.App

執行mvn clean會將target整個目錄清掉

※以上會發現jar的名稱是${artifactId}-${version},副檔名是pom.xml裡packaging設定的

※groupId目前還看不出來

※artifactId雖然我用ccc.ddd,但整個是一個資料夾名稱


觀念:




這裡有說有三個內建的Build Lifecycle(這個專有名詞不要翻譯,越翻越不懂)
default佈署用,如剛剛的mvn package
clean清除用,剛剛一下這個命令,target就不見了
site下載文件用,如果下mvn site,會在target裡新增一個資料就叫site,裡面是文件

往下找到Lifecycle Reference,標題會發現
clean lifecycle有3個
default lifecycle有23個
site lifecycle有4個

這些(30個)官方的名詞叫phases,用在官方的命令,下面還會講goals


文件有說會按順序由上往下執行到你下的指令為止,
所以mvn clean這個指令會執行pre-clean和clean
而mvn package會執行validate、initialize一直到package

但要注要下面還有個Built-in Lifecycle Bindings,它說pom.xml的packaging不一樣也會有所不同,預設是jar,所以以我這個例子如下圖

本來有23個,因為是jar的關係,所以會變成8個,一樣由上往下執行
右邊的xxx:xxx官方的名詞叫goals,一個phase由很多個goals組成的


幾個較重要的phases:
一樣由上往下寫
clean:清除target
compile:編譯成class
test:測試src\test\java裡的程式,所以就算沒有target資料夾也可以測試
package:產生pom.xml裡的packaging指定的副檔名,如jar
install:將產生的檔案,例如jar放到local repository(.m2),是從groupId開始放的,如aaa\bbb\ccc.ddd\1.0,jar檔會放在1.0資料夾裡
deploy:將產生的檔案放在remote repository (目前的設定還不行用,還得有大量的設定)

2016年7月18日 星期一

集合、Iterator (JavaScript 6)

※集合

和java的Map和Set差不多,但方法名不同
Map的key不重覆,後者會蓋前者; Set塞相同的資料,長度不會變長
沒有List,可能已經有Array了吧!

// map
var map = new Map();
map.set("a", "1");
map.set("b", "2");
map.set("c", "3");
console.log(map.size); // 3
console.log(map.get("fox")); // undefined
console.log(map.get("b")); // 2
console.log(map.has("b")); // true
map.delete("b");
console.log(map.has("b")); // false
    
for(let m of map) console.log(m); // ["a", "1"] ["c", "3"]
map.set("a", 10);
map.forEach(function(e, i, a){
    console.log(e); // 10 3
});
    
    
// set
var set = new Set();
set.add(1);
set.add("a");
set.add("b");
    
console.log(set.size); // 3
console.log(set.has(1)); // true
set.delete(1);
console.log(set.has(1)); // false
    
for (let s of set) console.log(s); // a b
console.log(set.size); // 2
set.add("a");
console.log(set.size); // 2
    
set.forEach(function(e, i, a){
    console.log(e); // a b
});

※除了Map 和 Set 外,還有 WeakMap 和 WeakSet
WeakMap 的 key 只能塞物件,Map 無限制
WeakSet 只能放物件,Set 無限制



※ Iterator


※Symbol.iterator

var xxx = {}; // []也可以
xxx[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
console.log([...xxx]); // [1, 2, 3]

※「*」一定要,可以不和function連在一起

※ Symbol.iterator是內鍵的,一個字都不能改,有這個才能用「...變數」

※yield就類似return,但它可以一直接起來

※沒辦法用lambda的寫法


※function*的yield、yield*和next()

function* gen() {
    yield* ["a", "b", "c"];
}
    
const g = gen();
console.log(g.next()); // { value:"a", done:false }
console.log(g.next()); // { value:"b", done:false }
console.log(g.next()); // { value:"c", done:false }
console.log(g.next()); // { value:undefined, done:true }
    
// 一次宣告多個變數和值
var [a, b, c] = new Set(["aa", "bb", "cc"]);
console.log(a); // "aa"
console.log(b); // "bb"

※回傳的done是內鍵的,表示完成了沒

※如果yield不加「*」,那結果是{value: Array[3], done: false},會將整個陣列裝起來,後面如果再呼叫next(),結果都是{value: undefined, done: true}

※最後的宣告改成Array,如var [a, b, c] = new Array(["aa", "bb", "cc"]);,
結果a會變成["aa", "bb", "cc"],後面的b和c都會變成undefined


※function的return

function* gen() { 
    yield 1;
    yield 2;
    yield 3;
}
    
var g = gen();
console.log(g.next());        // { value: 1, done: false }
console.log(g.next());        // { value: 2, done: false }
console.log(g.return("xxx")); // { value: "xxx", done: true }
console.log(g.next());        // { value: undefined, done: true }

※只要一return,後面的value就沒有了,done也變成true了,也就是說一return就算完成了

Nightwatch 基本用法 (Nightwatch 3)

架個server來練習,因為我只會java,要架的可以參考這篇

首頁出來後,將網址複製到要測的js檔裡的browser.url('')裡面
此時一些方法就可以看官網的API練習了


※範例一

module.exports = {
    'Demo test Google' : function (browser) {
        browser
        .url('http://localhost:8080/TestServletXXX/index.jsp')
        .setValue('input[type=text]', 'あ')
        .setValue('input[type=text]', 'ああ')
        .setValue('input[type=text]', 'あああ')
        .pause(1000)
        .setValue('input[type=text]', 'ooo');
        .end();
    
        demoTest(browser);
    }
};
    
function demoTest(browser) {
    browser.assert.containsText("[name='ccc']", "xxx");
};


※範例二

module.exports = {
    function (browser) {
        demoTest(browser);
    }
};
    
demoTest = function (browser) {
    browser
    .url('http://localhost:8080/TestServletXXX/index.jsp')
    .setValue('input[type=text]', 'あ')
    .setValue('input[type=text]', 'ああ')
    .setValue('input[type=text]', 'あああ')
    .pause(1000)
    .setValue('input[type=text]', 'ooo')
    .end();
};

※useCss()和.useXpath()可以切換使用哪一種語法,預設是CSS

※setValue和getValue我不管怎麼設,都只能抓到第一個text
用Xpath「//input[@type='text'][2]」可取得第2筆,不是從0開始,是從1開始
用CSS我沒試出來
一次抓全部也沒試出來

※如果text有預設值,它並不會覆蓋,會附加到預設值的後面,假設預設值是xxx,那結果是xxxああああああooo,所以要清預設值,要用clearValue

※要注意text和value的差別

※Xpath有「/」「//」和沒有「/」三種,但我試的結果只有「//」有用

※input[type=text]用css時,text可以用「'」或「"」包起來,加不加都ok;但用Xpath時,一定要加才抓的到

2016年7月16日 星期六

型態、迴圈 (JavaScript 5)

※七種型態

Boolean
null
undefined
Number
String
Symbol: ECMAScript 6 中新增,實體是唯一且不可變的
Object


※有new 和沒new的差別

var n = new Number(5);
console.log('n=' + n + ',tn=' + typeof n); // object
    
var n2 = 5;
console.log('n2=' + n2 + ',tn2=' + typeof n2); // number
    
var s = new String('a');
console.log('s=' + s + ',ts=' + typeof s); // object
    
var s2 = 'a';
console.log('s2=' + s2 + ',ts2=' + typeof s2); // string
    
var b = new Boolean(true);
console.log('b=' + b + ',tb=' + typeof b); // object
    
var b2 = true;
console.log('b2=' + b2 + ',tb2=' + typeof b2); // boolean
    
var nil = null;
console.log('nil=' + nil + ',tnil=' + typeof nil); // object
    
var u = undefined;
console.log('u=' + u + ',tu=' + typeof u); // undefined
    
var f = new Function();
console.log('f=' + f + ',tf=' + typeof f); // 看下面的圖
    
var f2 = function(){};
console.log('f2=' + f2 + ',tf2=' + typeof f2); // 看下面的圖

※結果:

※除了function外,有new的型態都是object

※字串用「'」和「"」都可以


※型態要注意的事

// var b = new Boolean(false);
var b = false;
console.log('b1=' + b);// false
console.log('b2=' + b ? 'true':'false'); // true
console.log('b3=' + b == true ? 'true':'false');// false
    
    
// null 和 undefined 區別
console.log(null == undefined); // true
console.log(null === undefined); // false
console.log(1 + null); // 1
console.log(1 + undefined); // NaN
    
    
// 數字
var n = .1;
console.log(n); // 0.1
console.log(typeof n); // number
    
    
// 字串+數字和數字+字串
var a = '1';
var b = 2;
console.log(a + b); // 12
console.log(b + a); // 21

※要注要boolean用來判斷時的寫法,如判斷b而已,它會認為有東西就是true

※null 可以加減;undefined 不行

※數字用「.」開頭,會幫你加上0

※使用 typeof 關鍵字可顯示型態

※字串+數字和數字+字串,較舊的瀏覽器有可能變成3,我用IE11和Google51結果都一樣


※六種迴圈

// 一、do...while
var i = 0;
outer:
do {
    console.log(++i);
    if (i == 3){
        break outer;
    } else {
        continue outer;
    }
} while (i < 5);
    
    
// 二、while
var i = 0;
outer:
while (i < 5) {
    console.log(++i);
    if (i == 3){
        break outer;
    } else {
        continue outer;
    }
}
    
    
// 三、for
outer:
for(var i=1; i<5; i++){
    console.log(i);
    if (i == 3){
        break outer;
    } else {
        continue outer;
    }
}
    
    
// 四、for in
var obj = ['a', 2, 'c', 4, 'e'];
outer:
for (var i in obj) {
    console.log(i);      // 0 1 2 3
    console.log(obj[i]); // a 2 c 4
    if (i == 3){
        break outer;
    } else {
        continue outer;
    }
}
    
    
// 五、for of
var obj = ['a', 2, 'c', 4, 'e'];
for (var i of obj) {
    console.log(i); // a 2 c 4 e
}
    
    
// for in 和 for of 區別
var arr = ['a', 2, 'c'];
arr.six = 6;
for (let i in arr) {
    console.log(arr[i]); // a 2 c 6
}
    
for (let i of arr) {
    console.log(i); // a 2 c
}
    
    
// 六、forEach
var obj = ['a', 2, 'c'];
obj.forEach(xxx);
function xxx(element, index, array) {
    console.log('element=' + element); // a 2 c
    console.log('index=' + index); // 0 1 2
    console.log('array=' + array); // 都是a,2,c
}
/* 匿名寫法
obj.forEach(function (element, index, array) {
    console.log('element=' + element); // a 2 c
    console.log('index=' + index); // 0 1 2
    console.log('array=' + array); // 都是a,2,c
});
*/
/* lambda寫法
obj.forEach((element, index, array) => {
    console.log('element=' + element); // a 2 c
    console.log('index=' + index); // 0 1 2
    console.log('array=' + array); // 都是a,2,c
});
*/

※for in和for of的區別是在裡面宣告變數時,用for in是index;而for of是值
還有上面的陣列,後面給的值,for of 不會抓
for of 是 ECMAScript 6新增的

※這六種迴圈,只有forEach沒有標籤的寫法和break、continue,但可以用return true/false代替break、continue

※forEach不能呼叫var xxx = 的function

宣告變數 (JavaScript 4)

宣告變數有3個關鍵字
var:全域變數
const:唯讀的,和java的final不太一樣,java的可以給一次,有值就不能改了;const都不能改
let:區域變數
※不寫以上三個也是全域變數,但有點不太一樣,下面有例子


※var和不寫var一樣的情況

bla = 2;
console.log(bla); // 2
var bla;
console.log(bla); // 2


※var和不寫var不一樣的情況1

var a = 1;
console.log('a=' + a); // 1
delete this.a;
console.log('a=' + a); // 1
    
b = 2;
console.log('b=' + b); // 2
delete this.b;
console.log('b=' + b); // 找不到b

※const和let的結果和寫var一樣,delete沒有作用

※不寫this也是一樣的結果


※var和不寫var不一樣的情況2

var xxx = "global";
var test = function () {
    console.log(xxx); // 這行會因為下行而有變化
    var xxx = "local"; // 有沒有加var有差
    console.log(xxx);
}
console.log(xxx);
    
var test2 = function () {
    console.log(xxx);
}
----------
<button onclick="test()">t1</button>
<button onclick="test2()">t2</button>

※此例test()和test2原本都是global,但test裡也宣告了xxx變數,所以test第一次呼叫時會變成undefined

※沒寫var會變成全域變數,第3行是global,這個和大部分的人想的一樣


※var變成區域變數

var x = 0;
function f(){
    // var z = y = x = 1; // z未定義
    var x = y = z = 1; // x是區域,y是全域
    console.log(x, y, z); // 1 1 1
}
f();
console.log(x, y, z); // 0 1 1

※宣告多個變數為一行時,最左邊的在全域變數找的到才不會出錯


※let和var的差異

var a = 1;
var b = 2;
    
if (a === 1) {
    var a = 11; // 區域變數a,如果全域也有變數a,不管有沒有加var,都會覆蓋
    let b = 22; // 區域變數b,只活在if裡
    
    console.log(a);  // 11
    console.log(b);  // 22
}
console.log(a); // 11
console.log(b); // 2


※const 須注意

const c = {"key": "value"};
console.log(c.key); // value
c.key = 'v';
console.log(c.key); // v
c = {'c':'ccc'}; // 錯誤

※如果宣告成JSON的格式,值還是可以改的;但key不行


※取值須注意

var a = { b: {a: "ooo", "b": "xxx"}, 7: "zzz" };
console.log(a.b.b); // xxx
console.log(a.b['b']); // xxx
console.log(a["b"].b); // xxx
console.log(a["b"]['b']); // xxx
console.log(a[7]); // zzz
// console.log(a.7); // 語法錯誤,數字不要點
    
var t = {
    "": "empty",
    "!": "exclamation"
}
// console.log(t.""); // 不可預期的錯誤
console.log(t[""]); // empty
// console.log(t.!); // 不可預期的錯誤
console.log(t["!"]); // exclamation

※上半部沒什麼問題,下半部要注意key為空和一些特殊符號的情形

2016年7月15日 星期五

debug、版本 (JavaScript 3)

※debug

window.onload = function() {
    try {
        alrt('xxx');
    } catch(e) {
        if(e.description != null){
            alert(e.description);
        } else {
            alert(e.message);
        }
    } finally {
        console.log('一定會執行!');
    }
};

※使用alert、console.log、try…catch…finally三種方法

※try...finally也是可以的,不一定要catch,和java一樣

※console.log要按F12(大部分的瀏覽器都是這樣),再按一次可復原

※上面是IE11,下面是Chrome



※javascript版本

以下的程式碼是測試版本用的
javascript的介面是ECMA script,要對應到它的版本會比較準確,也就是有此新方法要在高版本才有,IE我用11版,還是1.3
但還是有很多試的結果不一樣的地方,如下一篇的const,我就試過有些瀏覽器居然還可以改它的值,也不會出錯
<head>
    <script language="javascript1.1">
        var ver = 1.1;
    </script>
    <script language="javascript1.2">
        var ver = 1.2;
    </script>
    <script language="javascript1.3">
        var ver = 1.3;
    </script>
    <script language="javascript1.4">
        var ver = 1.4;
    </script>
    <script language="javascript1.5">
        var ver = 1.5;
    </script>
    <script language="javascript1.6">
        var ver = 1.6;
    </script>
    <script language="javascript1.7">
        var ver = 1.7;
    </script>
    <script language="javascript1.8">
        var ver = 1.8;
    </script>
    <script language="javascript1.8.1">
        var ver = 1.8.1;
    </script>
    <script language="javascript1.8.2">
        var ver = 1.8.2;
    </script>
    <script language="javascript1.8.5">
        var ver = 1.8.5;
    </script>
</head>
    
<body>
    <script>document.write(ver)</script>
</body>

Nightwatch 設定 (Nightwatch 2)

複製這個網址官網連結的Writing Tests,副檔名一定要叫js
然後自己架一個網站就可以測了,
其中.url('')裡面要放測試的網站,其他的用法和說明就要看官方的API了


※設定檔

※server-standalone檔

每次要執行都要java -jar很麻煩,所以打開
C:\Users\bruce_java\AppData\Roaming\npm\node_modules\nightwatch\bin\nightwatch.json
這個檔一開始會讀它,然後將selenium下的server_path後面打上selenium-server-standalone-xxx.jar的路徑,前面的「./」表示這一層目錄,因為是這一層,所以也可以不打,也可以打絕對路徑

輸入完還不夠,還要將start_process改成true才可以


※換瀏覽器

執行時,預設是firefox,如果想換,可以在selenium下的cli_args有三個瀏覽器driver,下載點在這裡的下面有個cli_args


※下載完,路徑寫法和server-standalone一樣,而且start_process也是要true,最後還要設定test_settings下有一個browserName,目前有9種可以設定,看這裡

※IE我測的結果,跑超慢的,而且好像畫面要100%才能跑的樣子;因為我都用Chrome,所以就沒有深入去研究IE了

2016年7月14日 星期四

台語家族的稱呼


爸爸的哥哥我要叫「阿伯」,阿伯的某叫「阿姆」
我的後生和查某囝叫「伯公」和「姆婆」

爸爸的弟弟我要叫「阿叔」,阿叔的某叫「阿嬸」
我的後生和查某囝叫「叔公」和「嬸婆」

爸爸的姊姊和妹妹我要叫「阿姑」,阿姑的翁婿叫「姑丈」
我的後生和查某囝叫「姑婆」和「丈公」

媽媽的哥哥和弟弟我要叫「阿舅」,阿舅的某叫「阿妗」
我的後生和查某囝叫「舅公」和「妗婆」
舅公叫我的後生和查某囝「外甥」和「外甥女」

媽媽的姊姊和妹妹我要叫「阿姨」,阿姨的翁婿叫「姨丈」
我的後生和查某囝叫「姨婆」和「丈公」

※新婦的婦發「邊龜七」; 弟婦的婦發「喜龜七」

※大小揹和東婿仔發白讀音

2016年7月12日 星期二

Nightwatch 安裝 (Nightwatch 1)

官網連結
寫這篇時,版本是0.9.5

1.-g的意思就是安裝好後,要不要隨便一個地方都可以用nightwatch這個指令,如下面的圖是在
C:\Users\bruce_java這個路徑
如果沒加-g,會將Nightwatch安裝在目前的目錄,畫面和下面的不一樣
如果有加-g,會將Nightwatch安裝在下圖我標紅框的地方
※P.S. 不加-g,我沒有成功run起來
直接再官方首頁下載,內容也和這裡做的一樣,只是下載的有沒有加-g的功能,我沒有試過


2.有3步,下載標3的那一個,因為綠框有寫


3.這一步最好先執行下面的java -jar,意思就是執行程式,然後再去超連結裡


4.這是執行好程式的畫面,最下面沒有大於提示「>」才是正確的,不要關掉,按Ctrl+C或右上角可以關掉


5.我是Windows的,它說將紅框的內容存成一個檔案叫「nightwatch.js」

6.將存好的檔案放在nightwatch資料夾,然在再開啟一個命令提示字元,切到放檔案的下一層,也就是如下圖的綠框再進去nightwatch資料夾
然後執行node ..\nightwatch.js或nightwatch -t ..\nightwatch.js(有時候其中一個不行,也沒報錯,但就是不執行,不知道為什麼),這時就會跳出瀏覽器再測一些有的沒的了
下圖的錯誤是我沒有開啟第4步的圖



2016年7月11日 星期一

Buffer、Modules、Web (Node.js 5)

※Buffer

官網連結


// const buf = require('buffer').Buffer(6, 'utf8');
const buffer = require('buffer');
    
// 以下四種方法,長度都是6
var buf = buffer.Buffer(6, 'utf8');
// var buf = buffer.Buffer('az4_e)', 'utf8');
// var buf = buffer.Buffer(['a',4,'z',99, 'xxx', '%'], 'utf8');
/*
var xf = buffer.Buffer(6, 'utf8');
var buf = buffer.Buffer(xf);
*/
    
console.log('length0='+  buf.length);
    
var len = buf.write("abc");
console.log('length1='+  len);
for(var i=0; i<len; i++){
    console.log(buf[i]);
}
    
len = buf.write("12");
console.log('length2='+  len);
for(var i=0; i<len; i++){
    console.log(buf[i]);
}
    
len = buf.write("一二");
console.log('length3='+  len);
for(var i=0; i<len; i++){
    console.log(buf[i]);
}
    
len = buf.write("\r\n");
console.log('length4='+  len);
for(var i=0; i<len; i++){
    console.log(buf[i]);
}

※第一行的寫法,我改成第二行的寫法,然後直接.Buffer,或者都不要require,直接new Buffer(6)也是可以

※第二個參數,預設就是utf8,所以可以不打

※length3是中文,utf8一個佔3B,所以如果給5個長度,它會變成3
但我將此js檔也用utf8存的,用別的會怪怪的

※write第2、3個參數是起始結束,可是一設定以後,就沒有辦法再改了

※buf[i]是ascii,可以用String.fromCharCode(buf[i])轉,但中文不行

※toString

const buffer = require('buffer');
    
var buf = buffer.Buffer(60, 'utf8');
console.log('length0='+  buf.length);
    
var len = buf.write("abcdefghijk");
console.log('length='+  len);
    
for(var i=0; i<len; i=i+2){
    console.log(buf.toString('utf8', i, i+2) + '\r\n');
}

※直接印出裡面的字(abcde...)



※Modules

官網連結

※exportsTest.js

module.exports = {
    name : 'chess',
    price : 50,
    company : [
        'A',
        'B',
        'C'
    ]
};

※先寫一支檔案


※引用檔案

var exports = require('./exportsTest.js');
for(var e in exports){
    console.log('key=' + e);
    console.log('value=' + exports[e] + '\r\n');
}

※.是當前目錄,就是和node xxx同個目錄,不是dos上的目錄

※.js可以不用加,但如果有一支檔案叫exportsTest會先抓這支檔案,沒有抓到才會抓.js的
官網有說,如果找不到,就會就檔名加上.js->.json->.node,都沒有才是錯,以這個例子.json和.node是不能用的



※原型模組

var count = 0;
var xxx = module.exports = function(){
    this.count = 0;
}
    
xxx.prototype.ooo = function(){
    this.count++;
}

※先寫一支檔案,我將剛剛的拿來改


※引用檔案

var exports = require('./exportsTest.js');
var x = new exports();
x.ooo();
x.ooo();
console.log(x.count);

※結果是2



※Web

官網範例
複製好後,在命令提示字元輸入node xxx會停在那裡,然後到瀏覽器打127.0.0.1:3000就會看到Hello World了

2016年7月9日 星期六

OS、File System、Readline (Node.js 4)

※OS

取得作業系統資訊
官網連結


const os = require('os');
    
console.log('EOL=' + os.EOL);
console.log('arch=' + os.arch());
console.log('endianness=' + os.endianness());
console.log('freemem=' + os.freemem());
console.log('homedir=' + os.homedir());
    
console.log('hostname=' + os.hostname());
console.log('loadavg=' + os.loadavg());
console.log('networkInterfaces=' + os.networkInterfaces());
console.log('platform=' + os.platform());
console.log('release=' + os.release());
    
console.log('tmpdir=' + os.tmpdir());
console.log('totalmem=' + os.totalmem());
console.log('type=' + os.type());
console.log('uptime=' + os.uptime() + '\r\n');
    
// 取得所有屬性
for(var i in os.cpus()){
    console.log(os.cpus()[i]);
}
    
/*
上面的for in和下面的for of一樣,比較少人用,差在console.log裡面可少打一點
這個例子的結果是一樣的,但如果是陣列,for of只會抓初始值
for(var i of os.cpus()){
    console.log(i);
}
*/
    
console.log('\r\n');
// 知道有什麼屬性後,可以取得個別屬性
for(var j=0; j<os.cpus().length; j++){
    console.log(os.cpus()[j].model);
    console.log(os.cpus()[j].speed);
    console.log(os.cpus()[j].times.user);
    console.log(os.cpus()[j].times.sys + '\r\n');
}

※cpus是抓全部的CPU,像我有兩顆



※File System

檔案系統操作,分成同步和非同步,同步不會有最後的Callback參數,可以使用try/catch處理
官網連結


※unlink

非同步的刪除檔案
const fs = require('fs');
    
var path = 'C:\\fsTest.txt';
fs.unlink(path, (err) => {
    if (err) throw err;
    console.log('err=' + err);
    console.log('刪除' + path + '成功');
});
console.log('xxx');

※unlinkSync

同步的刪除檔案
const fs = require('fs');
    
var path = 'C:\\fsTest.txt';
fs.unlinkSync(path);
console.log('刪除' + path + '成功');
console.log('xxx');

※如果有錯誤訊息是權限不夠,就要用有權限的來執行

※注意xxx的執行時機,圖第一個執行的是同步,第二個執行的是非同步

※其他如rename、rmdir、mkdir、readFile、writeFile、appendFile…等,都有分同步/非同步,用法都差不多


※寫檔

const fs = require('fs');
    
// 準備好要寫的資料
var content = '';
content += '1, 2, 3, 4, 5 \r\n';
content += 'a, b, c, d, e \r\n';
    
// 已經有目錄不會報錯,目錄內的檔案也不會增加或減少
var path = '.\\123';
fs.mkdir(path, ()=>{});
    
// 再執行一次會覆蓋原有的內容
fs.writeFile(path + '\\data.txt', content, 'utf8', (err) => {
    if (err) throw err;
    console.log('已存檔!');
});


※增加內容到檔案的最後面

const fs = require('fs');
    
// 準備好要寫的資料
var content = '';
content += '0, 9, 8, 7, 6 \r\n';
content += 'z, y, x, w, v \r\n';
    
var path = '.\\123';
fs.mkdir(path, ()=>{});

// 沒有檔案也會創建新檔案喔!
fs.appendFile(path + '\\data.txt', content, 'utf8', (err) => {
    if (err) throw err;
    console.log('已存檔!');
});


※讀檔


※準備一個檔案,內容如下:
1, 2, 3, 4, 5 
a, b, c, d, e 
0, 9, 8, 7, 6 
z, y, x, w, v 


const fs = require('fs');
fs.readFile('D:\\123\\data.txt', 'utf8', (err, data) => {
    if (err) throw err;
    console.log(data);
});

※很簡單就將內容全部都讀出來了,但如果只想一次讀一行要看下面的Readline



※Readline

官網連結


const readline = require('readline');
const fs = require('fs');
    
const rl = readline.createInterface({
    input: fs.createReadStream('D:\\123\\data.txt')
});
    
rl.on('line', (xxx) => {
    console.log(xxx);
    var split = xxx.trim().split(',');
    for(l in split){
        console.log(l.trim());
        // split.forEach(ooo);
    }
});
    
function ooo(value, index, ar){
    console.log(value.trim());// 值
    console.log(index);// 就是index
    console.log(ar); // 整個陣列
}

※on裡面的字,一定要叫line

※Callback已經是迴圈了,直接將抓到的值做處理


ajax低階介面、快速方法 (jQuery24)

官網連結

※ajax()

@WebServlet(urlPatterns = { "/xxx" })
public class XxxServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html; charset=UTF-8");
        PrintWriter out = resp.getWriter();
        // try {
        //     Thread.sleep(2000);
        // } catch (InterruptedException e) {
        //     e.printStackTrace();
        // }
        out.print("username=" + req.getParameter("username") + "<br />");
        out.print("password=" + req.getParameter("password"));
    }
}
----------
var ajaxTest = function(){
    $.ajax({
        url : "xxx",
        type : "POST",
        // data : {
        //        username:'u', 
        //        password:$('input[name="password"]').val()
        //        },
        // async : false,
        data : $.param({ 
                    username: $('input[name="username"]').val(), 
                    password: 'p' 
                }),
        success : function(data, textStatus, jqXHR){
            alert(data); // username=user<br />password=p
            alert(textStatus); // success
            for(xhr in jqXHR){
                alert('xhr=' + xhr); // readyState、getResponseHeader、getAllResponseHeaders、setRequestHeader、overrideMimeType、statusCode、abort、state、always、then、promise、pipe、done、fail、progress、complete、success、error、responseText、status、statusText
                // alert('jqXHR[xhr]=' + jqXHR[xhr]);
            }
        }
    });
    alert('think');
}
----------
<form action="xxx" method="post">
    使用者:<input type="text" name="username" value="user" /><br />
    密碼:<input type="password" name="password" value="pass" /><br />
    <input type="submit" />
</form>
<input onclick="ajaxTest()" type="button" value="test" />

※最下面的form不是ajax,是一般的寫法,整批一起丟到controller

※按鈕test是ajax寫法,async預設是true,是非同步,至少要有url和type才可以運作(雖然預設是GET,但我不寫就是不行),但總是要看結果回傳什麼,所以我加了success;而data是傳過去的json資料,「:」左邊等同name名稱,controller是抓這個名稱的
data我用了兩種方法

※如果將async設為false,就是同步

※注意think印出的時機,如果沒將controller的sleep打開,我試的結果它都是最後執行
但打開時,也就是停2秒,這兩秒的意思是模擬後端有很多工作
這時async為true時think會先執行,所以才叫非同步;false就變成最後執行,所以才叫同步

※另外還有可能會用到的還有error和statusCode,其他就很少用到了,要用時再研究



※ajaxPrefilter()、ajaxSetup()

var ajaxTest = function(){
    $.ajaxSetup({
        config1: 123,
        config2: "c2",
        config3: false,
        config4: 4.5,
        config5: {'c1': 1, 'c2': false},
        url: "zzz"
    });
    
    $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
        alert(options.url);//xxx
        options.url = "http://localhost:8080/TestServletXXX/xxx/ooo/zzz";
        alert(options.url);
    
        alert('options=' + options);
        alert('config1=' + options.config1); // 123
        alert('config5=' + options.config5.c2); //false
    
        for(o in options){
            alert('o=' + o); // url、type、isLocal、global、processData、async、contentType、accepts、contents、responseFields、converters、flatOptions、jsonp、jsonpCallback、xhr、data、success、dataTypes、crossDomain
        }
    
        for(oo in originalOptions){
            alert('oo=' + oo); // url、type、data、success
        }
    });
    
    $.ajax({
        url : "xxx",
        type : "POST",//async : false,
        data : $.param({ 
                    username: $('input[name="username"]').val(), 
                    password: 'p' 
                }),
        success : function(data, textStatus, jqXHR){
            // ...
        }
    });
    alert('think');
}

※使用ajaxPrefilter表示要在$.ajax前過濾,所以將$.ajax註解後,ajaxPrefilter也不會執行

※ajaxPrefilter的第一個參數是個選項,可以是xml html text json jsonp script,預設是「*」,像上面的範例,是沒有第一個參數的,這個參數表示還要特定的類型才會過濾,也就是說$.ajax有一個dataType的屬性,兩個對應才會過濾,隨便打也行,兩個有對應就ok

※ajaxSetup是設定options用的,在ajaxPrefilter的第二個參數的第一個option去點就有了,可以用自訂的、也可以用options本來就有的
理論上ajaxSetup是設options的預設值,我設sync有成功,但url居然失敗了,不知道為什麼,而致於其他的我也沒試

※像上面的ajaxPrefilter,我在呼叫前過濾一下,將xxx轉成另外一支叫xxx/ooo/zzz的servlet了



※ajaxTransport

$.ajaxTransport('abc', function(options, originalOptions, jqXHR) {
    for(o in options) {
        alert('o=' + o); // url、type、isLocal、global、processData、async、contentType、accepts、contents、responseFields、converters、flatOptions、jsonp、jsonpCallback、xhr、dataType、data、success、dataTypes、crossDomain、hasContent
    }
    
    for(oo in originalOptions) {
        alert('oo=' + oo); // url、type、dataType、data、success
    }
    
    for(xhr in jqXHR) {
        alert('xhr=' + jqXHR.xhr);// readyState、getResponseHeader、getAllResponseHeaders、setRequestHeader、overrideMimeType、statusCode、abort、state、always、then、promise、pipe、done、fail、progress、complete、success、error、[Object object]、completeCallback=function done(...
    }
    
    return {
        send: function(headers, completeCallback) {
            alert('headers=' + headers);
            alert('completeCallback=' + completeCallback);
        },
    
        abort: function() {
            alert('abort function');
        }
    };
});


※ajaxTransport的第一個參數是必填,否則不會執行,所以$.ajax的dataType也要一樣才會執行

※這個功能是用在ajaxPrefilter也無法滿足需求時,實際的用法我也不清楚



※快速方法

官網連結

※post、get、getJSON

$.post(
    'xxx', 
    $.param({ 
        username: $('input[name="username"]').val(), 
        password: 'p' 
    }),
    function(data, textStatus, jqXHR){
        alert(data);
        alert(textStatus);
        alert(jqXHR);
    },
    'html'
);

※總共4個參數,第一個參數一定要,其他都是選項,最後一個參數是dataType,就是從server返回的格式是哪一種,如xml、json、script、text、htm,不給的話會自己猜測

※和另外一個$.get完全一樣,只差在要對應後端的doGet

※$.getJSON,差在沒有最後的dataType參數,因為就是json


※load

$('input[name="username"]').load(
    'xxx', 
    $.param({ 
        username: $('input[name="username"]').val(), 
        password: 'p' 
    }),
    function(responseText, textStatus, XMLHttpRequest){
        alert(responseText);
        alert(textStatus);
        alert(XMLHttpRequest.status);
        alert(XMLHttpRequest.statusText);
    }
);

※事件也有一個方法叫load,兩個是不一樣的

※總共3個參數,第一個參數一定要,其他都是選項


※getScript

$.getScript(
    'xxx.js', 
    function(script, textStatus, jqXHR){
        alert(script);
        alert(textStatus);
        alert(jqXHR);
    }
);

※前面的一定要連到server,這個不用

※第一個參數抓javascript,像我是將xxx.js和寫getScript這一支放在同一個目錄,所以這樣子就抓到了

※總共2個參數,第一個參數一定要

Process、Utilities、Events (Node.js 3)

※Process

可以取得此程序的資訊
官網連結

※argv

for(var i in process.argv) {
    console.log(process.argv[i]);
}
console.info('\r\n');
process.argv.forEach((val, index, array) => {
    console.log(`${index}: ${val}`);
    // console.log(`${array}`);
});

※官網用的是lambda寫法,我用的是一般寫法,都可以,變數用左上角的ESC鍵下面的那個1,用2個包起來,然後用「${}」可以取得,而用「'」和「"」是不行的

※變數array太長了,裡面就是陣列,用「,」隔開


※cwd、chdir

console.log(`Starting directory: ${process.cwd()}`);
try {
    process.chdir('D:\\');
    // process.chdir('/tmp');
    console.log(`New directory: ${process.cwd()}`);
}
catch (err) {
    console.log(`chdir: ${err}`);
}

※cwd是目前路徑,chdir是改變路徑,我用的是Windows,所以tmp註解打開會抓不到,就會跑catch的程式碼



※arch、env、memoryUsage、platform

console.log('This processor architecture is ' + process.arch);
// console.log(process.env);
console.log(process.env.USERDOMAIN);
console.log(process.memoryUsage());
console.log(`${process.platform}`);

※arch是位元
※process.env裡面有很多,其中有一個USERDOMAIN是其中一個,所以我才可以拿來用
※memoryUsage看記憶體的使用heapTotal和heapUsed是V8用的情況




※Utilities

就是一些公用的方法
官網連結

※isXxx、log

isXxx都是判斷用的,也就是回傳值是true/false,用法都差不多,官網的範例也夠清楚了,就寫一個意思意思一下

const util = require('util');
console.log(util.isArray([]));
console.log(util.isArray(new Array));
console.log(util.isArray({}));
util.log('xxx');

※util.log可以印出現在時間,裡面的xxx可打可不打,只是黏在後面的字串而已


※debuglog

debuglog是偵測環境變數用的,有才會執行程式碼,否則什麼都不會發生

var debuglog = require('util').debuglog('xxx');
var root = 123;
debuglog('hello from foo [%d]', root);

※執行之前要設環境變數,只要xxx有對應到,就會執行


※inherits

左邊繼承右邊,繼承後會多一個叫「super_」的東西,代表右邊的爸爸

function Dad(){}
Dad.prototype.write = function() {
    console.log('prototype');
}
    
const util = require('util');
var son = function(){}
util.inherits(son, Dad);
    
new Dad().write();
new son().write();

※繼承後可以使用爸爸的write方法了

※官網的範例,不懂Events的人看不太懂,所以我寫了這個,然後下面的Events看一下就很容易懂了

※另外javascript宣告變數有三種:var、const、let
var:全域變數,不寫var也是
const:只讀的變數,和java有一點不一樣,java一開始給null,但一給值後就不能改了,這裡的const更嚴格,就算是一開始給null或undefined都不能改
let:區域裡的區域變數

※我用IE11試的結果,const和let都不支援,和ECMA script的版本有關,我記得應該是要在第四版才有支援,但我測IE11的javascript版本是1.3,對應到ECMA script,是1或2版,所以沒有支援

假設最外層有一個全域變數a,if裡面宣告a=1或var a=1,都會改到全域變數,宣告成let就不會改到了

宣告let必需要在最上最寫一行「"use strict";」或者執行時加「--use_strict」,
如node --use_strict xxx.js



※Events

事件
官網連結


const events = require('events');
    
var event = events.EventEmitter;
var e = new event();
    
/*
    e.on('xxx', function() {
        count++;
        console.log('trigger' + count);
    });
*/
    
e.on('xxx', () => {
    count++;
    console.log('trigger' + count);
});
    
e.emit('xxx');
e.emit('xxx');

※註解的部分是一般的寫法,現在官方都是用lambda的寫法了

※emit要和on裡的字一樣,就可以觸發事件

※其他事件都差不多,請參考官網

2016年7月4日 星期一

REPL操作、全域變數 (Node.js 2)

安裝完成後,打開命令提示字元,輸入node或者打開安裝路徑的node.exe(預設在C:\Program Files\nodejs),就會出現「>」的提示,裡面可以打javascript語法,如:


※紅框:打完function想離開按一次Ctrl+C會提示再按一次或打「.exit」可以離開或用更猛的Ctrl+D直接跳出
.help可以看到其他的命令,或者看官網的API

※綠框:雖然hello()剛剛可以執行,但因為已經執行 .exit 了,所以記錄都不見了,所以會出錯



離開再進來還想抓到之前的程式碼,可以用.save和.load,如下:
我一load xxx就會幫我將內容打出來,所以就可以很輕鬆的呼叫了
我有看到在「下載」的資料夾裡,出現一個檔案叫xxx,內容就是這個了
在「下載」的資料夾裡,可能是預設下載路徑的關係吧!
所以命令提示字元關掉再打開,當然還是抓的到

※.clear是.break的別名,所以兩個功能一樣
功能就是在打程式的時候,一開始左邊是「>」的符號,但打到「{」按Enter後,會自動出現「...」的提示,之後每打完一行按Enter都會出現,直到打上「}」才表示輸入完畢,符號也會變回「>」
但有時打錯字,但已經按Enter了,沒有辦法回上面改,所以可以下這個指令,讓符號直接變回「>」,而剛剛打的就無效了,所以才會取名叫.break和.clear



將function存成一個檔案

我將檔名取名為helloNodeJS.txt(其實和.save一樣,差別只是誰存而已)
※一般副檔名是js,但我故意用txt,表示它是抓裡面的文字來編譯,甚至沒有副檔名也可以

※最下面的用法是直接用,但因沒辦法呼叫,這個例子不適用,我將內容改成以下的樣子,執行後就可以看到了
const xxx = 1;
if(xxx = 1) {
    console.log('我是1');
} else {
    console.log('我不是1');
}

※做個判斷式,執行結果如下:



全域變數

官網連結

首先用node進入後打上console.log(global);尤於太長了,只列出後面的部分
可以看到有很多「xxx:」,和官網的API一樣,如綠框,所以直接用global點它,可以看到裡面的內容,也可以自己定義,如上圖的xxx,定義完再次執行console.log(global);也能看到自定義的變數,但自定義的重新進入就不見了

※檔名和檔案路徑

__dirname和__filename是一抓檔案時,可以取得檔名和路徑用的,但直接寫是會錯誤的
我新增一個檔案叫test.txt,內容如下:
console.log(__filename);
console.info(__dirname);

※想直接用.load也是不行的,因為.load只是機器幫你打,結果當然一樣


Console.log的變數

console也是其中一個全域變數,因為太常用了,所以有必要了解一下
將helloNodeJS.txt修改成如下:
console.log('string: %s', 'bruce');
console.log('decimal: %d', 100);
console.log('json: %j', {'a':1, 'b':[1,2,3]});
console.log('percent: %');
console.log('percent: %%');
console.log('xxx\r\nooo');

※輸出的結果為:

官方的API就這四種,其中打1或2個%都是1個「%」,打3或4個%都是2個「%」,依此類推

※\r\n可以換行


※Console

console的info是log的別名,標準輸出
console的warn是error的別名,標準錯誤輸出
在命令提示字元看起來一模一樣,顏色也一樣
但是如果是輸出到檔案就會有所不同,如下:
※「>」表示輸出到哪裡;「>>」表示附加到哪裡
如上圖表示輸出到同一層(javaBruce),且新增一個檔案叫111.txt(可以沒有這個檔案),然後將xxx寫進去
還有最後一個指令表示,附加到111.txt的最後面,沒有檔案會新增
所以後面兩個指令,「xxx」才看不到,但ooo永遠都在控制台


※Console.time 和 Console.timeEnd

可以知道一段程式碼執行了多少時間

console.time('xxx');
for (var i = 0; i < 10; i++) {
    console.info('index=' + i);
}
console.timeEnd('xxx');

※不下Console.timeEnd不會印出多少時間