九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開(kāi)APP
userphoto
未登錄

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

開(kāi)通VIP
JavaScript簡(jiǎn)易教程

這是我所知道最完整最簡(jiǎn)潔的JavaScript基礎(chǔ)教程。

本文將帶你盡快走進(jìn)JavaScript的世界——前提是你有一些編程經(jīng)驗(yàn)的話。本文試圖描述這門(mén)語(yǔ)言的最小子集。我給這個(gè)子集起名叫做“JavaScript簡(jiǎn)易教程”,并推薦那些準(zhǔn)備深入閱讀細(xì)節(jié)和高級(jí)技巧之前的新手閱讀。合抱之木生于毫末,九層之臺(tái)起于壘土,欲速則不達(dá)。本文的最后會(huì)提出如何進(jìn)一步學(xué)習(xí)。

警告:下面是我所描述的規(guī)則集和最佳實(shí)踐。我喜歡整潔清晰(例如,你可以隨時(shí)通過(guò)下面的目錄快速導(dǎo)航)。橫看成嶺側(cè)成峰,遠(yuǎn)近高低各不同,雖然規(guī)則是無(wú)懈可擊的,但不可避免——每個(gè)人的理解會(huì)各不相同。

目錄

  1. 本文約定
  2. 語(yǔ)言的性質(zhì)
  3. 語(yǔ)法
  4. 變量和賦值
  5. 布爾
  6. 數(shù)字
  7. 字符串
  8. 語(yǔ)句
  9. 函數(shù)
  10. 異常處理
  11. 嚴(yán)格模式
  12. 變量作用域和閉包
  13. 對(duì)象和繼承
  14. 數(shù)組
  15. 正則表達(dá)式
  16. 數(shù)學(xué)
  17. 標(biāo)準(zhǔn)庫(kù)的其他功能
  18. 下一步學(xué)什么?

本文約定(Conventions used in this blog post)

命令行交互(Command line interaction)

每當(dāng)我介紹一個(gè)新概念,我都會(huì)嘗試通過(guò)JavaScript命令行進(jìn)行演示。像下面這樣:

> 3   4  7

大于號(hào)后面的文本是用戶輸入內(nèi)容。其他的都是JavaScript引擎的輸出內(nèi)容。此外,也可以使用console.log()來(lái)向控制臺(tái)打印數(shù)據(jù)(這種方法可以在大部分JavaScript引擎中工作,包括Node.js).

查找文檔(Finding documentation)

有時(shí)你會(huì)看到一些函數(shù)或方法有超鏈接,你應(yīng)該清楚他們的工作原理。如果沒(méi)有,可以在Mozilla Developer Network (MDN)上查看細(xì)節(jié),你也可以使用Google在MDN上查找文檔。例如,下面是通過(guò)Google搜索數(shù)組的push()方法的例子:

mdn array push

語(yǔ)言的性質(zhì)(The nature of the language)

本節(jié)對(duì)JavaScript的性質(zhì)做簡(jiǎn)要介紹,以幫你理解一些疑問(wèn)。

JavaScript 和 ECMAScript(JavaScript versus ECMAScript)

編程語(yǔ)言稱(chēng)為JavaScript,語(yǔ)言標(biāo)準(zhǔn)被稱(chēng)為ECMAScript。他們有不同名字的原因是因?yàn)椤癑ava”已經(jīng)被注冊(cè)為商標(biāo)(屬于Oracle)。目前,只有Mozilla被正式允許使用“JavaScript”名稱(chēng),因?yàn)楹芫靡郧八麄兊玫揭环菰S可。因此,開(kāi)放的語(yǔ)言標(biāo)準(zhǔn)擁有不同的名字。當(dāng)前的JavaScript版本是ECMAScript 5,ECMAScript 6當(dāng)前是開(kāi)發(fā)版。

影響(Influences)

JavaScript之父,Brendan Eich 別無(wú)選擇必須迅速創(chuàng)建一門(mén)語(yǔ)言。(否則,會(huì)更糟糕,Netscape將使用其他技術(shù))。他借鑒了幾門(mén)其他語(yǔ)言:

  • JavaScript借鑒了Java的語(yǔ)法和如何區(qū)分原始值和對(duì)象
  • JavaScript的函數(shù)設(shè)計(jì)受Scheme和AWK的啟發(fā)——他們(的函數(shù))都是第一類(lèi)(first-class)對(duì)象,并且在語(yǔ)言中廣泛使用。閉包使他們(函數(shù))變成強(qiáng)大的工具。
  • Self影響了JavaScript獨(dú)一無(wú)二的面向?qū)ο缶幊?OOP)風(fēng)格。它的核心思想(在這里我們沒(méi)有提到)非常優(yōu)雅,基于此創(chuàng)建的語(yǔ)言非常少。但后面會(huì)提到一個(gè)簡(jiǎn)單的模式照顧大部分用例。JavaScript面向?qū)ο缶幊痰臍⑹旨?jí)特性是你可以直接創(chuàng)建對(duì)象。不需要先創(chuàng)建類(lèi)或其他類(lèi)似的東西。
  • Perl和Python影響了JavaScript字符串,數(shù)組和正則表達(dá)式的操作。

JavaScript直到ECMAScript 3才加入異常處理,這解釋了為什么這門(mén)語(yǔ)言經(jīng)常自動(dòng)轉(zhuǎn)換類(lèi)型和經(jīng)常靜默失?。鹤畛鯖](méi)有拋出異常的功能。

一方面,JavaScript有很多怪癖,并且缺失很多功能(塊級(jí)變量作用域(block-sciped variables),模塊(modules)支持子類(lèi)型(subtyping)等)。另一方面,它有幾個(gè)非常強(qiáng)大的特性,允許你彌補(bǔ)上面的問(wèn)題。在其他語(yǔ)言中,你要學(xué)習(xí)語(yǔ)言特性。在JavaScript中,你需要經(jīng)常學(xué)習(xí)模式代替。

深入閱讀(Further reading)

語(yǔ)法(Syntax)

這節(jié)介紹一些JavaScript的基本語(yǔ)法規(guī)則。

語(yǔ)句和表達(dá)式(Statements versus expressions)

了解JavaScript的語(yǔ)法,先來(lái)了解兩個(gè)主要的語(yǔ)法類(lèi)型:語(yǔ)句和表達(dá)式。

  • 語(yǔ)句通?!白瞿承┦虑椤薄3绦蚴且唤M語(yǔ)句序列。舉個(gè)例子,下面聲明(創(chuàng)建)一個(gè)變量 foo: var foo;

  • 表達(dá)式產(chǎn)生值。他們通常位于賦值操作的右邊,函數(shù)參數(shù),等。舉個(gè)例子: 3 * 7

語(yǔ)句和表達(dá)式之間的區(qū)別最好通過(guò)實(shí)例說(shuō)明,JavaScript(像Java)有兩種不同的方式實(shí)現(xiàn)if-then-else。一種是用語(yǔ)句:

var x;if (y >= 0) {    x = y;} else {    x = -y;}

另一種是表達(dá)式:

var x = y >= 0 ? y : -y;

你可以將后者作為函數(shù)參數(shù)(但前者不行):

myFunction(y >= 0 ? y : -y)

最后,每當(dāng)JavaScript期待一個(gè)語(yǔ)句,你也可以用一個(gè)表達(dá)式代替。例如:

foo(bar(7, 1));

foo(...);是一個(gè)語(yǔ)句(也叫做表達(dá)式語(yǔ)句),bar(7, 1)是一個(gè)表達(dá)式。他們都實(shí)現(xiàn)函數(shù)調(diào)用。

流程控制語(yǔ)句和語(yǔ)句塊(Control flow statements and blocks)

流程控制語(yǔ)句,其語(yǔ)句體可以是單條語(yǔ)句。舉兩個(gè)例子:

if (obj !== null) obj.foo();while (x > 0) x--;

然而,任何語(yǔ)句總能被語(yǔ)句塊代替,花括號(hào)包含零或多條語(yǔ)句。因此,你也可以這樣寫(xiě):

if (obj !== null) {    obj.foo();}while (x > 0) {    x--;}

在本文中,我們只使用后一種方式。

分號(hào)(Semicolons)

JavaScript中的分號(hào)是可選的。但省略(分號(hào))可能會(huì)帶來(lái)意想不到的結(jié)果,所以我建議你不要那樣做。

正如上面所看到的,分號(hào)作為語(yǔ)句的結(jié)尾,但語(yǔ)句塊不需要。僅有一種情況下你能看到語(yǔ)句塊后面有分號(hào)——函數(shù)表達(dá)式后面的函數(shù)體塊。表達(dá)式作為語(yǔ)句的結(jié)尾,后面是分號(hào):

var x = 3 * 7;var f = function () { };

注釋?zhuān)–omments)

JavaScript的注釋有兩種形式:?jiǎn)涡凶⑨尯投嘈凶⑨尅涡凶⑨屢?/開(kāi)頭,以換行符結(jié)尾:

x  ; // 單行(single-line)注釋

多行注釋用/**/包裹

/*  這是多行注釋 多行哦 */

深入閱讀

變量和賦值(Variables and assignment)

JavaScript中的變量在使用前必須先聲明,否則會(huì)報(bào)錯(cuò)引用錯(cuò)誤(Reference Error):

var foo;  // 聲明變量“foo”

賦值(Assignment)

你可以在聲明變量的同時(shí)為其賦值:

var foo = 6;

你也可以給已經(jīng)存在的變量重新賦值:

foo = 4;  // 更改變量的值

復(fù)合賦值操作符(Compount assignment operators)

有很多復(fù)合賦值操作符,例如 =。下面的兩個(gè)賦值操作等價(jià):

x  = 1;x = x   1;

標(biāo)識(shí)符和變量名(Identifiers and variable names)

標(biāo)識(shí)符就是事物的名字,在JavaScript中他們扮演不同的語(yǔ)法角色。例如,變量的名稱(chēng)是一個(gè)標(biāo)識(shí)符。

大體上,標(biāo)識(shí)符的第一個(gè)字符可以是任何Unicode字符、美元標(biāo)志符($)或下劃線(_)。后面可以是任意字符和數(shù)字。因此,下面全是合法的標(biāo)識(shí)符:

arg0_tmp$elemπ

注意:首字符不能是數(shù)字,如果是數(shù)字的話,該如何區(qū)分是數(shù)字還是變量呢?

一些標(biāo)識(shí)符是“保留關(guān)鍵字”——他們是語(yǔ)法的一部分,不能用作變量名:

arguments break case catch class const continue debugger default delete do else enum eval export extends false finally for function if implements import in instanceof interface let new null package private protected public return static super switch this throw true try typeof var void while with yield

從技術(shù)上講,下面三個(gè)標(biāo)識(shí)符不是保留字,但也不應(yīng)該作為變量名:

Infinity NaN undefined

深入閱讀

值(Values)

JavaScript有所有我們期待的編程語(yǔ)言值類(lèi)型:布爾,數(shù)字,字符串,數(shù)組等。JavaScript中的所有值都有屬性。每個(gè)屬性有一個(gè)鍵(或名字)和一個(gè)值。參考記錄的域(fields of record)。你可以使用點(diǎn)(.)操作符讀取屬性:

value.propKey

舉個(gè)例子:字符串“abc”有屬性lenght(長(zhǎng)度)。

 > var str = 'abc'; > str.length   3

上面的代碼也可以寫(xiě)成下面這樣:

> 'abc'.length  3

點(diǎn)操作符也可以用來(lái)給屬性賦值:

 > var obj = {};  // 空對(duì)象 > obj.foo = 123; // 創(chuàng)建屬性“foo”,設(shè)置它為123   123 > obj.foo   123

你也可以通過(guò)它(.)調(diào)用方法:

> 'hello'.toUpperCase()  'HELLO'

上面,我們?cè)谥怠癶ello”上面調(diào)用方法 toUpperCase()。

原始類(lèi)型值和對(duì)象(Primitive values versus objects)

JavaScript定義了不同值之間的區(qū)別:

  • 原始值包括:boolean,number,string,null和undefined,
  • 所有其他的值都是對(duì)象。實(shí)際上對(duì)象被定義為——所有不為原始值的值。

兩者之間的主要區(qū)別在于他們是如何被比較的:每一個(gè)對(duì)象有一個(gè)獨(dú)一無(wú)二的標(biāo)志,并且僅和自己相等:

> var obj1 = {};  // 一個(gè)空對(duì)象> var obj2 = {};  // 另一個(gè)空對(duì)象> obj1 === obj2  false> obj1 === obj1  true

相反,所有原始值只要編碼值相同就被認(rèn)為是相同的:

> var prim1 = 123;> var prim2 = 123;> prim1 === prim2  true

接下來(lái)的兩節(jié)會(huì)介紹原始值和對(duì)象的更多細(xì)節(jié)。

原始類(lèi)型值(Primitive values)

下面全是原始類(lèi)型值(簡(jiǎn)稱(chēng):原始值):

原始值的特征:

  • 值做比較時(shí):“內(nèi)容”做比較。

      > 3 === 3    true  > 'abc' === 'abc'    true
  • 無(wú)法更改:值的屬性無(wú)法更改,無(wú)法添加和移除屬性。

      > var str = 'abc';  > str.foo = 3; // try to create property `foo` ? no effect  > str.foo  // unknown property    undefined 

    (獲取未知屬性總返回undefined)

  • 原始值的集合是固定的(fixed set of values):你不能自定義原始值。

對(duì)象(Objects)

所有非原始值(non-primitive)的值都是對(duì)象。最常見(jiàn)的幾種對(duì)象類(lèi)型是:

  • 簡(jiǎn)單對(duì)象(類(lèi)型是Object)能通過(guò)對(duì)象字面量創(chuàng)建:

    { firstName: ‘Jane’, lastName: ‘Doe’ }

    上面的對(duì)象有兩個(gè)屬性:firstName屬性的值是“Jane”,lastName屬性的值是“Doe”。

  • 數(shù)組(類(lèi)型是 Array)能通過(guò)數(shù)組字面量創(chuàng)建:

    [ ‘a(chǎn)pple’, ‘banana’, ‘cherry’ ]

    上面的數(shù)組有三個(gè)元素,可以通過(guò)數(shù)字索引訪問(wèn)。例如“apple”的索引是0.

  • 正則表達(dá)式對(duì)象(類(lèi)型是 RegExp)能通過(guò)正則表達(dá)式字面量創(chuàng)建。

    /^a b $/

對(duì)象的特征:

  • 比較的是引用:比較的是標(biāo)識(shí)符,每個(gè)值有自己的標(biāo)識(shí)符。

      > {} === {}  // 兩個(gè)不同的空對(duì)象    false	  > var obj1 = {};  > var obj2 = obj1;  > obj1 === obj2    true
  • 默認(rèn)可以更改。

       > var obj = {};   > obj.foo = 123;   > obj.foo     123

-** 用戶可擴(kuò)展(user-extensible):**你可以通過(guò)構(gòu)造函數(shù)定義新的對(duì)象類(lèi)型。

所有的數(shù)據(jù)結(jié)構(gòu)(如數(shù)組)都是對(duì)象,但并不是所有的對(duì)象都是數(shù)據(jù)結(jié)構(gòu)。例如:正則表達(dá)式是對(duì)象,但不是數(shù)據(jù)結(jié)構(gòu)。

undefined 和 null(undefined and null)

多少有些不必要,JavaScript有兩個(gè)“無(wú)值(non-values)”:undefined 和 null。

  • undefined的意思是“沒(méi)有值(no value)”。未初始化的變量是undefined:

      > var foo;  > foo  undefined

    讀取不存在的屬性時(shí),將返回undefined:

      > var obj = {}; // 空對(duì)象  > obj.foo    undefined

    缺省的參數(shù)也是undefined:

      > function f(x) { return x }  > f()    undefined
  • null的意思是“沒(méi)有對(duì)象(no object)”。它被用來(lái)表示對(duì)象的無(wú)值(參數(shù),鏈上的對(duì)象等)。

通常情況下你應(yīng)該把undefined和null看成是等價(jià)的,如果他們代表相同意義的無(wú)值的話。檢查他們的一種方式是通過(guò)嚴(yán)格比較:

if (x === undefined || x === null) {    ...}

另一種在實(shí)際中使用的方法是認(rèn)為undefined 和 null 都是false

if (!x) {    ...}

警告:false,0,NaN 和 “” 都被當(dāng)作false。

包裝類(lèi)型(Wrapper types)

對(duì)象類(lèi)型的實(shí)例Foo(包括內(nèi)建類(lèi)型,例如Array和其他自定義類(lèi)型)從對(duì)象Foo.prototype上獲取方法。你可以通過(guò)讀取這個(gè)方法的方式(不是調(diào)用)驗(yàn)證這點(diǎn):

> [].push === Array.prototype.push  true

相反,原始類(lèi)型是沒(méi)有類(lèi)型的,所以每個(gè)原始類(lèi)型有一個(gè)關(guān)聯(lián)類(lèi)型,稱(chēng)之為包裝類(lèi)型:

  • 布爾值的包裝類(lèi)型是 Boolean。布爾值從Boolean.prototype上獲取方法:

      > true.toString === Boolean.prototype.toString	true

    注意包裝類(lèi)型名字的首字母是大寫(xiě)的B。如果在JavaScript中布爾值的類(lèi)型可以訪問(wèn),那么它可能會(huì)被轉(zhuǎn)換為布爾對(duì)象。

  • 數(shù)字值的包裝類(lèi)型是Number。
  • 字符串值的包裝類(lèi)型是String。

包裝類(lèi)型也有實(shí)例(他們的實(shí)例是對(duì)象),但不常用。相反,包裝類(lèi)型有其他用處:如果你將他們作為函數(shù)調(diào)用,他們可以將值轉(zhuǎn)換為原始類(lèi)型。

> Number('123')  123> String(true)  'true'

通過(guò)typeof 和 instanceof 將值分類(lèi)(Categorizing values via typeof and instanceof)

有兩個(gè)操作符可以用來(lái)將值分類(lèi):typeof 主要用于原始值,instanceof 主要用于對(duì)象。

typeof 使用方法如下:

typeof ?value?

typeof返回描述 value “類(lèi)型”的一個(gè)字符串。例如:

> typeof true  'boolean'> typeof 'abc'  'string'> typeof {} // 空對(duì)象字面量  'object'> typeof [] // 空數(shù)組字面量  'object'

下面列出了typeof操作的所有結(jié)果:

操作數(shù)結(jié)果
undefined'undefined'
null'object'
Boolean value'boolean'
Number value'number'
String value'string'
Function'function'
All other values'object'

有兩個(gè)結(jié)果和我們上面說(shuō)的的原始值與對(duì)象是矛盾的:

  • 函數(shù)的類(lèi)型是“function”而不是“object”。鑒于函數(shù)(類(lèi)型為“function”)是對(duì)象(類(lèi)型是對(duì)象)的子類(lèi)型,這不是一個(gè)錯(cuò)誤。
  • null的類(lèi)型是“object”。這是一個(gè)bug,但從沒(méi)被修復(fù),因?yàn)樾迯?fù)后會(huì)破壞現(xiàn)有的代碼。

instanceof使用方法如下:

value? instanceof ?Constr?

如果 value 是一個(gè)對(duì)象,并且value 是由構(gòu)造函數(shù)Constr創(chuàng)建的(參考:類(lèi))。例如:

> var b = new Bar();  // 通過(guò)構(gòu)造函數(shù)Bar創(chuàng)建對(duì)象> b instanceof Bar  true> {} instanceof Object  true> [] instanceof Array  true> [] instanceof Object  // 數(shù)字是對(duì)象的子類(lèi)型  true

深入閱讀

布爾(Booleans)

布爾類(lèi)型原始值包括true和false。下面的操作符產(chǎn)生布爾值:

  • 二元邏輯運(yùn)算符:&&(與),   (或)
  • 前綴邏輯運(yùn)算符:!(非)
  • 等值運(yùn)算符:=== !== == !=
  • 比較運(yùn)算符(字符串或數(shù)字):> >= < <=

真值和假值(Truthy and falsy)

每當(dāng)JavaScript希望一個(gè)布爾值時(shí)(例如:if語(yǔ)句的條件),可以使用任何值。它將被理解(轉(zhuǎn)換)為true或false。下面的值被理解為false:

  • undefined, null
  • 布爾: false
  • 數(shù)字: -0, NaN
  • 字符串: ‘’

所有其他值被認(rèn)為true。被理解為false的值稱(chēng)為假值(falsy),被理解為true的值稱(chēng)為真值(truthy)??梢允褂肂oolean作為函數(shù),測(cè)試值被理解為什么。

> Boolean(undefined)  false> Boolean(0)  false> Boolean(3)  true

二元邏輯運(yùn)算符(Binary logical operators)

JavaScript中的二元邏輯運(yùn)算符是短路運(yùn)算——如果第一個(gè)操作數(shù)可以確定結(jié)果,第二個(gè)操作數(shù)將不被驗(yàn)證(運(yùn)算)。例如,在下面的代碼中,函數(shù)foo()永遠(yuǎn)不會(huì)被調(diào)用。

false && foo()true  || foo()

此外,二元邏輯運(yùn)算符會(huì)返回操作數(shù)中的一個(gè)——可能是一個(gè)布爾值,也可能不是。一張真值表用來(lái)決定返回哪個(gè)值:

  • 與:如果第一個(gè)操作數(shù)是假值,返回第一個(gè)。否則返回第二個(gè)操作數(shù)。

      > NaN && 'abc'    NaN  > 123 && 'abc'    'abc'
  • 或:如果第一個(gè)操作數(shù)是真值,返回第一個(gè)。否則,返回第二個(gè)操作數(shù)。

      > 'abc' || 123    'abc'  > '' || 123    123

等值運(yùn)算符(Equality operators)

在JavaScript中檢測(cè)相等,你可以使用嚴(yán)格相等(===)和嚴(yán)格不等(!==)。或者你也可以使用非嚴(yán)格相等(==)和非嚴(yán)格不等(!=)。經(jīng)驗(yàn)規(guī)則:總是用嚴(yán)格運(yùn)算符,假裝非嚴(yán)格運(yùn)算符不存在。嚴(yán)格相等更安全。

深入閱讀

數(shù)字(Numbers)

JavaScript中的所有數(shù)字都是浮點(diǎn)型(雖然大部分的JavaScript引擎內(nèi)部也使用整數(shù))。至于為什么這樣設(shè)計(jì),查看這里(每一個(gè)JavaScript開(kāi)發(fā)者應(yīng)該了解的浮點(diǎn)知識(shí))。

> 1 === 1.0  true

特殊數(shù)字:

  • NaN (“不是一個(gè)數(shù)字 not a number”): 錯(cuò)誤值。

      > Number('xyz')  // 'xyz' 不能被轉(zhuǎn)換為數(shù)字    NaN
  • Infinity:也是最大錯(cuò)誤值(溢出).

      > 3 / 0    Infinity  > Math.pow(2, 1024)  // 數(shù)字太大了    Infinity

    Infinity 有時(shí)很有用,因?yàn)樗热魏纹渌麛?shù)字都大。同樣,-Infinity 比其他任何數(shù)字都小。

  • JavaScript有兩個(gè)零, 0 和 -0。它(js引擎)通常不讓你看到,并簡(jiǎn)單將兩個(gè)零都顯示為0:

      >  0    0  > -0    0

    因此最好假裝只有一個(gè)零(正如我們看到假值時(shí)所做的那樣:-0 和 0 都是假值)。

運(yùn)算符(Operators)

JavaScript中有下列算數(shù)運(yùn)算符

  • 加: number1 number2
  • 減: number1 - number2
  • 乘: number1 * number2
  • 除: number1 / number2
  • 模: number1 % number2
  • 自增: variable, variable
  • 自減: –variable, variable–
  • 負(fù)值: -value
  • 正值(轉(zhuǎn)換為數(shù)字): value

全局對(duì)象Math通過(guò)函數(shù)提供更多算數(shù)運(yùn)算操作。

JavaScript中也有位運(yùn)算符(例如:位與 &)。

深入閱讀

在2ality有一系列博文介紹這些內(nèi)容,例如:

字符串(Strings)

字符串可以直接通過(guò)字符串字面量創(chuàng)建。這些字面量被單引號(hào)或雙引號(hào)包裹。反斜線(\)轉(zhuǎn)義字符并且產(chǎn)生一些控制字符。例如:

'abc''abc''Did she say 'Hello'?''Did she say \'Hello\'?''That\'s nice!''That's nice!''Line 1\nLine 2'  // 換行'Backlash: \\'

可以通過(guò)方括號(hào)訪問(wèn)單個(gè)字符:

> var str = 'abc';> str[1]  'b'

length屬性是字符串的字符數(shù)量。

> 'abc'.length  3

提醒:字符串是不可變的,如果你想改變現(xiàn)有字符串,你需要?jiǎng)?chuàng)建一個(gè)新的字符串。

字符串運(yùn)算符(String operators)

字符串可以通過(guò)加號(hào)操作符( )拼接,如果其中一個(gè)操作數(shù)為字符串,會(huì)將另一個(gè)操作數(shù)也轉(zhuǎn)換為字符串。

> var messageCount = 3;> 'You have ' messageCount ' messages'  'You have 3 messages'

連續(xù)執(zhí)行拼接操作可以使用 = 操作符:

> var str = '';> str  = 'Multiple ';> str  = 'pieces ';> str  = 'are concatenated.';> str  'Multiple pieces are concatenated.'

字符串方法(String methods)

字符串有許多有用的

深入閱讀

語(yǔ)句(Statements)

條件(Conditionals)

if語(yǔ)句通過(guò)布爾條件決定執(zhí)行那個(gè)分支:

if (myvar === 0) {    // then}if (myvar === 0) {    // then} else {    // else}if (myvar === 0) {    // then} else if (myvar === 1) {    // else-if} else if (myvar === 2) {    // else-if} else {    // else}

下面的switch語(yǔ)句,furit的值決定那個(gè)分支被執(zhí)行。

switch (fruit) {    case 'banana':        // ...        break;    case 'apple':        // ...        break;    default:  // 所有其他情況        // ...}

循環(huán)(Loops)

for 循環(huán)的格式如下:

for(初始化; 當(dāng)條件成立時(shí)循環(huán); 下一步操作)

例子:

for (var i=0; i < arr.length; i  ) {    console.log(arr[i]);}

當(dāng)條件成立時(shí)while循環(huán)繼續(xù)循環(huán)它的循環(huán)體。

// 和上面的for循環(huán)相等var i = 0;while (i < arr.length) {    console.log(arr[i]);    i  ;}

當(dāng)條件成立時(shí),do-while循環(huán)繼續(xù)循環(huán)。由于條件位于循環(huán)體之后,所以循環(huán)體總是被至少至少執(zhí)行一次。

do {    // ...} while(條件);

在所有的循環(huán)中:

  • break中斷循環(huán)
  • continue開(kāi)始一個(gè)新的循環(huán)迭代

函數(shù)(Functions)

定義函數(shù)的一種方法是通過(guò)函數(shù)聲明:

function add(param1, param2) {    return param1   param2;}

上面的代碼定義一個(gè)名稱(chēng)叫做add的函數(shù),有兩個(gè)參數(shù)param1和param2,并且返回參數(shù)的和。下面是如何調(diào)用這個(gè)函數(shù):

> add(6, 1)  7> add('a', 'b')  'ab'

另一種定義add()函數(shù)的方法是通過(guò)函數(shù)表達(dá)式:

var add = function (param1, param2) {    return param1   param2;};

函數(shù)表達(dá)式產(chǎn)生一個(gè)值,因此可以直接將函數(shù)作為參數(shù)傳遞給其他函數(shù):

someOtherFunction(function (p1, p2) { ... });

函數(shù)聲明提升(Function declarations are hoisted)

函數(shù)聲明會(huì)被提升,他們?nèi)灰苿?dòng)到當(dāng)前作用域開(kāi)始之處。這允許你在函數(shù)聲明之前調(diào)用它們:

function foo() {    bar();  // 沒(méi)問(wèn)題,bar被提升    function bar() {        ...    }}

注意:雖然變量聲明也會(huì)被提升,但賦值的過(guò)程不會(huì)被提升:

function foo() {    bar();  // 有問(wèn)題,bar是undefined    var bar = function () {        // ...    };}

特殊變量arguments(The special variable arguments)

在JavaScript中你可以調(diào)用任意函數(shù)并傳遞任意數(shù)量的參數(shù)——語(yǔ)言絕不會(huì)抱怨(參數(shù)檢測(cè))。都可以正常工作,然而,使所有參數(shù)可訪問(wèn)需要通過(guò)特殊變量 arguments。arguments 看起來(lái)像數(shù)組,但它沒(méi)有數(shù)組的方法(稱(chēng)為類(lèi)數(shù)組 array-like)。

> function f() { return arguments }> var args = f('a', 'b', 'c');> args.length3> args[0]  // 獲取索引為0的元素'a'

太多或太少參數(shù)(Too many or too few arguments)

讓我們通過(guò)下面的函數(shù)探索JavaScript中傳遞太多或太少參數(shù)時(shí)如何處理(函數(shù) toArray在后面提到

function f(x, y) {    console.log(x, y);    console.log(toArray(arguments));}

多出的參數(shù)將被忽略(可以通過(guò)arguments訪問(wèn)):

> f('a', 'b', 'c')a b[ 'a', 'b', 'c' ]

缺少的參數(shù)將會(huì)是undefined:

> f('a')a undefined[ 'a' ]> f()undefined undefined[]

可選參數(shù)(Optional parameters)

下面是一個(gè)常見(jiàn)模式,給參數(shù)設(shè)置默認(rèn)值:

function pair(x, y) {    x = x || 0;  // (*)    y = y || 0;    return [ x, y ];}
在(*)這行,如果x是真值(除了:null,undefined 等),   操作符返回x。否則,它返回第二個(gè)操作數(shù)。
> pair()[ 0, 0 ]> pair(3)[ 3, 0 ]> pair(3, 5)[ 3, 5 ] 

強(qiáng)制數(shù)量(Enforcing an arity)

如果你想強(qiáng)制參數(shù)的數(shù)量,你可以檢測(cè)arguments.length:

function pair(x, y) {    if (arguments.length !== 2) {        throw new Error('Need exactly 2 arguments');    }    ...}

將arguments 轉(zhuǎn)換為數(shù)組(Converting arguments to an array)

arguments 不是一個(gè)數(shù)組,它僅僅是類(lèi)數(shù)組(array-like):它有一個(gè)length屬性,并且你可以通過(guò)方括號(hào)索引方式訪問(wèn)它的元素。然而,你不能移除元素,或在它上面調(diào)用任何數(shù)組方法。因此,有時(shí)你需要將其轉(zhuǎn)換為數(shù)組。這就是下面函數(shù)的作用。

function toArray(arrayLikeObject) {    return [].slice.call(arrayLikeObject);}

深入閱讀

異常處理(Exception handling)

異常處理最常見(jiàn)的方式像下面這樣:

function throwException() {    throw new Error('Problem!');}try {    throwException();} catch (e) {    console.log(e);  // 錯(cuò)誤:信息    console.log(e.stack);  // 非標(biāo)準(zhǔn),但大部分瀏覽器支持}

try分支包裹易出錯(cuò)的代碼,如果try分支內(nèi)部拋出異常,catch分支將會(huì)執(zhí)行。

深入閱讀

嚴(yán)格模式(Strict mode)

你也可以在每個(gè)函數(shù)上選擇性開(kāi)啟嚴(yán)格模式,只需將上面的代碼放在函數(shù)的開(kāi)頭:

function functionInStrictMode() {    'use strict';}

下面的兩小節(jié)看下嚴(yán)格模式的三大好處。

明確錯(cuò)誤(Explicit errors)

讓我們看一個(gè)例子,嚴(yán)格模式給我們明確的錯(cuò)誤,否則JavaScript總是靜默失敗:下面的函數(shù) f() 執(zhí)行一些非法操作,它試圖更改所有字符串都有的只讀屬性——length:

function f() {    'abc'.length = 5;}

當(dāng)你調(diào)用上面的函數(shù),它靜默失敗,賦值操作被簡(jiǎn)單忽略。讓我們將 f() 在嚴(yán)格模式下運(yùn)行:

function f_strict() {    'use strict';    'abc'.length = 5;}

現(xiàn)在瀏覽器報(bào)給我們一些錯(cuò)誤:

> f_strict()TypeError: Cannot assign to read only property 'length' of abc

不是方法的函數(shù)中的this(this in non-method functions)

在嚴(yán)格模式下,不作為方法的函數(shù)中的this值是undefined:

function f_strict() {    'use strict';    return this;}console.log(f_strict() === undefined);  // true

在非嚴(yán)格模式下,this的值是被稱(chēng)作全局對(duì)象(global object)(在瀏覽器里是window):

function f() {    return this;}console.log(f() === window);  // true

不再自動(dòng)創(chuàng)建全局變量(No auto-created global variables)

在非嚴(yán)格模式下,如果你給不存在的變量賦值,JavaScript會(huì)自動(dòng)創(chuàng)建一個(gè)全局變量:

> function f() { foo = 5 }> f()  // 不會(huì)報(bào)錯(cuò)> foo5

在嚴(yán)格模式下,這會(huì)產(chǎn)生一個(gè)錯(cuò)誤:

> function f_strict() { 'use strict'; foo2 = 4; }> f_strict()ReferenceError: foo2 is not defined

深入閱讀

變量作用域和閉包(Variable scoping and closures)

在JavaScript中,你必須使用變量之前,通過(guò)var聲明變量:

> var x;> x = 3;> y = 4;ReferenceError: y is not defined

你可以用一條var語(yǔ)句聲明和初始化多個(gè)變量:

var x = 1, y = 2, z = 3;

但我建議每個(gè)變量使用一條語(yǔ)句。因此,我將上面的語(yǔ)句重寫(xiě)為:

var x = 1;var y = 2;var z = 3;

由于提升(見(jiàn)下文),最好在函數(shù)頂部聲明變量。

變量和函數(shù)作用域(Variables are function-scoped)

變量的作用域總是整個(gè)函數(shù)(沒(méi)有塊級(jí)作用域)。例如:

function foo() {    var x = -3;    if (x < 0) {  // (*)        var tmp = -x;        ...    }    console.log(tmp);  // 3}

我們可以看到tmp變量不僅在(*)所在行的語(yǔ)句塊存在,它在整個(gè)函數(shù)內(nèi)都存在。

變量提升(Variables are hoisted)

變量聲明會(huì)被提升:聲明會(huì)被移到函數(shù)的頂部,但賦值過(guò)程不會(huì)。舉個(gè)例子,在下面的函數(shù)中(*)行位置聲明了一個(gè)變量。

function foo() {    console.log(tmp); // undefined    if (false) {        var tmp = 3;  // (*)    }}

在內(nèi)部,上面的函數(shù)被執(zhí)行像下面這樣:

function foo() {    var tmp;  // declaration is hoisted    console.log(tmp);    if (false) {        tmp = 3;  // assignment stays put    }}

閉包(Closures)

每個(gè)函數(shù)保持和函數(shù)體內(nèi)部變量的連接,甚至離開(kāi)創(chuàng)建它的作用域之后。例如:

function createIncrementor(start) {    return function () {  // (*)        return start  ;    }}

在(*)行開(kāi)始的函數(shù)在它創(chuàng)建時(shí)保留上下文,并在內(nèi)部保存一個(gè)start活動(dòng)值:

> var inc = createIncrementor(5);> inc()5> inc()6> inc()7

閉包是一個(gè)函數(shù)加上和其作用域鏈的鏈接。因此,createIncrementor() 返回的是一個(gè)閉包。

IIFE:模擬塊級(jí)作用域(IIFE: Simulating block scoping)

有時(shí)你想模擬一個(gè)塊,例如你想將變量從全局作用域隔離。完成這個(gè)工作的模式叫做 IIFE(立即執(zhí)行函數(shù)表達(dá)式(Immediately Invoked Function Expression)):

(function () {  // 塊開(kāi)始    var tmp = ...;  // 非全局變量}());  // 塊結(jié)束

上面你會(huì)看到函數(shù)表達(dá)式被立即執(zhí)行。外面的括號(hào)用來(lái)阻止它被解析成函數(shù)聲明;只有函數(shù)表達(dá)式能被立即調(diào)用。函數(shù)體產(chǎn)生一個(gè)新的作用域并使 tmp 變?yōu)榫植孔兞俊?/p>

閉包實(shí)現(xiàn)變量共享(Inadvertent sharing via closures)

下面是個(gè)經(jīng)典問(wèn)題,如果你不知道,會(huì)讓你費(fèi)盡思量。因此,先瀏覽下,對(duì)問(wèn)題有個(gè)大概的了解。

閉包保持和外部變量的連接,有時(shí)可能和你想像的行為不一致:

var result = [];for (var i=0; i < 5; i  ) {    result.push(function () { return i });  // (*)}console.log(result[1]()); // 5 (不是 1)console.log(result[3]()); // 5 (不是 3)

(*)行的返回值總是當(dāng)前的i值,而不是當(dāng)函數(shù)被創(chuàng)建時(shí)的i值。當(dāng)循環(huán)結(jié)束后,i的值是5,這是為什么數(shù)組中的所有函數(shù)的返回值總是一樣的。如果你想捕獲當(dāng)前變量的快照,你可以使用 IIFE:

for (var i=0; i < 5; i  ) {    (function (i2) {        result.push(function () { return i2 });    }(i));  // 復(fù)制當(dāng)前的i}

深入閱讀

對(duì)象和繼承(Objects and inheritance)

和所有的值類(lèi)型一樣,對(duì)象有屬性。事實(shí)上,你可以將對(duì)象當(dāng)作一組屬性的集合,每個(gè)屬性都是一對(duì)(鍵和值)。鍵是字符串,值可以是任意JavaScript值。到目前為止,我們僅僅見(jiàn)過(guò)鍵是標(biāo)識(shí)符的屬性,因?yàn)辄c(diǎn)操作符處理的鍵必須為標(biāo)識(shí)符。在這節(jié),你講見(jiàn)到另一種訪問(wèn)屬性的方法,能將任意字符串作為鍵。

單個(gè)對(duì)象(Single objects)

在JavaScript中,你可以直接創(chuàng)建對(duì)象,通過(guò)對(duì)象字面量:

var jane = {    name: 'Jane',    describe: function () {        'use strict';        return 'Person named ' this.name;    }};

上面的對(duì)象有兩個(gè)屬性:name 和 describe。你能讀(“get”)和 寫(xiě)(“set”)屬性:

> jane.name  // get'Jane'> jane.name = 'John';  // set> jane.newProperty = 'abc';  // 自動(dòng)創(chuàng)建

屬性是函數(shù)如 describe 可以被當(dāng)作方法調(diào)用。當(dāng)調(diào)用他們時(shí)可以在它們內(nèi)部通過(guò)this引用對(duì)象。

> jane.describe()  // 調(diào)用方法'Person named John'> jane.name = 'Jane';> jane.describe()'Person named Jane'

in 操作符用來(lái)檢測(cè)一個(gè)屬性是否存在:

> 'newProperty' in janetrue> 'foo' in janefalse

若讀取一個(gè)不存在的屬性,將會(huì)得到undefined值。因此上面的兩個(gè)檢查也可以像下面這樣:

> jane.newProperty !== undefinedtrue> jane.foo !== undefinedfalse

delete操作符用來(lái)刪除一個(gè)屬性:

> delete jane.newPropertytrue> 'newProperty' in janefalse

任意鍵屬性(Arbitrary property keys)

屬性的鍵可以是任意字符串。到目前為止,我們看到的對(duì)象字面量中的和點(diǎn)操作符后的屬性關(guān)鍵字。按這種方法你只能使用標(biāo)識(shí)符。如果你想用其他任意字符串作為鍵名,你必須在對(duì)象字面量里加上引號(hào),并使用方括號(hào)獲取和設(shè)置屬性。

> var obj = { 'not an identifier': 123 };> obj['not an identifier']123> obj['not an identifier'] = 456;

方括號(hào)允許你動(dòng)態(tài)計(jì)算屬性關(guān)鍵字:

> var x = 'name';> jane[x]'Jane'> jane['na' 'me']'Jane'

引用方法(Extracting methods)

如果你引用一個(gè)方法,它將失去和對(duì)象的連接。就其本身而言,函數(shù)不是方法,其中的this值為undefined(嚴(yán)格模式下)。

> var func = jane.describe;> func()TypeError: Cannot read property 'name' of undefined

解決辦法是使用函數(shù)內(nèi)置的bind()方法。它創(chuàng)建一個(gè)新函數(shù),其this值固定為給定的值。

> var func2 = jane.describe.bind(jane);> func2()'Person named Jane'

方法內(nèi)部的函數(shù)(Functions inside a method)

每個(gè)函數(shù)都有一個(gè)特殊變量this。如果你在方法內(nèi)部嵌入函數(shù)是很不方便的,因?yàn)槟悴荒軓暮瘮?shù)中訪問(wèn)方法的this。下面是一個(gè)例子,我們調(diào)用forEach循環(huán)一個(gè)數(shù)組:

var jane = {    name: 'Jane',    friends: [ 'Tarzan', 'Cheeta' ],    logHiToFriends: function () {        'use strict';        this.friends.forEach(function (friend) {            // 這里的“this”是undefined            console.log(this.name ' says hi to ' friend);        });    }}

調(diào)用 logHiToFriends 會(huì)產(chǎn)生錯(cuò)誤:

> jane.logHiToFriends()TypeError: Cannot read property 'name' of undefined

有兩種方法修復(fù)這問(wèn)題。

#1:將this存儲(chǔ)在不同的變量。

logHiToFriends: function () {    'use strict';    var that = this;    this.friends.forEach(function (friend) {        console.log(that.name ' says hi to ' friend);    });}

#2:forEach的第二個(gè)參數(shù)允許提供this值。

logHiToFriends: function () {    'use strict';    this.friends.forEach(function (friend) {        console.log(this.name ' says hi to ' friend);    }, this);}

在JavaScript中函數(shù)表達(dá)式經(jīng)常被用作函數(shù)參數(shù)。時(shí)刻小心函數(shù)表達(dá)式中的this。

構(gòu)造函數(shù):對(duì)象工廠(Constructors: factories for objects)

目前為止,你可能認(rèn)為JavaScript的對(duì)象僅是鍵值的映射,通過(guò)JavaScript對(duì)象字面量可以得出這個(gè)觀點(diǎn),看起來(lái)很像其他語(yǔ)言中的地圖/字典(map/dictionary)。然而,JavaScript對(duì)象也支持真正意義上的面向?qū)ο筇匦裕豪^承(inheritance)。本節(jié)不會(huì)完全講解JavaScript中繼承的工作原理,但會(huì)給你以此為開(kāi)始的簡(jiǎn)單模式。如果你想得到更多知識(shí),請(qǐng)查閱這篇文章“JavaScript inheritance by example”。

除了作為“真正”的函數(shù)和方法,函數(shù)還在JavaScript中扮演第三種角色:如果通過(guò)new操作符調(diào)用,他們會(huì)變?yōu)闃?gòu)造函數(shù),對(duì)象的工廠。構(gòu)造函數(shù)是對(duì)其他語(yǔ)言中的類(lèi)的粗略模擬。約定俗成,構(gòu)造函數(shù)的第一個(gè)字母大寫(xiě)。例如:

// 設(shè)置實(shí)例數(shù)據(jù)function Point(x, y) {    this.x = x;    this.y = y;}// 方法Point.prototype.dist = function () {    return Math.sqrt(this.x*this.x   this.y*this.y);};

我們看到構(gòu)造函數(shù)分為兩部分:首先,Point函數(shù)設(shè)置實(shí)例數(shù)據(jù)。其次,Point.prototype屬性包含對(duì)象的方法。前者的數(shù)據(jù)是每個(gè)實(shí)例私有的,后面的數(shù)據(jù)是所有實(shí)例共享的。

我們通過(guò)new操作符調(diào)用Point:

> var p = new Point(3, 5);> p.x3> p.dist()5.830951894845301

p是Point的一個(gè)實(shí)例:

> p instanceof Pointtrue> typeof p'object'

深入閱讀

數(shù)組(Arrays)

數(shù)組是數(shù)組元素的序列,能通過(guò)整數(shù)索引方法數(shù)組元素,數(shù)組索引從0開(kāi)始。

數(shù)組字面量(Array literals)

數(shù)組字面量創(chuàng)建數(shù)組很方便:

> var arr = [ 'a', 'b', 'c' ];

上面的數(shù)組有三個(gè)元素:分別是字符串“a”,“b”, “c”。你可以通過(guò)整數(shù)索引訪問(wèn)它們:

> arr[0]'a'> arr[0] = 'x';> arr[ 'x', 'b', 'c' ]

length屬性總表示一個(gè)數(shù)組有多少項(xiàng)元素。

> arr.length3

除此之外它也可以用來(lái)從數(shù)組上移除尾部元素:

> arr.length = 2;> arr[ 'x', 'b' ]

in操作符也可以在數(shù)組上工作。

> 1 in arr // arr在索引為1處是否有元素?true> 5 in arr // arr在索引為5處是否有元素?false

值得注意的是數(shù)組是對(duì)象,因此可以有對(duì)象屬性:

> arr.foo = 123;> arr.foo123

數(shù)組方法(Array methods)

數(shù)組有許多方法。舉些例子:

> var arr = [ 'a', 'b', 'c' ];> arr.slice(1, 2)  // 復(fù)制元素[ 'b' ]> arr.slice(1)[ 'b', 'c' ]> arr.push('x')  // 在末尾添加一個(gè)元素4> arr[ 'a', 'b', 'c', 'x' ]> arr.pop()  // 移除最后一個(gè)元素'x'> arr[ 'a', 'b', 'c' ]> arr.shift()  // 移除第一個(gè)元素'a'> arr[ 'b', 'c' ]> arr.unshift('x')  // 在前面添加一個(gè)元素3> arr[ 'x', 'b', 'c' ]> arr.indexOf('b')  // 查找給定項(xiàng)在數(shù)組中的索引,若不存在返回-11> arr.indexOf('y') -1> arr.join('-')  // 將元素拼接為一個(gè)字符串'x-b-c'> arr.join('')'xbc'> arr.join()'x,b,c'

遍歷數(shù)組(Iterating over arrays)

有幾種方法可以遍歷數(shù)組元素。其中兩個(gè)最重要的是 forEach 和 map。

forEach遍歷整個(gè)數(shù)組,并將當(dāng)前元素和它的索引傳遞給一個(gè)函數(shù):

[ 'a', 'b', 'c' ].forEach(    function (elem, index) {  // (*)        console.log(index   '. '   elem);    });

上面代碼的輸出

0. a1. b2. c

注意(*)行的函數(shù)參數(shù)是可省略的。例如:它可以只有一個(gè)參數(shù) elem。

map創(chuàng)建一個(gè)新數(shù)組,通過(guò)給每個(gè)存在數(shù)組元素應(yīng)用一個(gè)函數(shù):

> [1,2,3].map(function (x) { return x*x })[ 1, 4, 9 ]

深入閱讀

正則表達(dá)式(Regular expressions)

JavaScript內(nèi)建支持正則表達(dá)式。他們被雙斜線分隔:

/^abc$//[A-Za-z0-9] /

方法 test():測(cè)試是否匹配(Method test(): is there a match?)

> /^a b $/.test('aaab')true> /^a b $/.test('aaa')false

方法 exec():匹配和捕獲組(Method exec(): match and capture groups)

> /a(b )a/.exec('_abbba_aba_')[ 'abbba', 'bbb' ]

返回的數(shù)組第一項(xiàng)(索引為0)是完整匹配,捕獲的第一個(gè)分組在第二項(xiàng)(索引為1),等。有一種方法可以反復(fù)調(diào)用獲取所有匹配。

方法 replace():搜索并替換(Method replace(): search and replace)

> '<a> <bbb>'.replace(/<(.*?)>/g, '[$1]')'[a] [bbb]'

replace的第一個(gè)參數(shù)必須是正則表達(dá)式,并且開(kāi)啟全局搜索(/g 標(biāo)記),否則僅第一個(gè)匹配項(xiàng)會(huì)被替換。有一種方法使用一個(gè)函數(shù)來(lái)計(jì)算替換項(xiàng)。

深入閱讀


本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
各大互聯(lián)網(wǎng)公司2014前端筆試面試題–JavaScript篇 – 碼農(nóng)網(wǎng)
你可能不知道的19個(gè)JavaScript編碼技巧
每個(gè)前端開(kāi)發(fā)者必會(huì)的 20 個(gè) JavaScript 面試題 – 碼農(nóng)網(wǎng)
<貼板> Javascript 常見(jiàn)陷阱及特殊用法
JavaScript 新手的踩坑日記
JavaScript分享ES6相關(guān)知識(shí)
更多類(lèi)似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服