国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
我思故我在 javascript

Thinking in Technique

2006-09-5
tangrui.cn: ok
我已經(jīng)把名字改成 lcore Le
不過還沒 commit
Weiming: 我說,怎么沒有up到

tangrui.cn: en

lazy load 的暫且先放一放
說那個(gè)資源和代碼先后的問題
Weiming: 好,這個(gè)我覺得需要去調(diào)查以下
Sent at 10:30 PM on Monday
Weiming: ?
tangrui.cn: 啊,我在等你說呀
Weiming: 你不是說了,lazyload的,放一下,我說好,先去調(diào)查
tangrui.cn: 就是我上午說,代碼文件要是訪問資源文件的話,那么資源文件必須在代碼文件之前引用
這就要求,比如 longjs.lang.lstring 必須先定義這個(gè)類型
Weiming: 上午說的,你說要把定義,單獨(dú)放在__package__蝦米,這個(gè)我不同意
如果
longjs.res = {};
然后所有的res,都掛在這個(gè)蝦米呢?
下面
longjs.res.lstring = {};
long.res.lstring[’en’];
這樣就有了
tangrui.cn: 什么意思
Weiming: 就是,現(xiàn)在的res都是單獨(dú)的
比如lstring的,
那么就是
longjs.lstring[’en’]這樣的
tangrui.cn: res 不能單開命名空間呀
要不然我怎么能知道他放在哪里了
Weiming: 我的意思,res,不是一個(gè)單獨(dú)的命名空間
longjs.lstring[’en’]這樣的
tangrui.cn: 再說把他們放到 longjs.res 下面也不成呀,res 豈不成一個(gè)命名空間了
Weiming: res,是一個(gè)變量
或者說,應(yīng)該是
longjs.__res
這樣
他只是一個(gè)resource的掛節(jié)點(diǎn)
從一個(gè)邏輯的角度,
tangrui.cn: 那么你的資源就沒有層次結(jié)構(gòu)了呀
Weiming: longjs.__res,起始就是統(tǒng)一的管理resource了
還是有的,
只不過,你的原來的沒有一個(gè)統(tǒng)一的根,現(xiàn)在有了
tangrui.cn: 再說這個(gè)東西沒有放到前面的,還是那句話,你的資源是要跟類型走的
Weiming: 什么東西沒有放到前面的?
tangrui.cn: 現(xiàn)在是因?yàn)榭赡苡卸嗾Z言把他們分開,但其是資源和類型是應(yīng)該在一起的
Weiming: 資源,起始,做成
longjs.lstring[’en’];
tangrui.cn: 即便像你說的那樣,也應(yīng)該是 longjs.lang.lstring.__res
Weiming: ok,停以下
tangrui.cn: ok
Weiming: lstring的res,是否是lstring的一部分?
先不考慮default的
tangrui.cn: 不是
Weiming: 那么,也就是沒有res,我可以用lstring
tangrui.cn: 但是需要至少配備 default 的
Weiming: 先不考慮default
tangrui.cn: 是的
Weiming: 如果default的實(shí)現(xiàn)和其他完全一樣
那么也沒必要考慮
因?yàn)槎际且粯拥?/div>
ok,這個(gè)地方,咱們沒有分歧,就是lstring是可以,并且應(yīng)該單獨(dú)使用的
tangrui.cn: 對(duì)
Weiming: 如果,我現(xiàn)在有了res
那么他也應(yīng)該在lstring加載后,以一種補(bǔ)充的方式
把自己”掛”上去
ok?
tangrui.cn: 是的
Weiming: 那么加載的順序就定了(先不管怎么實(shí)現(xiàn))
就是先lstring,再是他的res,(如果default和其他的一樣,那么同樣處理)
tangrui.cn: 是的
然后
Weiming: 在現(xiàn)階段
咱們已經(jīng)實(shí)現(xiàn)了lstring對(duì)longjs的掛接
可以使用這個(gè)說法么?
tangrui.cn: 什么叫 lstring 對(duì) longjs 的掛接
Weiming: 如果從一個(gè)擴(kuò)展的角度看,(也許不合適)
就是lstring,是對(duì)longjs的一個(gè)擴(kuò)展
tangrui.cn: 這個(gè)不能這么說吧
Weiming: 為什么不能?
tangrui.cn: lstring 畢竟是 longjs native 的 class
不說那么拗口的名詞,繼續(xù)往下
Weiming: ok
反正,就是
現(xiàn)有了longjs,然后又了lstring
tangrui.cn: 對(duì)
Weiming: 并且,lstring,要么有,要么沒有
不能說,我有一部分
tangrui.cn: 是的
Weiming: 那么,早晨你說的吧lstring的定義
也就是longjs.lstring = xxx
放在__package__里面,我覺得是不合適的
tangrui.cn: 但是,沒有辦法
Weiming: 其實(shí),現(xiàn)在可以說,只有在static method的地方,才會(huì)出現(xiàn)
我使用res,但是沒有
對(duì)吧
tangrui.cn: 對(duì)
Weiming: 我想想
先說結(jié)果
就是,這樣
longjs.__res.lstring
那么再說我是如何理解
我現(xiàn)在也不知道這樣是否合適
就是
現(xiàn)有l(wèi)ongjs,后有l(wèi)string
longjs。lstring,從某種意義上
認(rèn)為是lstring掛在longjs上面
那么,這個(gè)時(shí)候,能否認(rèn)為
lstring的res,也是在和lstring加載的時(shí)候,也是掛在longjs.__res上面的
對(duì)于longjs,這些class,他的跟是longjs
對(duì)于他們的res,根是longjs.__res
也就是longjs管理所有的class等
longjs
longjs.__res管理所有的res
可否這么認(rèn)為
tangrui.cn: 那就不對(duì)了
Weiming: ok
tangrui.cn: 你要是這么理解的話,那怎么組織都說得通了
我就算把資源放到 abc.def.hjk.__res.lssssss
Weiming: 我這樣說,只是從一個(gè)樹,變成了兩個(gè)樹
tangrui.cn: 下面我也能說,是在 longjs.lang.lstring 加載的時(shí)候掛上去的
但是既然咱么做了一個(gè)有層次結(jié)構(gòu)的框架,那就資源也和類型必須在他的可控范圍之內(nèi)
Weiming: ok
tangrui.cn: 資源與類型不是平行的關(guān)系,而是資源從屬與類型
Weiming: 對(duì)
tangrui.cn: 所以從組織上也需要是具有從屬的層次
ft 又遇到一個(gè)問題
這個(gè)我覺得咱么明天再說吧,一晚上估計(jì)不一定能討論出來
Weiming: 是,這是一個(gè)圈,媽的
tangrui.cn: 現(xiàn)在恐怕 lcore.using 要加上一個(gè)參數(shù)表示所在的 window 了
lcore.using(target, win);
Weiming: 不好吧
為什么這么玩?
tangrui.cn: 因?yàn)樵瓉?lcore.using 沒有前面的 lcore 所以
Weiming: 所以,都是本window?
我靠
tangrui.cn: 所以在 using 里面那到 this 就是那個(gè) window
現(xiàn)在,lcore.using 的 this 都是 lcore
Weiming: 那,using就沒用了
tangrui.cn: 如果你強(qiáng)行使用 window 那么這個(gè) window 就是 jsFrame 而不是調(diào)用方法的那個(gè) window
除非把 using 前面的 lcore 去掉
否則就要加上這個(gè)惡心的參數(shù)
Weiming: 我寧可叫做longjs_using
也不愿意加上window
tangrui.cn: 要不咱么這些 core 的方法都這么叫
longjs_undef
longjs._createPackage();
Weiming: ._
還倆?
tangrui.cn: 多打了一個(gè)
我已經(jīng)提交了
Weiming: 豪
longjs里面,多少是和jsframe相關(guān)的?
tangrui.cn: 什么意思
Weiming: 就是,longjs,提供一系列的方法
他有多少是和window,frame相關(guān)的
比如using就和window相關(guān)
tangrui.cn: 類庫(kù)部分沒有
Weiming: longjs.js
這里面
tangrui.cn: 有的話也是靠類似 lcore.using 這樣的方法來獲得的
Weiming: using,應(yīng)該是都是針對(duì)調(diào)用這個(gè)方法的window吧
tangrui.cn: 現(xiàn)在 lcore 的 unit test 最后一個(gè)有問題之外,其他的都是可以用的了
對(duì)
而且不能用到 function 里面
比如你應(yīng)該 using(longjs.lang);
而不能 var MyClass = function() { using(longjs.lang) }; 這樣就不對(duì)了
這時(shí)候 using 的 this 就是 MyClass 了
Weiming: var MyClass = function() { using(longjs.lang) };
這肯定不行
tangrui.cn: 所保險(xiǎn)起見是應(yīng)該提供這樣的一個(gè)參數(shù),但是可以允許省略
Weiming: 那就得寫成
longjs_using
tangrui.cn: 是呀,前提都是這么寫
要不這么寫,就一定要提供這個(gè)參數(shù)
Weiming: 除了不好看,還有什么問題
tangrui.cn: 沒什么問題
以前也是這么寫的,就是沒有 longjs 前綴
Weiming: 還是有一個(gè)前綴好
tangrui.cn: 我覺得寧愿加一個(gè)參數(shù)也不這么寫
Weiming: longjs_using比using好
我是寧可不加這個(gè)參數(shù)
tangrui.cn: 加一個(gè)參數(shù),無論如何是保險(xiǎn)的
Weiming: 你想,肯定很多的人
都會(huì)問你
為什么
我這個(gè)頁(yè)面,調(diào)用
longjs.using
還非得加一個(gè)window,我不就是在這個(gè)window么?
既然我再這個(gè)window,那么為什么還得加上
tangrui.cn: 但是這個(gè)方法不是在這個(gè) window 里面 run 的
Weiming: 但是會(huì)很不爽
tangrui.cn: 這樣的問題有的是
比如 win$()
你必須指定一個(gè) window 即便你在這個(gè) window 里面
Weiming: 哪個(gè),我明顯是要操作其他的window的,
我覺得win$可以省略
tangrui.cn: 這個(gè)可以說是 js 編程的一個(gè)特例,沒什么辦法
Weiming: 如果省略了,就是本window
還有,如果我沒有jsframe
那么我怎么用?
tangrui.cn: 不可以省略,省略了就是 jsFrame 里的東西了
Weiming: 我覺得不能接受,肯定很多的人不接受
至少我就不接受
我寧可寫一個(gè)不好看的longjs_win$
tangrui.cn: 因?yàn)楝F(xiàn)在 win$ 放到了 lcore 里面,以后應(yīng)該放到比如 longjs.web.dom.LElement 這樣的類型下面
無論如何是不能省略 window 的
Weiming: 不好
我寧可已給一個(gè)叫做longjs_win$的alias
tangrui.cn: 而且省略了 window 只是代碼上面稍微好看了一點(diǎn),但是會(huì)帶來嚴(yán)重的不安全性
給 alias 也沒有
Weiming: 如果我沒有jsframe之類的東西
我只有這個(gè)也沒
你讓我都寫一個(gè)這個(gè)東西,自己的這個(gè)window,
tangrui.cn: 再說 longjs 下面只放和 core 有關(guān)的,這些和 core 是無管的
Weiming: 很丑陋啊
tangrui.cn: 沒有辦法,我也不想這樣
否則就是那個(gè) class
Weiming: 如果這樣,那么我要是用,我肯定寫一個(gè)很小的做alias的js,然后每個(gè)頁(yè)面都include
tangrui.cn: javascript 就這樣,否則都寫成平的,就一點(diǎn)問題都沒有了
Weiming: 我覺得,這些和window相關(guān)的,
tangrui.cn: 這是他的事情了
Weiming: 給window是應(yīng)該的
tangrui.cn: 如果他這樣的話為什么還要用咱么的東西
Weiming: 但是,不給,默認(rèn)是當(dāng)前的window,也是應(yīng)該的
ok,這就是問題了
tangrui.cn: 問題是做不到
Weiming: 你出這個(gè)東西,
目的是方便大家的使用啊
當(dāng)然是越方便越好了
tangrui.cn: 那也要有一定的適用條件
Weiming: 還是這個(gè)問題
如果我只有一個(gè)頁(yè)面,我也得都寫window
我本來只有一個(gè)window啊
tangrui.cn: 所以我說有一個(gè)適用條件
Weiming: longjs,是不應(yīng)該依賴jsFrame的
也就是,我必須用這個(gè)webfx么?
tangrui.cn: 按照有 jsFrame 的模式來用是 longjs 的長(zhǎng)處,也是區(qū)別于 dojo 的地昂
地方
Weiming: 為什么我一定要有jsFrame
tangrui.cn: 你要是 single page 的首先一點(diǎn)就是他為什么要用你的東西而不用 dojo 的
Weiming: 我不是single page啊
tangrui.cn: 當(dāng)然你不一定有,但是我的 api 是根據(jù)有 js frame 優(yōu)化的
Weiming: 我也是每個(gè)頁(yè)面都去跳轉(zhuǎn)啊
做軟件的一個(gè)點(diǎn),就是讓用戶用起來很方便,
把麻煩留給自己,而不是用戶
tangrui.cn: 沒有我可以保證運(yùn)行正常,有我也會(huì)保證運(yùn)行正常,且他們能保持同樣的 api 接口
Weiming: 可是,這樣很煩啊
況且,我只有一個(gè)window,你為什么還讓我非得寫這個(gè)window
tangrui.cn: 你用 frame work 的初衷是要解決你棘手的問題
Weiming: 比如什么棘手的問題?
tangrui.cn: 這點(diǎn)東西相比之下就不足味道了
Weiming: 我不認(rèn)為
當(dāng)一個(gè)開發(fā)者,用一個(gè)庫(kù)不爽的時(shí)候,他會(huì)選擇放棄這個(gè)庫(kù)
tangrui.cn: 當(dāng)然對(duì)于他來講我能不能有一個(gè) tree 有一個(gè) datagrid 是更重要的
問題是這樣沒什么不爽呀
Weiming: 難道這樣很爽么?
就好像
tangrui.cn: 何況是咱么現(xiàn)在討論的這個(gè)問題是沒有辦法jiejuede
Weiming: 你寫所有的關(guān)于net的程序
tangrui.cn: 解決的,就算不爽也辦法,我也覺得不爽,但是只能這樣
Weiming: 所有的方法,你都需要寫一個(gè)localhost
這樣你也會(huì)不爽
我并不認(rèn)為只能這樣
這個(gè)是可以解決的
tangrui.cn: 當(dāng)然可以有一個(gè) work around 就是再提供一個(gè) $() 方法
Weiming: 提供$,我也不認(rèn)為是work around的方法
我認(rèn)為是標(biāo)準(zhǔn)的做法
tangrui.cn: 這個(gè)方法里面直接調(diào)用 window.document.getElementById()
Weiming: 如果非要加上window,那么就必須給一個(gè)不要window的方阿飛
tangrui.cn: 如果你保證是 single page 就用這個(gè)方法,否則這個(gè)方法永遠(yuǎn)返回 js frame 里面的東西
那么 using 也可這么做
Weiming: 這個(gè)方法,為什么要放在jsFrame里面?
tangrui.cn: 只有在 single page 的時(shí)候允許他不用加上 window
Weiming: 操作本window,都應(yīng)該可以不加上
tangrui.cn: 所有的方法都在 js frame 里面
Weiming: 為什么?
tangrui.cn: 現(xiàn)在所有的方法都在 js frame 里面,上面的 frame 沒有任何類庫(kù)相關(guān)的內(nèi)容
Weiming: 為什么?
tangrui.cn: 不為什么呀,要不然咱么做這個(gè)干什么呢
Weiming: 那么,也就是我必須有一個(gè)jsFrame咯
tangrui.cn: 不需要呀,你不用 js frame 就把他們 perpage include 就可以了
反正不用 window 的重載只會(huì)返回代碼所在的那個(gè) window 里面的東西
Weiming: 如果
tangrui.cn: 所以通常是 js frame 除非他是 single page 的
Weiming: 如果,你提供了這個(gè)必須寫window的東西
然后,有人寫一個(gè)很小的做alias和一些window處理的js
要求每個(gè)頁(yè)面都include
那么你認(rèn)為,大家會(huì)不會(huì)使用這個(gè)
如果不會(huì),為什么
tangrui.cn: 你要是這么說得話,就沒有意義了
Weiming: 如果會(huì),能有多少人用?
為什么沒意義?
tangrui.cn: 他所有的都可以這么做,為什么好要用咱么的東西
Weiming: 做為使用者,
我不但要求功能強(qiáng)大,我還要求使用方便
你提供功能強(qiáng)大
那么為什么,我不能在你提供功能強(qiáng)大的基礎(chǔ)上,做一個(gè)使用方便的呢
tangrui.cn: 再說,我已經(jīng)給他提供了足夠好用的變通方法,如果他再不認(rèn)可,那還能有什么辦法
讓他自己寫這樣的框架最終也要寫成這樣
Weiming: 你的變通的方法,不也得是每個(gè)頁(yè)面做include么
tangrui.cn: 不用呀
Weiming: 那么,我怎么用$
又能解決有window的,又能解決沒有window的
tangrui.cn: 在多頁(yè)面的情況下不能用 $
Weiming: 如果我是本頁(yè)面,為什么不能?
tangrui.cn: 不能就是不能,javascript 不做不到
Weiming: 不會(huì)啊
$ = function (id, win) {
win = win || window;
}
這樣就可以啊
tangrui.cn: 你要是在本頁(yè)面 include 代碼的話,那么這個(gè)代碼至少不屬于框架的一部分
Weiming: 我認(rèn)為是框架的一部分
你既要給強(qiáng)大的功能,還要給最簡(jiǎn)單和方便的使用方法
tangrui.cn: 咱么可以提供很多這樣的 util 來輔助用戶
但是同時(shí)他這樣帶來的是代碼的重復(fù)
Weiming: 重復(fù)在什么地方?
tangrui.cn: 作為一個(gè)框架你不能在任何時(shí)候都往 util 里面加?xùn)|西
Weiming: 這個(gè)是肯定的
tangrui.cn: 比如 java 用戶自然希望往屏幕上輸出一行字,用 print(abc); 就可了
Weiming: 但是前提是我可以很”方便”的使用你”強(qiáng)大”的框架
tangrui.cn: 但是作為一個(gè)框架,他必須要 System.out.println();
Weiming: 這點(diǎn)我承認(rèn)
tangrui.cn: 你認(rèn)為這樣不可以接受嗎
Weiming: 我認(rèn)為不可接受
所以我的,并且很多人的
tangrui.cn: 框架就要有框架的規(guī)矩
Weiming: java,如果是做一個(gè)大的
那么肯定有一個(gè)叫做print的方法
框架有框架的規(guī)矩,是針對(duì)框架內(nèi)部說的
對(duì)于用戶,就應(yīng)該給最方便的
就好比
tangrui.cn: 如果有一個(gè)方法可以游離于框架之外,那么就會(huì)有更多的方法游離
不肯能,否則類庫(kù)就沒有必要設(shè)計(jì)了
Weiming: 我不認(rèn)為,框架,只能從一個(gè)地方include
一個(gè)類庫(kù),也不是說,我必須只能從一個(gè)地方include
tangrui.cn: 我覺得這個(gè)也沒有必要討論了
Weiming: 如果又方便的方法,那么肯定會(huì)有人寫,并且大量的人用
結(jié)論
tangrui.cn: 最后的結(jié)果,首先在類庫(kù)內(nèi)部沒有辦法,提供這樣的方法,所以只能提供 win$ 和 $
然后在頁(yè)面上可以隨便 include 任何的代碼
Weiming: win$放在那?
$放在那?
tangrui.cn: 但是這些不能算作框架的一部分,只是為了方便
Weiming: 頁(yè)面include什么?
tangrui.cn: 都在方他們?cè)撛诘牡胤?/div>
Weiming: 你說對(duì)于解析xml,算作框架的一部分么?
tangrui.cn: 框架中的方法肯定不能任意游離
如果咱么要做的話,就算
Weiming: xerces,
這個(gè)現(xiàn)在已經(jīng)被包含在java里面了
但是開始他并沒有
從這里,就能說明,框架,不是一個(gè)單根的
tangrui.cn: 但是他加到 java 里面去以后也不可能是游離的
就像 java 永遠(yuǎn)都無法提供 print 方法一樣
Weiming: 我可以接受,框架有框架的規(guī)矩
但是,我要求吧util做為框架的一部分
tangrui.cn: 除非把它做進(jìn) vm 和編譯器
Weiming: 他并不是游離
tangrui.cn: 這樣的話就已經(jīng)不屬于框架類庫(kù)的一部分了
Weiming: 每名把,什么做進(jìn)vm?
為什么不屬于?
這么說罷,從實(shí)用主意
你會(huì)不會(huì)使用這個(gè)東西?
tangrui.cn: 框架不能有 util 的東西,還是那句話,有一個(gè)就會(huì)有更多
Weiming: 你會(huì)不會(huì)在你的頁(yè)面include這個(gè)東西
關(guān)鍵不是有多少,而是為什么有
如果他有他存在的理由,那么多少也是應(yīng)該的
tangrui.cn: 或許說得準(zhǔn)確一點(diǎn),這個(gè)不算是類庫(kù)的一部分,但是可以算作框架的一部分
Weiming: 這個(gè)說法,我接受
tangrui.cn: 我還是那句話,不建議他用這套框架寫 single page 的東西
Weiming: 就好像,如果真的,java給出的sdk里面,有一個(gè),print的方法,你覺得多少人還會(huì)用system.out.print
tangrui.cn: 否則重復(fù)做一個(gè) dojo 沒有意思
Weiming: 1,我并不是覺得,這個(gè)是重復(fù)的dojo
tangrui.cn: 那么他內(nèi)部肯定也是轉(zhuǎn)換成 system out
Weiming: 2,這個(gè)的目的是,就算當(dāng)dojo用,也要比dojo好
這個(gè)是我的目標(biāo)
tangrui.cn: 所以這樣的方法不能是類庫(kù)的一部分
Weiming: 用戶不管你是不是轉(zhuǎn)換
tangrui.cn: 問題是你和 dojo 競(jìng)爭(zhēng)是沒有意義的
Weiming: 所以,我堅(jiān)持他是框架的一部分
我并沒有和dojo競(jìng)爭(zhēng)
競(jìng)爭(zhēng)也沒有意義
tangrui.cn: 我不需要比 dojo 做得好,別人用我的東西,是因?yàn)?dojo 做不到
Weiming: 但是如果,非要這么做,要保證比他出色
longjs不是針對(duì)single page
但是也要兼容single page
tangrui.cn: 當(dāng)然,做就要做好了,但是咱么和 dojo 是沒有競(jìng)爭(zhēng)關(guān)系的
或者說是 dojo 的超集
Weiming: 有沒有競(jìng)爭(zhēng)關(guān)系,不是咱們說了算的,要看用戶
很多地方,做成single page類似的是很有必要的
比如我做一個(gè)login 的一個(gè)塊
我就要求要能夠隨意的include到其他的頁(yè)面里面
這個(gè)很正常的
tangrui.cn: 這個(gè)就沒有必要了吧,直接寫 html 比用任何框架都劃算
Weiming: 很有必要啊
比如我同時(shí)幾個(gè)產(chǎn)品
都需要認(rèn)證
login
當(dāng)然只寫一個(gè)就好了
tangrui.cn: 這個(gè)先討論到這里吧,還有一個(gè)問題
Weiming: ok,什么?
tangrui.cn: 這個(gè)屬于 user control 更高級(jí)了
就是我在想這個(gè)文檔怎么寫,肯定沒有時(shí)間寫所有的文檔了,所以只能寫用戶文檔
我想用戶文檔就寫成 java doc
Weiming: 你指的用戶文檔,就是api doc么?
tangrui.cn: 然后應(yīng)該有工具可以轉(zhuǎn)成一份文檔
tangrui.cn: 其實(shí) api doc 寫好了就是用戶文檔
這些都是生成doc的工具
這個(gè)好說
tangrui.cn: java 和 msdn 都是這樣,把說明寫全了,再寫上示例代碼就足夠了
Weiming: 示例代碼必要
tangrui.cn: 那就好,睡覺了
Weiming: 呵呵,去吧
歸類于: javascript, Programming — 尹偉銘 @ 12:11 評(píng)論(1)
2006-07-14

剛剛?cè)滩蛔∈职W,下載了一個(gè)Firefox 2.0 Beta 1(可能過幾天這個(gè)鏈接就換了)。寫了一段JS,看來果然在JS1.7當(dāng)中,Iterator是非常好用的。

代碼如下
================================
<html>
<head>
<script language=javascript>
// add function for JavaScript Object
Object.prototype.newfunc = function(){};
function init() {
    var a = [1,2,3,4];
    var it;
    var s;

    // old method in JavaScript 1.5
    s = “”;
    for (it in a) {
        s += it + ” ==> ” + a[it] + “<BR>”;
    }
    document.getElementById(”old_in”).innerHTML = s;

    // new one in JavaScript 1.7
    s = “”;
    try {
        it = Iterator(a, true);
        while (true) {
            var key = it.next();
            s += key + ” ==> ” + a[key] + “<BR>”;
        }
    } catch (err if err == StopIteration) {
        //alert(”End of record.\n”);
    } catch (err) {
        //alert(”Unknown error: ” + err.description + “\n”);
    }
    document.getElementById(”new_in”).innerHTML = s;
}
</script>
</head>
<body onload=”init()”>
<div id=old_in></div>
<hr>

<div id=new_in></div>
<hr>

</body>
</html>
================================

運(yùn)行結(jié)果如下:
0 ==> 1
1 ==> 2
2 ==> 3
3 ==> 4
newfunc ==> function () { }


0 ==> 1
1 ==> 2
2 ==> 3
3 ==> 4
 

 

可見,使用Iterator是可以避免在for之中錯(cuò)誤的使用一些未知的新添加的方法的。     

有一點(diǎn)遺憾的就是,Iterator的結(jié)束是很丑陋的,不知道有沒有什么好的方法。還需要繼續(xù)研究。 

 

 

歸類于: javascript — 尹偉銘 @ 12:19 評(píng)論(1)
2006-07-13

Firefox 2.0 beta 1推出了,肯定很多人已經(jīng)關(guān)注這個(gè)事情了,我則比較(更加)關(guān)心的是JavaScript的增強(qiáng)。JavaScript升級(jí)到1.7了(FF1.5支持JavaScript1.5,IE6sp1支持不完全的JavaScript1.5)

JavaScript 1.7里面有了一些新功能的支持,比如Generator和Iterator,let語法的支持,非結(jié)構(gòu)化賦值(destructuring assignment)。
令我最關(guān)心和期待的就是Iterator的支持,據(jù)說只要自定義next方法和__iterator__屬性就可以根據(jù)自己的需要定義返回的值了。Iterator的出現(xiàn)最大的好處就是可以放心的在一些內(nèi)嵌的對(duì)象當(dāng)中添加方法了。

以前這樣的代碼是很危險(xiǎn)的:
var o = new Object();
for (var i in o){}
因?yàn)楹芸赡苣硞€(gè)第三方的庫(kù)文件在Object當(dāng)中添加了一些方法,(比如著名的prototype),這樣,在不同的第三方庫(kù)混用的時(shí)候,就很可能出現(xiàn)問題。

現(xiàn)在有了自定義的Iterator,那么我覺得是完全可以避免的,只要為Object寫好合適的iterator就可以了。具體的代碼我還沒有嘗試。

還有一個(gè)問題,就是不知道IE7支持JavaScript到什么版本,而且,IE6和Firefox1.5.*都還是JavaScript 1.5 并且很多人是不會(huì)升級(jí)的。
所以,JavaScript1.7也許在未來的一段時(shí)間內(nèi),還是一個(gè)美好的(但是不能實(shí)現(xiàn)的)愿景吧。

歸類于: javascript — 尹偉銘 @ 11:25 評(píng)論(0)
2006-06-20

如我前面的文章說的,對(duì)于JavaScript,一個(gè)類,就是一個(gè)function,他的類方法(也就是static的)都是作為這個(gè)function的一部分,而實(shí)例方法,都是在prototype上面的。
function ClassA() {
}

ClassA.staticMethod = function () {
}

ClassA.prototype.instanceMethod = function () {
}

在我這個(gè)實(shí)現(xiàn)當(dāng)中,一個(gè)類的繼承是拷貝父類的所有類方法,這樣子類就有了父類的靜態(tài)方法。
然后讓子類的prototype.prototype指向父類的prototype.
然后可以根據(jù)自己的需要,重寫一些方法。
function ClassB() {
}
ClassB.staticMethod = ClassA.staticMethod;
ClassB.prototype.prototype = ClassA.prototype;
ClassB.prototype.instanceMethod = function () {
// method 2
}

對(duì)于子類,使用一個(gè)prototype的鏈,來實(shí)現(xiàn)方法的實(shí)例方法的繼承。之所以選擇這種實(shí)現(xiàn)方法,是因?yàn)樽宇愂且貙懫渲械哪承┓椒ǖ?。而prototype又是一個(gè)reference,所以直接的寫作ClassB.prototype = ClassA.prototype,會(huì)在重寫ClassB的實(shí)例方法的同時(shí),破壞ClassA的實(shí)例方法。而修改后的方法則會(huì)屏蔽父類的。

尋找方法的順序是,instanceA.prototype.method -> ClassA.prototype.
此時(shí)對(duì)于類方法的繼承,已經(jīng)實(shí)現(xiàn),現(xiàn)在需要實(shí)現(xiàn)在子類中,調(diào)用父類的方法。
對(duì)于Java,這樣的使用是很平常的
public void method() {
super.method();
}
在JavsScript中,為了實(shí)現(xiàn)此類功能,所以必須保留一個(gè)parent的reference,指向ParentClass.prototype.
ClassB.prototype.parent = ClassA.prototype.
那么在instanceB里面調(diào)用this.parent.method.call(this);就可以使用父類的方法了。使用call調(diào)用,是為了把自己的數(shù)據(jù)傳到父類。更漂亮的解決方法,我還沒有想到。

所以完成的代碼是
function ClassA() {
}

ClassA.prototype.method1 = function () {
}

ClassA.staticMethod = function () {
}

function ClassB(){
}

ClassB.staticMethod = ClassA.staticMethod;

ClassB.prototype.prototype = ClassB.prototype.parent = ClassA.prototype;

這個(gè)我抽象出來一個(gè)extend方法,

var LCore = function () {
}

LCore.extend = function (destination, source) {
// copy all functons
for (var prop in source) {
if (prop == “prototype”) {
continue;
}

destination.prototype[prop] = source[prop];
}

// make a reference for parent and reference prototype
destination.prototype.prototype = destination.prototype.parent = source.prototype;

return destination;
}

歸類于: javascript, OOP — 尹偉銘 @ 7:49 評(píng)論(0)
2006-05-13

停了一段時(shí)間,今天說說JavaScript的面向?qū)ο?br>js不是一個(gè)天生的oo的語言。但是他的函數(shù)是可以擔(dān)負(fù)面向?qū)ο蟮母拍畹?。并且js也內(nèi)置了很多的對(duì)象,比如String,Date等等。

js有一個(gè)關(guān)鍵字new,可以認(rèn)為是實(shí)例化一個(gè)function的對(duì)象,把function作為一個(gè)class。
比如
function MyObj () {
}
var myObj = new MyObj();
這個(gè)時(shí)候,myObj就是MyObj的一個(gè)實(shí)例。

有兩點(diǎn)應(yīng)該具體的說一下
1,JavaScript是一個(gè)prototype的語言
2,this在JavaScript里面的應(yīng)用

首先我們說一下prototype,prototype是一個(gè)function的屬性,也可以認(rèn)為是一個(gè)類的屬性。他用來記錄這個(gè)類有那些方法。
比如我們要給MyObj定義一個(gè)sayHello的方法,我們可以這樣寫
MyObj.prototype.sayHello = function () {
alert(”Hello”);
}
這個(gè)時(shí)候,我們就可以調(diào)用myObj.sayHello()執(zhí)行這個(gè)方法。

而this則表示這個(gè)類本身(嚴(yán)格意義上說,應(yīng)該是這個(gè)函數(shù)本身),比如
MyObj.prototype.sayBye = function () {
alert(”bye” + this.name);
}
那么這里的this,就是實(shí)例變量本身。myObj.sayBye()。函數(shù)里面的this就是表示myObj。那么我們就可以實(shí)現(xiàn)帶參數(shù)的構(gòu)造函數(shù)。

function MyObj2(name) {
this.name = name;
}
var myO2 = new MyObj2(”tom”);
這樣,我們就可以實(shí)現(xiàn)一般情況下使用的面向?qū)ο罅恕?/p>

需 要主意的是,JavaScript沒有屬性的共有私有機(jī)制,我們可以通過myO2.name訪問他的name屬性。而且js也不是強(qiáng)行規(guī)定的,我們要訪問 myO2.age也是可以的,但是myO2并沒有age的屬性(或者說重來沒有給age賦值)那么得到的就是undefined。
通過這個(gè),我們就可以用Object來實(shí)現(xiàn)平常使用的Map(java語言,對(duì)于python應(yīng)該是字典類型)。
var m = new Object();
m[”name”] = “tom”;
m[”age”] = 20;
alert(m[”name”]);
注1:對(duì)于alert,JavaScript調(diào)用的是這個(gè)object的toString函數(shù),如果沒有,則會(huì)顯示 ie:[object] ff:[object, Object]
注2:在js當(dāng)中,new Object和{}是一樣的,我們可以寫 var m = {};
這也是js中簡(jiǎn)單的map的實(shí)現(xiàn)。不好的地方是遍歷不方便,因?yàn)闆]有地方記錄有那些key
for (var i in m) 這種遍歷方法,會(huì)把所有的對(duì)于object進(jìn)行擴(kuò)展的方法都顯示出來。

對(duì)Object的擴(kuò)展,是通過對(duì)Object的prototype添加方法實(shí)現(xiàn)的。
比如js的String方法是沒有trim的,我們可以自己做一個(gè)實(shí)現(xiàn)然后通過擴(kuò)展String來提供這個(gè)方法
String.prototype.trim = function () {}
var a = ” 123 “.trim();

上面提到了一下this,之所以說一下this,是因?yàn)樗⒉煌耆韧贑++或者Java里面的this變量。
this在js中表示緊貼著調(diào)用地點(diǎn)的,非prototype擴(kuò)展的方法。
比如上面提到的
MyObj.prototype.sayBye = function () {
alert(”Bye” + this.name);
}
這個(gè)里面的this,緊貼的非prototype的函數(shù)是MyObj(再次注意,js中class是通過函數(shù)實(shí)現(xiàn)的),所以this.name就是實(shí)例變量。
但是在這種情況
MyObj.prototype.doSomething = function () {
todo(function () {
alert(this.name);
});
}
這個(gè)時(shí)候,this表示的是這個(gè)匿名函數(shù)
function () {
alert(this.name)
}
那么這里就會(huì)出現(xiàn)錯(cuò)誤,如果想要這樣使用,應(yīng)該使用輔助變量。
MyObj.prototype.doSomething = function () {
var me = this; //把自己的reference賦值給變量me
todo (function () {
alert(me.name); //通過me來訪問myObj實(shí)例
});
}
而且所有的實(shí)例變量必須通過this來進(jìn)行訪問,直接寫變量名稱會(huì)認(rèn)為是全局的變量。
上例中的alert(this.name)是正確的,而alert(name)是錯(cuò)誤的。

還有最后說一下靜態(tài)方法。我們可以用js來模擬靜態(tài)方法(或者說是類方法)
就是直接把方法寫在函數(shù)上
MyObj.staticMethod = function () {
}
這種方法都是實(shí)例無關(guān)的,調(diào)用的時(shí)候,通過MyObj.staticMethod()來調(diào)用。其實(shí)這也是一個(gè)變通的方法。

下一次我再說說類的繼承。
大家有什么想要聽的,告訴我,如果我會(huì),那么我一定分享出來。

歸類于: javascript — 尹偉銘 @ 4:17 評(píng)論(0)

今天說一下函數(shù)參數(shù)。

函數(shù)參數(shù),可以理解為函數(shù)的參數(shù),還有就是函數(shù)作為參數(shù)(還是挺詭意)。
首先說一下函數(shù)的參數(shù)。
這個(gè)問題看上去沒有什么可說的。因?yàn)樽鳛榕拇a的,都肯定知道這個(gè)東西。
function method1(a, b) {
return a + b;
}
很簡(jiǎn)單,a,b就是函數(shù)method1的參數(shù)。一般情況下,這樣足夠了。
但是在JavaScript當(dāng)中,函數(shù)的調(diào)用,其中的參數(shù)個(gè)數(shù)是不強(qiáng)制的。(作為腳本語言,當(dāng)然類型也沒有強(qiáng)制)。
這里很象某些語言的不定參數(shù)列表(由于我沒有過多的研究,所以不便多說)。
比如上面的方法
var c = method1(1,2); //正確
var d = method(1); //也正確
此時(shí)c的值是3,d的值是NaN。
那么我們?nèi)绾蝸肀WC參數(shù)的個(gè)數(shù)呢?
JavaScript當(dāng)中,每一個(gè)方法里面,有一個(gè)內(nèi)欠的變量,arguments。這是一個(gè)數(shù)組變量,記錄著傳入這個(gè)方法一共有幾個(gè)參數(shù)。
很象java里面main函數(shù)的 args數(shù)組
static public void main(String args[]) {…}
我們可以使用arguments.length來判斷一共有幾個(gè)參數(shù)
function method2() {
if (arguments.length == 2) {
return arguments[0] + arguments[1];
} else {
return 0;
}
}
這樣我們就可以保證參數(shù)的個(gè)數(shù)了。

接下來,我們說一下函數(shù)作為參數(shù)。
在昨天的例子當(dāng)中,我使用了很多這樣的例子。比如
ServerHandler.getName(myID, fucntion (name) {
alert(”Hello:” + name);
});
這里面,getName方法的第二個(gè)參數(shù)就是一個(gè)方法,
function (name) {…}
在JavaScript 當(dāng)中,任何的東西都是Object,一個(gè)函數(shù)的類型是Function,他是Object的一個(gè)子類(姑且這么說,JavaScript不是一個(gè)純粹的面 向?qū)ο蟮恼Z言,所以說子類有一些牽強(qiáng))。所有的Object都可以作為參數(shù)被傳入函數(shù)。那么一個(gè)函數(shù)作為參數(shù)就不足為奇了。

暫停一下,我們現(xiàn)來看一下這個(gè)例子。
function method3() {
alert(”Hello”);
}

var m = method1;
var v = method1();
上面的兩個(gè)變量,m,v,他們的區(qū)別就是,v是method1運(yùn)算的結(jié)果,在這里是undefined,因?yàn)閙ethod3在alert以后什么都沒有返回。
而m,這句付值語句,是把method3的函數(shù)體,付值給了m(有興趣的話,可以使用alert(m)來看一下結(jié)果)。如果現(xiàn)在寫下如下的語句
m();
那么就會(huì)調(diào)用這個(gè)函數(shù),然后alert一個(gè)Hello。

好,我們回來,上面我想說明的就是,當(dāng)一個(gè)函數(shù)作為參數(shù)傳入到另外的一個(gè)函數(shù)當(dāng)中,我們是可以使用一個(gè)參數(shù)變量來接受這個(gè)函數(shù)的。并且在需要的時(shí)候,我們可以繼續(xù)的分發(fā),或者調(diào)用。
比如
function method4(m) {
m();
}

method4(method3); //注意,這里面的method3沒有后面的括號(hào)(),他表示是這個(gè)函數(shù)體作為參數(shù)而不是運(yùn)行結(jié)果作為參數(shù)。
在進(jìn)入到method4里面之后,通過參數(shù)變量m,可以調(diào)用method3。

利 用函數(shù)作為參數(shù),在JavaScript中使用的最普遍的就是callback方法了。當(dāng)需要執(zhí)行一個(gè)函數(shù),傳入一個(gè)callback function用來處理結(jié)果。這種方法我們?cè)诤芏嗟胤揭呀?jīng)使用的非常多了。現(xiàn)在隨著AJAX的流行,callback方法也越來的重要。如我昨天所說, 很多的和server通訊的方法都是無法預(yù)料何時(shí)能夠結(jié)束的。那么傳入一個(gè)callback function就很方便了。

這里,我一直有這樣的一個(gè)難點(diǎn),始終沒有很好的解決辦法。
就是一般情況,我們給出callback function,都是在無法控制返回時(shí)間的情況下采用的,那么此時(shí),大多數(shù)的情況就是這個(gè)方法會(huì)使用另外的線程來執(zhí)行,而程序會(huì)繼續(xù)向下走。
使用返回值的函數(shù)調(diào)用,是會(huì)在這個(gè)函數(shù)調(diào)用的時(shí)候,線程阻塞,直到返回結(jié)果。
我現(xiàn)在遇到的情況就是,很多的時(shí)候,我無法返回值(比如AJAX),而使用callback function也挺麻煩。所以一直沒有好的方法。
雖然我昨天說的信號(hào)量的方法可以變通的解決這個(gè)問題。但是在復(fù)雜的情況下(比如我現(xiàn)在正在開發(fā)的一套Web UI Framework)里面也是挺麻煩的。希望大家如果有好的方法可以告訴我。

最后,還要提及的一點(diǎn)就是,在函數(shù)調(diào)用的時(shí)候,還有一種方法就是call(或者apply)調(diào)用。
function method5(msg) {
alert(msg);
}
method5.call(x, “Hello”);
這個(gè)x就是某個(gè)Object的變量(從面向?qū)ο蟮慕嵌瓤梢哉f是一個(gè)實(shí)例(instance))。很類似于python的self。
這個(gè)使用方法在一般情況下意義不大。但是在某種面向?qū)ο髮?shí)現(xiàn)的時(shí)候是非常有用的。我會(huì)在面向?qū)ο蟮奈恼轮性俅握f明的。

歸類于: javascript — 尹偉銘 @ 4:17 評(píng)論(0)

從今天開始,我會(huì)不定期的寫一些關(guān)于JavaScript的東西,包括語言,應(yīng)用等方面。組成JavaScript系列。
如果沒有特殊的說明,這里假定JavaScript的執(zhí)行環(huán)境是在瀏覽器(browser)當(dāng)中的。
今天開始第一次,討論一下同步和異步。

曾經(jīng)查詢過一些JavaScript的信息,發(fā)現(xiàn)google出來的結(jié)果都是詢問JavaScript如何能夠?qū)崿F(xiàn)異步的代碼。
而我,很不幸,查詢的卻是如何讓JavaScript實(shí)現(xiàn)異步調(diào)用的同步(是不是挺起來很詭異)。

首先說一下JavaScript當(dāng)中的異步方法。
其實(shí)這個(gè)問題是大家經(jīng)常要碰到的。而且這個(gè)實(shí)現(xiàn)也很簡(jiǎn)單。我就不多說了。
給兩段代碼

  1. setTimeout方法,他讓你的代碼在指定的時(shí)間(毫秒)之后執(zhí)行指定的方法。只執(zhí)行一次。
    比如:
    alert(1);
    setTimeout(”alert(2)”, 1000);
    alert(3);
    代碼在執(zhí)行到setTimeout的時(shí)候,會(huì)繼續(xù)執(zhí)行下面的代碼(alert(3))而不會(huì)被阻塞。等待1000ms之后執(zhí)行alert(2)
  2. setInterval方法,他讓你的代碼每隔指定的時(shí)間,執(zhí)行指定的方法,直到調(diào)用clearInterval
    比如:
    alert(1);
    timer = setInterval(”alert(2)”, 1000);
    alert(3);
    代碼基本上和上面的相同,不同的是,每隔1000ms就會(huì)執(zhí)行一次alert(2),直到調(diào)用
    clearInterval(timer);

我們應(yīng)該注意到setTimeout和setInterval都是window的方法。
我們可以直接使用,但是規(guī)范的還是調(diào)用window.setTimeout window.setInterval,之所以提及這個(gè),我會(huì)在以后的JavaScript系列中繼續(xù)講解。

現(xiàn)在該說一下我遇到的問題了。
我現(xiàn)在使用dwr作為AJAX的server端引擎,在調(diào)用dwr方法的時(shí)候,需要提供一個(gè)回調(diào)方法(callback function)來接受server的返回結(jié)果。
而這個(gè)回調(diào)方法是不會(huì)被阻塞的。此時(shí)browser回啟動(dòng)另外的現(xiàn)成處理。
這個(gè)很好理解,因?yàn)閐wr的這個(gè)方法執(zhí)行的時(shí)間是無法預(yù)料的,如果此時(shí)調(diào)用被阻塞,而server又花相當(dāng)長(zhǎng)的時(shí)間進(jìn)行處理。那么瀏覽器就會(huì)死在這里。從用戶體驗(yàn)的角度是根本無法接受的。
這里的例子代碼是


ServerHandler.getString(”Weiming”, function (str) { //”Weiming”是傳回server的參數(shù)
alert(str);
}); // ServerHandler是dwr提供的server方法的interface,具體使用請(qǐng)參見dwr網(wǎng)站。
alert(1);
在執(zhí)行的過程中,會(huì)先執(zhí)行alert(1),然后在一個(gè)無法預(yù)料的時(shí)間后執(zhí)行alert(str)。
如果一次簡(jiǎn)單的比如hello world的調(diào)用是不會(huì)出問題的。
但是如果我要執(zhí)行的一系列的dwr function是有前后順序的,比如后面執(zhí)行的需要前面的返回結(jié)果,簡(jiǎn)單的代碼書寫順序是無法保證執(zhí)行順序的。
var myID = null;
ServerHandler.getID(function (id) {
myID = id; //無法預(yù)料何時(shí)會(huì)執(zhí)行這句話
});

ServerHandler.getUserWithID(myID, function (name) {
/*
此時(shí)myID還沒有值,因?yàn)樯厦娴?myID = id這段代碼是需要一個(gè)時(shí)間段之后才會(huì)執(zhí)行的
*/
alert(”hello:” + name);
});

比如這樣的代碼就會(huì)出錯(cuò)。那么如何解決呢?
最簡(jiǎn)單的實(shí)現(xiàn)方法就是callback function的嵌套。

ServerHandler.getID(function (id) {
ServerHandler.getUserWithID(id, function (name) {
alert(”hello:” + name);
}
});
這樣我們就可以保證多個(gè)dwr方法調(diào)用的順序了。這樣貌似解決了問題。但是并不完美。
原因是當(dāng)我們把JavaScript和Browser作為一個(gè)操作的平臺(tái)和邏輯業(yè)務(wù)的平臺(tái)(AJAX的應(yīng)用程序,后面的JavaScript系列中會(huì)有提及),而不是一個(gè)簡(jiǎn)單的展示平臺(tái)的時(shí)候。這樣的回調(diào)函數(shù)嵌套就很難控制了。
這也就是我最開始指出的需要同步異步調(diào)用的一個(gè)方法。

最終我在公司的解決方案是這樣的。
寫一個(gè)信號(hào)量的類(JavaScript的面向?qū)ο髸?huì)稍后講解),當(dāng)我需要執(zhí)行一個(gè)方法的時(shí)候,我就申請(qǐng)一部分信號(hào)量。
把需要被執(zhí)行的方法放進(jìn)信號(hào)量的隊(duì)列進(jìn)行等待。等前面等待的方法(如果存在)執(zhí)行后在執(zhí)行。
信號(hào)量將作為一個(gè)參數(shù)被傳入執(zhí)行的方法,這樣這個(gè)方法可以決定釋放這個(gè)信號(hào)量還是繼續(xù)分發(fā)。
比如
var s = new Semaphore();
var myID = null;
s.p(function (e) {  //把方法放入信號(hào)量隊(duì)列
ServerHandler.getID(function (id) {
myID = id;
s.v(); //釋放信號(hào)量
}
});

s.p(function (e) { //將第二個(gè)方法放到信號(hào)量隊(duì)列,只有當(dāng)前面的s.v()執(zhí)行之后,這個(gè)方法才會(huì)執(zhí)行。
ServerHandler.getName(myID, function (name) { //此時(shí),可以保證myID一定有值
alert(”Hello:” + name);
s.v();
})
})

這里只是對(duì)信號(hào)量這個(gè)方法進(jìn)行了簡(jiǎn)單的闡述。
信號(hào)量還支持創(chuàng)建自信號(hào)量,如果創(chuàng)建了子信號(hào)量,那么父信號(hào)量必須等帶所有的孩子都?xì)w還了信號(hào)量之后才可以執(zhí)行他里面的代碼。
由于代碼的版權(quán)是公司的,所以很抱歉,現(xiàn)在無法給出相應(yīng)的完整的信號(hào)量的實(shí)現(xiàn)。
如果下一端我有時(shí)間的話,我會(huì)給出一個(gè)我實(shí)現(xiàn)的版本的。


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服