ES6&&JavaScript語法筆記(191207更新)

ES6 and JavaScript:

##ES6語法的特性
Js中的then函數和nodejs中的回調能夠保證函數的異步和跳過阻塞的部分進行下一步。

  1. 順序次序不一致但對取值沒有影響:

    var{bar,foo}={foo:"aaa",bar:"boo"};
    
  2. 循環的相關的寫法:

    for a in obj //非常方便的進行對象的遍歷
    for a of array//適合於進行一般的遍歷
    arr.forEach(()=>{});//速度接近原始方式進行的速度
    //常用的MAP遍歷結構
    for(let [key.value] of map)
    
  3. es7中async / await,爲解決function, 事件發佈和監聽方式模糊了異步方法之間的流程

    可以完全取代promise, generator的應用,但注意async只能夠在函數內部進行應用

    • 基本上任何一個函數都可以成爲async,使用async則表明這個函數是一個異步函數
    async function foo(){}
    const foo = async funtion(){}
    const foo = async()=>{}//es6的寫法
    
    • 在調用 async定義的函數時,使用await,可以簡單的理解爲函數掛起後等待promis進行返回。

      //async/await相關的代碼
      const printData = async function (filepath) {
         let keyword = await readFile(filepath);
         let count = await queryDB(keyword);
         let data = await getData(res.length);
         console.log(data);
      });
      
  4. generator//es6

    function後面加*號函數則函數可以變爲generator;執行generator將會返回一個遍歷器對象,用於遍歷generator內部的狀態。

    //生成器的定義generator
    const gen function*()
    {
        yield 1;
        return 3;
    }
    //迭代器的定義iterator,迭代器是生成器的實例化
    let g =gen();
    g.next();
    
    //在異步任務處使用yield關鍵詞,此時generator會將程序執行權交給其他代碼,而在異步任務完成後,調用next方法來恢復yield下方代碼的執行。
    

    yeild關鍵字後面需要是function, promise, generator, arrayobject。可以改寫文章一開始的例子:

    const co = reuqire('co');
    
    const task = function* (filepath) {
       let keyword = yield readFile(filepath);
       let count = yield queryDB(keyword);
       let data = yield getData(res.length);
       console.log(data);
    });
    
    co(task, './sample.txt');
    
  5. Promise通過進行鏈接的方式進行改造:

    readFile('./sample.txt').then(content => {
        let keyword = content.substring(0, 5);
        return queryDB(keyword);
    }).then(res => {
        return getData(res.length);
    }).then(data => {
        console.log(data);
    }).catch(err => {
        console.warn(err);
    });
    //通過then連接的鏈式操作,使代碼更加簡潔
    

    Promise的相關方法函數:

  6. reduce的相關用法:

    //例子,previousValue初始值0,currentValue初始的值爲index[currentValue],初始的值爲0,index的初始值也爲0,array一直不發生改變
    //previousValue2次以上爲上一次執行的值
    [0,1,2,3,4].reduce(function(previousValue, currentValue, index, array){
      return previousValue + currentValue;
    }, 10);
    
  7. weakmap是map的弱引用對象,只是相比於map上面少了很多函數方法,set和weakset也是類似的關係。

    • //JS提供5種內置對象之一
      //map的常用方法
      clear()方法, 刪除所有的鍵/值對;
      delete(key), 刪除指定的鍵/值對;
      entries()返回一個迭代器, 迭代器按照對象的插入順序返回[key, value]forEach(callback , context) 循環執行函數並把鍵/值對作爲參數; context爲執行函數的上下文thisget(key) 返回Map對象key相對應的value值;
      has(key) 返回布爾值, 其實就是返回Map對象是否有指定的key;
      keys() 返回一個迭代器,迭代器按照插入的順序返回每一個key元素;
      set(key, value) 給Map對象設置key/value 鍵/值對, 返回這個Map對象(相對於Javascript的Set,Set對象添加元素的方法叫做add,而Map對象添加元素的方法爲set[@@iterator] 和entrieds()方法一樣, 返回一個迭代器, 迭代器按照對象的插入順序返回[key, value]//weakmap的常用方法
      delete(key) : 刪除指定的鍵/值對;
      get(key) :返回Map對象key相對應的value值;
      has(key) :返回布爾值, 其實就是返回Map對象是否有指定的key;
      set(key):給Map對象設置key/value 鍵/值對, 返回這個Map對象;
      
  8. JavaScript的繼承(JavaScript語言特性決定了,類即函數,函數即類),ES6中出現class使得更加像一個類

    • JavaScript的語法中並沒有多繼承的存在

    • 實現多繼承:通過class裏面引用多個function

  9. Reflect的屬性:(都是對於Object,JSON裏面的方法進行修改)

    Reflect.deleteProperty(queRes[i],'count');//刪除指定的json對象屬性:
    
    Reflect.apply(target, thisArg, args)//
    Reflect.construct(target, args)//等同於new target(...args)
    Reflect.get(target, name, receiver)//查找並返回target對象的name屬性
    Reflect.set(target, name, value, receiver)//設置target對象的name屬性
    Reflect.defineProperty(target, name, desc)//等同於Object.defineProperty,用來爲對象定義屬性
    Reflect.has(target, name)//相當於name in target
    Reflect.ownKeys(target)//返回對象的所有屬性,等同Object.getOwnPropertyNames與Object.getOwnPropertySymbols之和
    Reflect.isExtensible(target)//表明當前對象是否可擴展
    Reflect.preventExtensions(target)//阻止該對象進行擴展
    Reflect.getOwnPropertyDescriptor(target, name)
    //等同於Object.getOwnPropertyDescriptor,用於得到指定屬性的描述對象,將來會替代掉後者
    Reflect.getPrototypeOf(target)
    //讀取對象的__proto__屬性,對應Object.getPrototypeOf(obj)
    Reflect.setPrototypeOf(target, prototype)
    //用於設置目標對象的原型(prototype),對應Object.setPrototypeOf(obj, newProto)方法
    
    
  10. JSON是用於TCP,http,websoket的常用數據交互格式,但傳入的是JSON字符串

    常用的JSON對象和字符串轉換方法:

    • JSON字符串轉換爲JSON對象

      let obj = eval('(' + str + ')');//1st
      let obj = str.parseJSON();//2nd
      let obj = JSON.parse(str)//3rd
      
    • JSON對象轉換爲JSON字符串

     let last=obj.toJSONString(); ;//1st
     let JSON.stringify(obj);//2nd
    
  11. 塊級作用域:{}將函數進行分開,函數作用域,js中的函數作用域在函數外也是可見的,變量的提升,node在相同命名的情況下會優先執行函數;

  12. 特殊對象 arguments,無需指出參數名字就可以訪問,類似的則是數組;Function在某些情況下也可以作爲對象,一般使用語句var add = new Function(obj1,obj2)。

  13. 合併兩個數組和數組擴展在原JS中用:arr.splice(start,num,value), 新的方法中 let arr=[origin1, insertvalue,origin];
    14.在nodejs中使用import語法:1.使用命令:node --experimental-modules test.mjs,2.在nodejs中package.json裏面添加:type:json;https://nodejs.org/api/esm.html#esm_ecmascript_modules

JavaScript tips

##JavaScript組成部分:核心(ECMAScript),文檔對象模型DOM,瀏覽器對象模型BOM

字面量/變量/常量和數據類型

  1. 變量 let /常量 const,ES6之前:var/無聲明(全局變量),var和let最大的區別是let的迭代循環不會受閉包影響, js會將函數的變量名提升到普通變量名之前。

  2. 標識符號的命名:必須以字母,,.,下劃線 _ 開頭,後面內容包含數字,數字不能作爲開頭.在JQuery中則代表自身。

  3. 三種基本數據類型( Number,String,Boolean ),兩種引用數據類型(Object,array),兩種特殊數據類型(undefined,null);

  4. 轉換數據類型:JavaScript能識別4種類型的數字字面量:十進制數、二進制數、八進制數和十六進制數

    parseInt("string",進制)//強制轉化爲整形,不填默認爲10進制
    parseFloat("string",進制)//強制轉化爲浮點型不填,默認爲10進制
    Boolean(value)//把給定的值轉換成Boolean型;
    Number(value)//把給定的值轉換成數字(可以是整數或浮點數);
    String(value)//把給定的值轉換成字符串。
    
  5. 特殊字符:

        \n   換行
        \r    回車
        \t    製表符
        \'    單引號
        \"    雙引號
        `     重音符(tab鍵上方的按鍵)
        \$    美元符
        \\     反斜線
        \uXXX    任意的Unicode碼
        \xXX       Latin1字符
    其他常用字符
        \0    NUL字符
        \v    垂直製表符
        \b    退格
        \f     分頁
    
  6. 模板字符串:${ } ,如果緊跟 $ 的值被包裹在大括號中,那麼該值就會被注入到字符串中

    const message = `The curren temperatrue is ${currentTemp} \u00b0C`;
    

對象- js5種內置對象之一

本質上對象是一個容器,對象的容器可以隨着時間推移而改變。

基本語法:let obj={key:value},key必須是字符串或者符號,值可以是任意類型

//for...in是枚舉對象屬性的傳統方式
const SYM =Symbol();
const o={a:1,b:2,c:3,{SYM}:4};
for(let prop in o)
{
    if(!o.hasOwnProperty(prop))continue;
    console.log('${prop}:${o{prop}}');
}

數組處理(Array) - js5種內置對象之一

數組是一種特殊類型的對象。

數組的內容天生具有自然排序特性。鍵是數字,並且是有序的。它具有強大的傳遞信息的能力。

數組特性:

  • 數組長度不固定,可以隨時添加和刪除元素。

  • 數組中元素的類型是多樣的,每個元素都可以是任意類型。

  • 數組從下標0開始。

//獲取子數組
arr.slice(start);
arr,slice(start,end);
arr.slice(-end);
//從任意位置添加或刪除元素
arr.splice(alterPos,count,elem)
//數組內的分割和替換
arr.copyWithin(targetPos,start,end)
//用指定值填充數組
arr.fill(1)//用相應數值填充過來
arr.fill(elem,start,end)
//數組反轉和排序
arr.reverse()
arr.sort()
//map&&filter
arr.map(x=>x.name)//可以把json的map轉換爲數組
arr.filter(condition)
//reduce轉化數組,可以將一個數組歸納爲一個單獨的值
const sum = arr.reduce({a,x}=>a += x,0)//a表示初始值arr[0],x表示第一個元素的值,然後循環運算
//字符串連接
arr.join(elem)

數組內容操作

push;pop//返回新數組的長度
unshift;shift
concat//在數組末尾添加多個元素
slice
splice
copyWithin//剪切並替換數組元素
fill//填充數組
reverse
sort

數組搜索

indexOf(簡單的值),findIndex(複雜的值)//查找元素的下標
lastIndexOf(簡單值)//查找最後一個元素的下標
find//元素本身
some//數組中符合條件的元素
every//數組中所有元素都符合給定條件

數組轉化

map//轉化數組中的所有元素
filter//根據給定條件排除數組元素
reduce//把整個數組轉化成另一種數組類型
join//把元素轉化成字符串合併

日期和時間(Date)- js5種內置對象之一

//moment.js爲日期提供支持方法
const m = moment().add(10,'hours').subtract(3,"days").endof('month');
//日期格式化
moment().format('Y-M-D h:m:s')
fromNow()//從現在算起
m爲未來10個小時以後的時間點倒退3天后所在月份的月底
//創建當前日期
const now = new Date();

//創建指定日期從0開始,9-10月
const halloweenParty = new Date(2016,9,31,19,0);

//創建指定日期和時間,19:00am = 7:00pm
const halloweenParty = new Date(2016,9,31,19,0)

//一些方法檢索Date對象的組件
halloweenParty.getFullYear();
getMonth();getDate();getDay();getHours();getMinutes();getSeconds();getMillseconds();
//上述時間所對應的UTC時間
getUTCFullYear();getUTCMonth();getUTCDate();


正則表達式(RegExp)-js5種內置對象之一

//簡單郵件識別器
const email = /\b[a-z0-9._-]+@[a-z_-]+(?:\.[a-z]+)+\b/;

//US手機號碼識別器
const phone = /(:?\+1)?(:?\d3\s?|\d{3}[\s-]?)\d{3}[\s-]?\d{4}/;

//基本正則表達式
const re1 = /going/ //可以搜索going的表達式
const re2 =new RegExP('going')//使用對象構造器的等價形式
//一些常用的正則方法
startWith(),endWith(),includes(),indexOf()
match(),search(),input.replace().test()//從字符串開始
re.exec//從正則表達式開始

{n}//精確n次,匹配5位數字
{n,}//至少n次,匹配5位或者5位以上的數字
{n,m}//最少n次,最多m次 /\d{2,5}/
 ?//0或者1,等價於{0,1}/[a-z]\d?/i
*//0次或者多次,匹配跟隨了0個或多個數字的字母 /a-z\d*/i 匹配跟隨了0個或者多個數字的字母,表示重複
+//1次或者多次 /a-z\d+/i 匹配至少跟隨一個數字的字母
\s\S能匹配所有的空格和非空格

函數替換

//保留class,id和href的屬性,並刪除其他內容
function sanitizeATag//獲取標籤
    const parts = aTag.match(/<a\s+(.*?)>(.*?)<\/a>/i);
//parts[1]是<a>標籤中的屬性,parts[2]是<a></a>之間的內容
const attributes = parts[1]
    .split(/\s+/);//接下來將其分割成獨立的屬性
return '<a'+attributes
    .filter(attr=>/^(?:class|id|href)[\s+]/i.test(attr)) //過濾掉class.id和href之外的屬性
    .join('')//將它們用空格連接起來
    +'>'//關閉<a>標籤
    +parts[2]//添加內容
    +'</a>'//添加閉合標籤
replace函數的接受順序//整個匹配的字符串(等價$&)>>匹配上的組,有多少組就會有多少參數,原始字符串中的匹配偏移量,原始字符串

描點

//只有兩種描點:^和$,類似於標記物之類的
//一般字符串匹配的是整個字符串的開始和末尾,即使字符串中有換行;
//如果把某個字符串當作多行字符串(以換行符分隔來處理,就需要用到m選項)
const input = "One line\nTwo lines\nTree lines\nFour"
const beginners = input.match(/^\w+/mg);//{"One","Two","Three","Four"}
const endings = input.match(/\w+$/mg)

向前查找

//向前查找(?=<subexpression>)
//否定向前查找(?!<subexpression>)
//重要場景:密碼驗證

動態構造正則

const userRegex= new RegExp('@(?:${user.join('|')})\\b','g');//第一個反斜杆是用來轉義第二個反斜槓
text.match(userRegex)

表達式和運算符

  • 算術表達式的優先級:PEMDAS(括指乘除加減)Parentless括號 Exponents指數 Multiplication乘法 Division除法 Addition加法 subtraction減法
  • typeof能夠打印運算符,instanceof原型鏈測試,判斷是否在其中,與in比較類似

作用域和嚴格模式

異步編程

  1. JavaScript對異步編程的支持有三個不同的階段:回調階段,promise階段和生成器階段

  2. 異步編程的4個主要使用場景:用戶輸入,網絡請求(如Ajax請求),文件系統操作(讀/寫文件等)刻意的時間延遲(比如警告)

  3. setTimeout,setInterval和clearInterval都定義在全局對象中(在瀏覽器中是Window,在node中是global)

  4. 錯誤優先回調

    const fs = require('fs');
    const fname ='may_or_may_not_exist.txt'
    fs.readFile(fname,function(err,data){
        if(err)return console('error reading file ${fname}:${err.message}')
        console.log('${fname}contents:${data'}
    })
    
  5. Promise

    • Promise只會返回兩種事情:被滿足(success)和被拒絕(failure)裏面分別使用resolve(滿足)和reject的回調

    • resolve和reject可以被多次調用,但只有一次會起作用,且並沒有終止函數執行,只是修改promise的狀態

    • 事件:EvenEmitter

    • promise鏈:

      function launch(){
          return new Promise((resolve,reject)=>{
              console.log("on")
              setTimeout(function(){
                  resolve("In orbit");
              },2*1000)
          })
      }
      
      const c = new Countdown(5)
          .on('tick',i=>console.log(i+'...'));
      c.go()
       .then(launch)
          .then(msg=>{
          console.log(msg);
      })
          .catch(err=>{
          console.error("Houston, we have a problem....")
      })
      //開發人員不應該編寫自己的生成器運行器,應該使用co或者koa
      

DOM和JQuery以及Node

  1. 文檔對象的基本模型

    <html>
        <head>
            <title></title>
            <js></js>
            <style></style>
        </head>
        <body>
            <h1></h1>
            <div>
                <h1></h1> text node
                <p></p> text node
            </div>
        </body>
        </body>
    </html>
    
  2. 對話框 alert() prompt() confirm()顯示帶有一段消息以及確認按鈕的對話

    頁面加載事件 onload onunload

    定時器 setTimeout,clearTimeout 指定時間後執行,setInterval 指定時間後反覆執行 clearInternal

  3. Dom操作:

    • 父節點:parentNode;

    • 兄弟節點:nextSibling, nextElementSibling, previousSibling, previousElementSbling;

    • 子節點firstChild, firstElementChild, lastChild, lastElementChild,

    • 所有子節點:ChildNotes 標準屬性, children 非標準屬性

      改變Html的輸出流:document.write(),改變html的內容 document.getElementById("p1").innerHTML = "Hello 實驗樓";
      
      改變HTML的屬性:document90.getElementById(id).attribute = new value;
      
      Dom能夠改變HTML元素的格式
      
      document.getElementById(id).style.property=new style; style爲html相應元素的屬性
      
      
      #創建節點:createElement("p")創建元素節點,createAttriute()創建屬性節點,createTextNode()創建文本節點
      
      #插入子節點:appendChild()方法向節點添加最後一個子節點,insertBefore在指定子節點插入新的子節點,
      
      #刪除節點:removeChild()
      
      #替換子節點:replaceChild()
      
      #設置節點的屬性:getAttribute(名稱)獲取,setAttribute(名稱,值)設置,removeAttribute(名稱)刪除
      
  4. 事件捕獲與事件冒泡:三件事情來影響其他處理器的調用

    • 第一種最常見的,即已經見過的preventDefault,它可以取消地址;事件會繼續傳播,但是defaultPrevented會被置成true
    • 第二種是調用stopPropagation,時間傳播到當前元素之後,將不會繼續傳播(所有綁定到當前元素上的處理器都會被調用,但綁定到其他元素上的處理器不會被調用)
    • 最後一件事,調用stopImmediatePropagation會阻止所有還未調用的處理器被調用(即使這些處理器被綁定在當前的元素上)
  5. 在JQuery的事件監聽器中,直接在處理器中返回false與調用stopPropagation是等價的,這是Jquery的約定,但不能在DOM API中進行使用。

  6. 事件的種類

    • 拖拽事件(Drag events):實現了拖放事件的接口,比如drag start,drag, dragend,drop。

    • 焦點事件(Focus events):用戶與可編輯的元素交互時執行的一些操作。當用戶“進入一個字段”會觸發focus事件,用戶離開時會觸發blur事件,當用戶修改字段時則會觸發change事件。onclick,onblclick

    • 表單事件(Form events):當用戶提交一個表單(由submit或者對應的地方敲擊回車),會觸發表單上的submit事件。onsubmit,onreset

    • 輸入設備事件(Input device events):常見的觸摸事件有鼠標觸摸事件(mousedown,move,mouseup,mouseenter,mouseleave,mouseover,mousewheel)和鍵盤事件(keydown,keypress,keyup)

    • 媒體事件(media events):用於追蹤用戶與html5中的視頻,音頻播放器的交互

    • 進度事件(Progress events):通知瀏覽器加載網頁的速度,最常用的是load

    • 觸摸事件(Touch events):觸摸事件爲可觸摸設備提供了高級支持

    • 一系列實現的例子:

      <!DOCTYPE html>
      <html lang="en">
      
          <head>
              <meta charset="UTF-8">
              <title>Title</title>
              <style>
                  #list li {
                      list-style-type: none;
                      width: 100px;
                      height: 50px;
                      line-height: 50px;
                      background-color: beige;
                      text-align: center;
                      float: left;
                  }
      
                  #list li.current {
                      background-color: red;
                  }
      
                  #list li a {
                      text-decoration: none;
                  }
              </style>
      
          </head>
      
          <body>
              <div id="menu">
                  <ul id="list">
                      <li class="current">
                          <a href="javascript:void(0)">首頁</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">HTML</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">CSS</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">JavaScript</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">關於</a>
                      </li>
                      <li>
                          <a href="javascript:void(0)">幫助</a>
                      </li>
                  </ul>
              </div>
      
              <script>
                  //獲取所有的li標籤,
                  var liObjs = document.getElementById("list").getElementsByTagName("li");
                  //循環遍歷,找到每個li中的a,註冊點擊事件
                  for(var i = 0; i < liObjs.length; i++) {
                      //每個li中的a
                      var aObj = liObjs[i].firstElementChild;
      
                      aObj.onclick = function() {
                          //把這個a所在的li的所有的兄弟元素的類樣式全部移除
                          for(var j = 0; j < liObjs.length; j++) {
                              liObjs[j].removeAttribute("class");
                          }
                          //當前點擊的a的父級元素li(點擊的這個a所在的父級元素li),設置背景顏色
                          this.parentNode.className = "current";
                      };
                  }
              </script>
      
          </body>
      
      </html>
      
  7. JQuery提供的text和html方法分別等於對DOM元素的textContent和innerHTML屬性進行賦值

    //jQuery的基本實例
    //方法1
    $(document).ready(function(){
       // 開始寫 jQuery 代碼...
    });
    
    //方法2
    $(function(){
       // 開始寫 jQuery 代碼...
    });
    
    //一個簡單的例子
    $('p')
        .after('<hr>')
        .append('<sup>*</sup>')
        .filter(':odd')
        .css('margin-left','20px')
    
  8. Ajax:在相應元素定義觸發事件,能夠在文件中定義觸發的函數

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <script>
    function loadXMLDoc()
    {
        var xmlhttp;
        if (window.XMLHttpRequest)
        {
            //  IE7+, Firefox, Chrome, Opera, Safari 瀏覽器執行代碼
            xmlhttp=new XMLHttpRequest();
        }
        else
        {
            // IE6, IE5 瀏覽器執行代碼
            xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange=function()
        {
            if (xmlhttp.readyState==4 && xmlhttp.status==200)
            {
                document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
            }
        }
        xmlhttp.open("GET","/try/ajax/ajax_info.txt",true);
        xmlhttp.send();
    }
    </script>
    </head>
    <body>
    <div id="myDiv"><h2>使用 AJAX 修改該文本內容</h2></div>
    <button type="button" onclick="loadXMLDoc()">修改內容</button>
    </body>
    
  9. Node相關的操作

    • exports有快捷語法和moudle.exports兩種表達方式,實際情況下多用第二個方法

      //方法1,exports導出的這個對象名字仍然叫function
      exports.function=function((err,a)={
          return a;
      })
      //方法2,app.js module.exports對象導出時可用文件名作爲對象app
      //index.get=function((err,a)={
          //return a;
      //})
      class index{
       
      }
      module.exports = index;
      
      
    • 核心模塊,文件模塊,npm模塊,自定義函數模塊

      核心模塊//不需要用顯示聲明,可以進行直接使用
      文件模塊//自己定義的模塊,需要用require(./)進行使用
      npm模塊//通過npm導入,需要用require進行定義
      自定義函數模塊 //const debug = require('debug')('main') 直接將文件所包含的函數
      
    • 文件,進程,操作系統,流

      //文件系統
      fs.writeFile();fs.readFile();fs.writeFileSync();fs.readFileSync();
      //進程 process
      //子進程的模塊對外主要是三個函數:exec,exeecFile和fork 並且有其自身的同步函數
      //流 const ws = fs.createWriteStream('streaming.txt',{encoding:'utf-8'});
      //操作系統os
      
    • web服務

      const http = require('http')
      
      const server = http.createServer((req,res)={
          console.log('${req.method} ${req.url}');
          res.end('hi')
      })
      const port = 8080
      server.listen(port,()={
          console.log('server started on port ${port}')
      })
      

[1].(美)鮑爾斯. JavaScript學習指南(第三版)[M].北京:人民郵電出版社

[2]. 《JavaScript基礎》實驗樓課程 https://www.shiyanlou.com/courses/1238

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章