Javascript核心讀書有感之類型、值和變量
來源:易賢網(wǎng) 閱讀:699 次 日期:2015-02-13 10:57:24
溫馨提示:易賢網(wǎng)小編為您整理了“Javascript核心讀書有感之類型、值和變量”,方便廣大網(wǎng)友查閱!

計算機(jī)程序的運(yùn)行需要對值(value)比如數(shù)字3.14或者文本"hello world"進(jìn)行操作,在編程語言中,能夠表示并操作的值的類型叫做數(shù)據(jù)類型(type),編程語言最基本的特性就是主持多種數(shù)據(jù)類型。當(dāng)程序需要將值保持起來以備將來使用時,便將其賦值給(將值“保存”到)一個變量(variable)。變量是一個值的符號名稱,可以通過名稱獲得對值的引用。變量的工作機(jī)制是編程語言的令一個基本特性。本章將參照上節(jié)幫助理解本章內(nèi)容,后續(xù)將更深入的講解。

javascript的數(shù)據(jù)分為兩類:原始類(primitive type)和對象類型(object type)

javascript中的原始類包括數(shù)字,字符串,布爾值,本章會有單獨(dú)的章節(jié)專門講述javascript的數(shù)字、字符串、布爾值。javascript還有兩個特殊的原始值,null(空)和Undefined(未定義),他們不是數(shù)字、字符串、布爾值。它們分別代表了各自特殊類型的唯一成員。

javascript除了數(shù)字、字符串、布爾值、null、undefined之外就是對象了。對象 (object)是屬性(property)的集合。每個屬性都由"名/值對"(值可以是原始值,比如數(shù)字,字符串,也可以是對象)構(gòu)成。其中一個比較特殊的對象(全局對象(global object)會在第五小姐介紹,第六小節(jié)將更詳細(xì)的描述)

普通的javascript對象是“命名值”的無需集合。javascript同樣定義了一種特殊對象--數(shù)組(array),表示帶編號的值的有序集合。javascript為數(shù)組定義了專用的語法。使數(shù)組擁有一些和普通對象不同的特有的行為屬性。

javascript還定義了一種特殊的對象--函數(shù)。函數(shù)是具有與它想關(guān)聯(lián)的可執(zhí)行代碼的對象,通過調(diào)用函數(shù)來運(yùn)行科執(zhí)行代碼,并返還運(yùn)算結(jié)果。和數(shù)組一樣,函數(shù)行為特征和其它對象都不一樣。javascript為使用函數(shù)定義了專用語法。對javascript函數(shù)來講。最重要的是,他們都是真值,并且javascript可以講他們當(dāng)做普通對象來對待。

如果函數(shù)初始化(使用new運(yùn)算符)一個新建對象,我們稱之為構(gòu)造函數(shù)(constructor)。每個構(gòu)造函數(shù)定義了一類(class)對象--構(gòu)造函數(shù)初始化對象組成的集合。類可以看做對象類型的子類型。除了數(shù)組(array)類和函數(shù)(function)類之外,javascript還定義了其它三種由用的類。日期(date)定義了代表日期的對象。正則(regExp)定義了正則表達(dá)式的對象。錯誤(error)類定義了那行表示javascript程序中運(yùn)行時錯誤和語法錯誤對象??梢酝ㄟ^定義自己的構(gòu)造函數(shù)來定義需要的類。

javascript解釋器有自己的內(nèi)存管理機(jī)制,可以自動對內(nèi)存進(jìn)行垃圾回收(garbagecollection)。這意味著程序程序可以按需創(chuàng)建對象,程序員則不必?fù)?dān)心這些對象的銷毀了內(nèi)存回收。當(dāng)不再有任何一個引用指向一個對象,解釋器就知道這個對象沒有用了,然后會自動回收它所占用的內(nèi)存資源。

javascript是一種面向?qū)ο蟮恼Z言。不嚴(yán)格的講,這意味著我們不用全局的定義函數(shù)去操作不同類型的值,數(shù)據(jù)類型本身可以定義方法(method)來使用值,例如要對數(shù)組a中的元素進(jìn)行排序,不必要將a傳入sort()函數(shù),而是調(diào)運(yùn)a的一個方法sort()

a.sort(); //sort(a)面向?qū)ο蟮陌姹?/P>

從技術(shù)上來將,只有javascript對象才能擁有方法。然而,數(shù)字,字符串,布爾值也擁有自己的方法。在javascript中,只有null和undefined是無法擁有方法的值。

javascript的類型可以分為原始類型和對象類型,可分為可以擁有方法的類型和不能擁有方法的類型。同樣可分為可變(mutable)和不可變(immutable)類型。可變類型的值是可以修改的,對象和數(shù)組屬于可變類型:javascript程序可以改變對象的屬性值和數(shù)組元素的值。

數(shù)字、布爾值、null和undefined屬于不可改變的類型。比如,修改一個數(shù)組的內(nèi)容本身就說不通。字符串可以看做是字符組成的數(shù)組,你可以認(rèn)為它是可以變的。然而在javascript中,字符串是不可變的。可以訪問字符串任意位置的文本,但javascript并未提供修改一直字符串文本內(nèi)容的方法。

javascript可以自由地進(jìn)行數(shù)據(jù)類型轉(zhuǎn)換。比如,如果在程序期望使用字符串的地方使用了數(shù)字,javascript會自動將數(shù)字轉(zhuǎn)換為字符串。如果期望在使用布爾值的地方使用了非布爾值,javascript也會相應(yīng)的轉(zhuǎn)換。javascript中對靈活的類型抓換規(guī)則對“判斷相等”(equality)

javascript的變量是無類型的(untyped),變量可以被賦予人和類型的值,使用var關(guān)鍵字來聲明(declare)變量。javascript采用語法作用域,不在任何函數(shù)內(nèi)聲明的變量稱為全局變量(global variable),它在javascript的程序 中任何地方都是可見的。

1.數(shù)字

和其它編程語言不同,javascript不區(qū)分整數(shù)數(shù)值和浮點(diǎn)數(shù)數(shù)值。javascript中的數(shù)值均用浮點(diǎn)數(shù)數(shù)值來表示。當(dāng)一個數(shù)字直接出現(xiàn)在javascript程序中,我們陳之為數(shù)字直接量(numeric literal),javascript支持多種格式的數(shù)字直接量。(注意:在任何數(shù)字前直接添加負(fù)號(-)可以得到它們的負(fù)值)但負(fù)號是一元求反運(yùn)算符。,并不是數(shù)字直接量語法的組成部分。)

i整數(shù)型直接量

javascript中用一個數(shù)組序列表示一個十進(jìn)制的整數(shù)

除了十進(jìn)制的整數(shù)直接量,javascript同樣識別十六機(jī)制(16)為基數(shù)的的值。所謂十六進(jìn)制是以“0X”或者"0x"為前綴,其后緊跟十六進(jìn)制數(shù)串的直接量。十六進(jìn)制數(shù)值是0-9的數(shù)字和a(A)-f(F)之間的字母構(gòu)成。a-f的字母對于的表述數(shù)字10-15下面是十六進(jìn)制整型直接量的例子

代碼如下:

0xff //15*16+15=255

0xCAFE911

盡管ECMAScript不支持八進(jìn)制直接量,但javascript的某些實現(xiàn)可以允許采用八進(jìn)制(基數(shù)為8)形式表示整數(shù)。八進(jìn)制直接量以數(shù)字0開始,其后跟隨著一個0-7之間數(shù)字組成的序列。

代碼如下:

0377 // 3*64 +7*8 +7 =255(十進(jìn)制)

由于某些javascript的實現(xiàn)支持八進(jìn)制的之間量,而有些不支持,因此最好不要使用以0為前綴的整數(shù)之間量,畢竟我們也無法得知當(dāng)前javascript的實現(xiàn)是否支持八進(jìn)制的解析。在ECMAScript6的嚴(yán)格模式下,八進(jìn)制的直接量是明令禁止的。

ii.浮點(diǎn)型直接量

浮點(diǎn)型直接量可以含有小數(shù)點(diǎn),它們采用的是傳統(tǒng)的實數(shù)寫法。一個實數(shù)由整數(shù)部分,小數(shù)點(diǎn)和小數(shù)部分組成。

此外,還可以使用指數(shù)計數(shù)法表示浮點(diǎn)型直接量。即在實數(shù)后跟字母E或e,后面再跟正負(fù)號,其后再加一個整型的指數(shù)。這種計數(shù)方法表示的數(shù)值,是有前面的實數(shù)乘以10的指數(shù)冪。

可以使用更簡潔的語法來表示

代碼如下:

[digits][.digits][(E|e)[(+|-)]digits]

3.14

2345.455

.33333333333333333

6.02e23 //6.02*10的23次方

1.255454E-23 //1.255454*10的負(fù)23次方

iii.javascript中的算術(shù)運(yùn)算

javascript程序是使用語言本省提供的算術(shù)運(yùn)算符來進(jìn)行數(shù)字運(yùn)算的的。這些運(yùn)算符包含+ - * /和求余(整除后的余數(shù))運(yùn)算符%

除了基本的運(yùn)算符之外,javascript還支持更加復(fù)雜的算術(shù)運(yùn)算,這個線復(fù)雜的運(yùn)算通過作為Math對象的屬性定義的函數(shù)和常量實現(xiàn)。

代碼如下:

Math.pow(2, 53) //=>9007199254740992 document.write(Math.pow(2,53) )

Math.round(.6) //=>1.0 四舍五入

Math.ceil(.6) //=>1.0向上求整

Math.floor(.6) //=>0.0向下求整

Math.abs(-5) //=>5 求絕對值

Math.max(x, y, z) //返回最大值

Math.min(x, y, z) //返回最小值

Math.random() //生成一個大于0小于1的偽隨機(jī)數(shù)

Math.PI //圓周率π

Math.E //e:自然對數(shù)的底數(shù)

Math.sqrt(3) //3的平方根

Math.pow(3, 1 / 3) //3的立方根

Math.sin(0) //三角函數(shù),還有Math.cos,Math.atan等

Math.log(10) //=>2.302585092994046 以10為底的自然對數(shù)

Math.log(512) / Math.LN2 //以2為底的512的對數(shù)

Math.log(100) / Math.LN10 //以10為底的100的對數(shù)

Math.exp(3) //e的三次冪

javascript中的算術(shù)運(yùn)算在溢出(overflow)、下溢(underflow)或被零整除時不會報錯。但數(shù)字運(yùn)算結(jié)果超過了javascript中所能表示的數(shù)字上線(溢出),結(jié)果為一個特殊的無窮大的值(infinty)值,在javascript中以infinty表示。同樣地,當(dāng)負(fù)數(shù)的值超過了javascript所能表達(dá)的負(fù)數(shù)范圍,結(jié)果為負(fù)無窮大,在javascript中以-Infinty表示。無窮大值的行為特性和我們所期望的是一致的:基于它們的加減乘除運(yùn)算結(jié)果是無窮大(保留正負(fù)號)

下溢(underflow)是當(dāng)運(yùn)算結(jié)果無線接近于零并比 javascript能表示的最小值還小的時候發(fā)生的一種情形。當(dāng)一個負(fù)數(shù)發(fā)生下溢時,javascript返回一個特殊的值,“負(fù)零”,這個(負(fù)零)幾乎和正常的零完全一樣。javascript程序員很少用到負(fù)零。

javascript預(yù)定義了全局變量Infinaty和NaN,用來表達(dá)正無窮大河非數(shù)字值,在ECMAScipt3中,這兩個值是可以讀寫的。ECMAScript5修正了這個問題,將他們定義為只讀的。ECMAScipt3中的Number對象定義的屬性值也是只讀的,這里有一些例子:

代碼如下:

Infinity //將一個可讀/寫的變量初始化為infinty

Number.POSITIVE_INFINITY //同樣的值,只讀

1 / 0 //這也是同樣的值

Number.MAX_VALUE + 1 //計算結(jié)果還是Infinity

Number.NEGATIVE_INFINITY //表示了負(fù)無窮大

-Infinity

-1/0

-Number.MAX_VALUE -1

NaN //將一個可讀/寫的變量初始化為NaN

Number.NaN //同樣的值,但是只讀

0/0 //計算結(jié)果還是NaN

Number.MIN_VALUE/2 //發(fā)生下溢。計算結(jié)果為0

-Number.MIN_VALUE/2 //負(fù)零

-1/Infinity //負(fù)零

-0 //負(fù)零

javascript中的非數(shù)字值有一點(diǎn)特殊,它和人和值都不相等,包括自身。也就是說沒法通過x==NaN來判斷x是否為NaN。相反,應(yīng)當(dāng)使用x!=x來判斷,當(dāng)且僅當(dāng)x為NaN的時候,表達(dá)式的結(jié)果為true.函數(shù)isNaN()作用與此相似,如果參數(shù)是NaN或者是一個非數(shù)字值(比如字符串和對象),則返回true。javascript中有一個類似的函數(shù)isFinite(),在參數(shù)不是NaN、Infinty或-Infinity的時候返回true.

負(fù)零值同樣有些特殊,它和正負(fù)零是相等的(甚至使用javascript的嚴(yán)格相等測試來判斷)、這意味這兩個值幾乎是一模一樣的,除了作為除數(shù)之外:

代碼如下:

var zero = 0;

var negz = -0;

zero === negz //=>true 正負(fù)零值相等

1/zero === 1/negz //false 正無窮大和負(fù)無窮大不等

iiii.二進(jìn)制浮點(diǎn)數(shù)和四舍五入錯誤

實數(shù)有無數(shù)個,但javascript通過浮點(diǎn)數(shù)的形式只能表示有限的個數(shù)(確切的說有18 437 736 874 454 810 627個),也就是說,當(dāng)javascript中使用實數(shù)的時候,常常只是真實值的一個近似的表示。

javascript采用了IEEE-754浮點(diǎn)數(shù)表示法(幾乎所有的現(xiàn)代編程語言采用)。這是一種二進(jìn)制表示法,可以精確的表示分?jǐn)?shù),比如1/2 1/8 和1/1024,遺憾的是,我們常采用的分?jǐn)?shù),特別是金融計算方面,都是以十進(jìn)制分?jǐn)?shù)1/10 ,1/100等。二進(jìn)制表示法并不能表示類似0.1這樣簡單的數(shù)字。

javascript中的數(shù)字具有足夠的精度。并可以接近0.1.但事實上,數(shù)字不能精確表述帶來了一些問題。

代碼如下:

var x = .3 - .2;

var y = .2 - .1;

alert(x == y) //=>false 兩值不相等

x == .1 //=>false .3-.2 不等于.1

y == .1 //=>true .2-.1等于1

由于舍入誤差,0.3和0.2之間的近似差值實際上并不等于0.2和0.1之間的近似差值(在真實模擬環(huán)境中,0.3-0.2=0.099 999 999 999 999 98).這個問題不只在javascript中存在,理解這一點(diǎn)十分重要:在任何使用二進(jìn)制浮點(diǎn)數(shù)的編程語言中都會有這個問題。同樣需要注意的是,上述代碼中x和y的值非常接近彼此和最終的正確值。這種計算結(jié)果可以勝任大多數(shù)的計算任務(wù)。這個問題也是只有比較兩個值是否相等的時候才才會出現(xiàn)。

javascript的未來版或許支持十進(jìn)制數(shù)字類型以避免這個問題,在這之前你可能更愿意使用大整數(shù)進(jìn)行重要的金融計算。例如,要使用整數(shù)“分”,而不要使用小數(shù)“元”進(jìn)行基于貨幣單位的運(yùn)算。

iiiii.日期和時間

javascript語言核心包含Date()構(gòu)造函數(shù),原來創(chuàng)建日期和時間的對象,這些日期對象的方法為日期計算提供了簡單的API,日期對象不能像數(shù)字那樣是基本數(shù)據(jù)類型。

代碼如下:

var zhen = new Date(2011, 0, 1); //2011年1月1日

var later = new Date(2011, 0, 1, 17, 10, 30); //同一天

var now = new Date(); //當(dāng)前的日期和時間

var elapsed = now - zhen; //日期減法。計算時間間隔的毫秒數(shù)

later.getFullYear(); //=>2011

later.getMonth(); //=>0 從0開始計數(shù)的月份

later.getDate(); //=>1 從1開始計數(shù)的天數(shù)

later.getDay(); //=>5 得到星期幾。 0代表星期日,5代表星期1

later.getHours() //=>當(dāng)?shù)貢r間

later.getUTCHours() //使用UTC表示小時的時間,基于時區(qū)。

2.文本

字符串(string)是一組16位值組成的不可變的有序序列,每個字符通常來自于Unicode字符集。javascript通過字符串類型來表示文本。字符串的長度(length)是其所含的16位值的個數(shù)。javascript字符串(和其數(shù)組)的索引從0開始??兆址?empty string)長度為0,javascript中并沒有表示單個字符的“字符型”。要表示一個16位值,只需要將其賦值給字符串變量即可。這個字符串的長度為1。

字符集,內(nèi)碼和javascript字符串

javascript采用UTF-16編碼的Unicode字符集,javascript字符串是由一組無序號的16位值組成的序列。最常用的Unicode字符都是通過16位的內(nèi)碼表示,并代表字符串中的單個字符,那行不能表示為16位的Unicode字符則遵循UTF-16編碼規(guī)則----用兩個16位值組成一個序列(亦稱為“代理項對”)表示。這意味著一個長度為2的javascript字符串(兩個16位值)可能表示一個Unicode字符。

代碼如下:

var p ="π" ; //π由16位內(nèi)碼表示0x03c0

var e = "e"; //e由17位內(nèi)碼表示0x1d452

p.length // =>1 p包含一個16位的值

e.length // =>2 e通過UTF-16編碼后包含兩個值:"\ud835\udc52"

javascript定義的各式字符串操作方法均作用于16位值,而非字符,且不會對代理項對做單獨(dú)處理。同樣javascript不會對字符串做標(biāo)準(zhǔn)化的加工。甚至不能保證字符串是合法的UTF-16格式

i字符串直接量

在javascript程序中的字符串直接量,是由單引號或雙引號括起來的字符序列,由單引號定界的字符串中可以包含雙引號,由雙引號定界的字符串中也可以包含單引號。這里有幾個字符串直接量的例子。

代碼如下:

"" //空字符串,0個字符

'testing'

"3.14"

'name="myform"'

"wouldn't you prefer O'Reily's book?"

ECMAScript3中,字符串直接量必須寫在一行中,而在ECMAScript5中,字符串的直接量可以拆分為數(shù)行,每行必須以反斜線(\)結(jié)束,反斜線和行結(jié)束符都不是字符串直接量的內(nèi)容。如果希望在一起,則可以使用\n轉(zhuǎn)義字符。

需要注意的是,當(dāng)使用單引號定界字符串時,需要格外小心英文中的縮寫和所有格式寫法,英文撇號和單引號是同一個字符,所以必須使用反斜線(\)來轉(zhuǎn)義。

ii轉(zhuǎn)義字符

在javascript字符串中,反斜線(\)有著特殊的用途,反斜線后加一個字符,就不再表示他們的字面含義了,比如\n 就是一個轉(zhuǎn)義字符,它表示一個換行符。

代碼如下:

\o //NUL字符

\b //退格符

\t //水平制表符

\n //換行符

\v //垂直制表符

\f //換頁符

\r //回車符

\" //雙引號

\\ 反斜線

\xXX 由兩位十六進(jìn)制指定的Latin-1字符

\xXXXX 由四位十六進(jìn)制XXXX指定的Unicode字符

iii字符串的使用

javascript的內(nèi)置功能之一就是字符串連接。將運(yùn)算符+用于字符串,表示字符串連接。例如

代碼如下:

var msg = "hello" + "world"; //生成字符串hello world

要確定一個字符串的長度——其所包含的16位值的個數(shù),可以使用length屬性,比如字符串s的長度。

s.length

除了length屬性,字符串還提供很多可以調(diào)用的方法。

代碼如下:

var s = "hello,world";

s.charAt(0); //"h"第一個字符

s.charAt(s.length - 1) //"d"最后一個字符

s.substring(1, 4) //"ell" 2-4個字符

s.slice(1, 4) //ell 同上

s.slice(-3) // 最后出現(xiàn)的3個字符

s.indexOf(l ")//2字符l 第一次出現(xiàn)的位置

s.lastIndexOf("l") //10 字符l最后一次出現(xiàn)的位置

s.indexOf("l",3)//在位置3之后,l字符首次出現(xiàn)的位置

s.split(",") //=> ["hello","world"]分隔成子串

s.replace("h","H")// =>"Hllo,world"全文字符替換

s.toUpperCase() //=>"HELLO,WORLD"

在javascript中,字符串是固定不變的,類似replace()和toUpperCase()方法都返回了新的字符串,原來的字符本身沒有發(fā)生變化。

在ECMAScript中,字符可以當(dāng)做只讀數(shù)組,除了使用charAt()方法,也可以使用方括弧來訪問字符串中的單個字符。(16位值)

代碼如下:

s = "hello,world"

s[0] //=>"h"

s[s.length-1] //=>"d"

Foxfire很久之前就支持這樣方法的字符串索引,多數(shù)現(xiàn)代瀏覽器(IE除外)也緊跟Mozailla的腳步,在ECMAScript成型之前就完成了這一特性

iiii模式匹配

javascript定義了RegExp()構(gòu)造函數(shù),用來創(chuàng)建表示文本模式匹配的對象,這些模式被稱為“正則表達(dá)式”(regular expression),javascript彩陽Perl中的正則表達(dá)語法。String和RegExp對象均定義了利用正則表達(dá)式進(jìn)行模式匹配和查找與替換的函數(shù)。

RegExp對象并不是語言中的基本數(shù)據(jù)類型,和Date一樣,它只是一種具有實用API的特殊對象。正則表達(dá)式的語法很復(fù)雜,API也很豐富。在第10章節(jié)會詳細(xì)介紹。RegExp是一種強(qiáng)大和常用的文本處理工具,此處只是一個概述。

盡管RegExp并不是語言中的基本數(shù)據(jù)類型,但是他們依然具有直接量的寫法,可以直接在javascript中使用。在兩條斜線之間的文本構(gòu)成了一個正則表達(dá)式的直接量。第二條斜線之后也可以跟隨一個或多個字母。用來修飾匹配模式的含義。例如:

代碼如下:

/^HTML/ //匹配以HTML開始的字符串

/[1-9][0-9]*/ //匹配一個非零數(shù)字,后面是任意個數(shù)字

/\bjavascript\b/i/ //匹配單詞javascript,并忽略大小寫

RegExp對象定義了很多有用的方法,字符串同樣具有可以接受RegExp參數(shù)的方法。例如:

代碼如下:

var text = "testing:1,2,3"; //文本示例

var pattern = /\d+/g / //匹配所有包含一個或多個數(shù)字的實例

pattern.test(text) // =>true:匹配成功

text.search(pattern) //=>9 :首次匹配成功的位置

text.match(pattern) //=> ["1","2","3"]所有匹配組成數(shù)組

text.repeat(pattern,"#"); //=>"testing:#,#,#"

text.split(/\D+/); //=>["","1","2","3"]:用非數(shù)字字符截取字符串

3.布爾值

布爾值指代真或假,開或關(guān),這個類型只有兩個值,保留字true或false

javascript中的比較語句的結(jié)果通常都是布爾值。例如

a==4

這段代碼用來檢測變量的a的值是否等于4.如果等于,則值為true,如果不等值為false

布爾值通常用于javascript的控制語句中,例如javascript中的if/else語句,如果布爾值為true執(zhí)行第一段邏輯,如果為false執(zhí)行另一段代碼,例如

代碼如下:

if (a == 4)

b = b + 1;

else

a = a + 1;

任意javascript的值都可以轉(zhuǎn)化為布爾值,下面這些值都被轉(zhuǎn)化為false

代碼如下:

undefined

null

0

-0

NaN

""http://空字符串

所有其它值,包括所有對象(數(shù)組)都會被轉(zhuǎn)換為true,false和上面6個可以轉(zhuǎn)化為false的值有時候稱為“假值”,javascript期望使用一個布爾值時,假值會被當(dāng)做false,真值會被當(dāng)做true

來看一個例子,加上變量o是一個對象或是null,可以通過一條if語句來檢測o是否是非null值。

if(o!==null)...

不等操作符“!==”將o和null比較,并得出結(jié)果為 true或false??梢韵群雎赃@里的比較語句,null是一個假值,對象是一個真值。

if(o)...

對于第一種情況,只要當(dāng)o不是null時才會執(zhí)行if后的代碼,第二種情況的限制沒有那么嚴(yán)格。只有o不是false或任何假值(比如null或unfined)時才執(zhí)行這個if。

布爾值包含toString()方法,因此可以使用這個方法將字符串轉(zhuǎn)換為 “true”或"false",但它不包含其他有用的方法,除了這個不重要的API,還有三個重要的布爾值運(yùn)算符。

&&運(yùn)算符,||運(yùn)算符和一元操作符“!”執(zhí)行了布爾非(NOT)操作,如果真值返回false,假值返回true,比如

代碼如下:

if ((x == 0 && y == 0) || !(z == 0)) {

//x和y都是零或z是非零

}

4.null和undefined

null是javascript語言的關(guān)鍵字,它表示一個特殊值“空值”,對于null執(zhí)行typeof()運(yùn)算,返回object.也就是說,可以將null認(rèn)為是一個特殊的對象值,含義是"非對象"。但實際上,通常認(rèn)為null是它自由類型的唯一一個成員。它可以表示數(shù)字,字符串,和對象是“無值”的。大多數(shù)編程語言和javascript一樣含有null,你可以對null或者nil很熟。

javascript還有第二個值表示值的空缺。用來表示更深層次的“空值”。它是一種變量的一種取值。表示變量的沒有初始化。如果要查詢對象屬性或數(shù)組元素的值是返回undefined則表明這個屬性或者元素不存在。undefined是預(yù)定義的全局變量(它和null不一樣,它不是關(guān)鍵字),它的值就是未定義。如果使用typeof來測試undefined類型,則返回“undefined”,表明這個值是這個類型的唯一成員。

盡管null和undefined是不同的,但它們都表示“值的空缺”,兩者往往可以互換。判斷相等的運(yùn)算符“==”認(rèn)為兩者是相等的(要使用嚴(yán)格相等運(yùn)算符"==="來區(qū)分它們)。在希望值是布爾類型的地方它們的值都是假值。和false類似。null和undefined都是不包含任何屬性和方法。實際上,使用"."和"[]"來存取這兩個值的成員或方法,都會產(chǎn)生一個類型錯誤。

你或許認(rèn)為undefined是表示系統(tǒng)級的,出乎意料的活類似錯誤的值的空缺,而null是表示程序級的,正?;蛟谝饬现械闹档目杖?,如果你想將它們復(fù)制變量或者屬性,或?qū)⑺鼈冏鳛閰?shù)傳入函數(shù),null是最佳的選擇。

5.全局對象

前幾節(jié)討論了javascript的元素類型和原始值。對象類型——對象、數(shù)組和函數(shù)/但有一類非常重要的對象,不得現(xiàn)在就必須將清楚:全局對象

全局對象(global object)在javascript中有著重要的用途。全局對象的屬性是全局定義的符號。javascript程序可以直接使用。當(dāng)javascript解釋器啟動時,它將新建一個新的全局對象,并給它一組定義的初始屬性。

全局屬性 比如undefined Infinty和NaN

全局函數(shù) 比如isNaN()、parseInt()和eval()

構(gòu)造函數(shù),比如Date()、RegExp()、String()、Object()和Array()

全局對象,比如Math 和JSON

全局對象的初始屬性并不是保留字,但他們應(yīng)當(dāng)當(dāng)做保留字來對待。

在代碼的最頂級——不在任何函數(shù)內(nèi)的javascript代碼,可以通過javascript關(guān)鍵字來引用全局對象。

var global = this; //定義一個引用全局對象的全局變量。

在客戶端javascript中,window對象充當(dāng)了全局對象,這個全局window對象有一個熟悉window引用其本身,它可以代替this來引用全局對象,window定義了全局核心屬性。但也征對web瀏覽器和和互動javascript定義了一部分其他全局屬性。

當(dāng)初次創(chuàng)建時,全局對象定義了javascript中所有的預(yù)定義全局值,這個特殊對象同樣包含了為程序定義的全局值。如果代碼聲明了一個全局變量。這個全局變量就是全局對象的一個屬性。

6.包裝對象

javascript對象是一種復(fù)合值:它是屬性或已命名值的集合。通過"."來引用屬性值,當(dāng)屬性值是一個函數(shù)的時候,陳其為方法,通過o.m()來調(diào)運(yùn)對象o中的方法。

我們看到字符串也同樣具有屬性和方法。

代碼如下:

var s ="hello world";

var word = s.substring(s.indexOf("")+1,s.length);//使用字符串的屬性。

document.write(word) //"ello world"

字符串既然不是對象,為什么它有屬性呢?只要引用了字符串s的屬性,javascript就會將字符串的值通過調(diào)用new String(s)的方式轉(zhuǎn)換成對象,這個對象繼承了字符串的方法。并被用來處理屬性引用。一旦新的屬性引用出來。一但引用結(jié)束,這個新創(chuàng)建的對象就會被銷毀。(實際上并不一定創(chuàng)建或銷毀這個臨時對象,然而這個過程看起來是這樣的。)

如同字符串一樣,數(shù)字和布爾值也具有各自的方法,通過Number()和Boolean()構(gòu)造函數(shù)創(chuàng)建一個臨時對象。這些方法的調(diào)用均是來自于這個臨時對象。(null和undefined沒有包裝過對象,訪問他們的屬性會有一個類型錯誤)

看如下 代碼,思考他們的執(zhí)行過程

代碼如下:

var s = "test";

s.len = 4; //給它設(shè)置一個屬性

var t = s.len //查找這個屬性

當(dāng)運(yùn)行這段代碼時,t的值是undefined,第二行代碼創(chuàng)建一個臨時字符串對象,并給len的值為4,隨即銷毀這個對象,第三行用過原始(沒有被修改的)的字符串創(chuàng)建一個新的字符串對象,并嘗試讀取len 的屬性。

這個屬性自然不存在,表示結(jié)果undefined,這段代碼說明了讀取字符串、數(shù)組和布爾值的屬性值(或方法)時,表現(xiàn)的像對象一樣,但如果你試圖給其屬性賦值。則會忽略這個操作;修改只是發(fā)生在臨時對象身上。而這個臨時對象并未保留下來。

需要注意的是,可以通過String(),Number(),Boolean()構(gòu)造函數(shù)來顯示創(chuàng)造包裝對象:

代碼如下:

var s = "test",

n = 1,

b = true;

var S = new String(s);

var N = new Number(n);

var B = new Boolean(b);

javascript會在必要的時候?qū)b轉(zhuǎn)換為原始值,因此上段代碼中的對象S N B常常——但不總是——表現(xiàn)的值和s n b一樣,"=="等于運(yùn)算符將原始值和其包裝對象視為相等。

但"==="全籌運(yùn)算符將它們視為不等,通過typeof運(yùn)算符可以看到原始值和其包裝的對象的不同。

7.不可變的原始值和可變的對象引用。

javascript的原始值(undefined null 布爾值 數(shù)字和字符串)與對象(包括數(shù)組和函數(shù))有著根本的區(qū)別,原始值是不可更改的;任何方法都無法(或突變)一個原始值。對數(shù)字和布爾值來說顯然如此———改變數(shù)字的值本身就說不通,而對字符串來說就不那么明顯,因為字符串看起來由字符組成的數(shù)組。我們期望可以通過指定的索引來修改字符串中的字符。實際上javascript是禁止這樣做的。字符串中所有的方法看上去返回了一個修改后的字符串,實際上是返回一個新的字符串。

代碼如下:

var s = "hello world";

s.toUpperCase(); //返回"HELLO WORLD"并沒更改s的值

s //=> "hello world" 原始的字符串并未改變

原始值的比較是值的比較,只有在他們的值相當(dāng)時它們在才相等。這對數(shù)字、布爾值、null和undefined來說聽起來有點(diǎn)難,并沒有其他辦法來比較他們。同樣,對于字符串來說則不那么明顯;如果比較兩個單獨(dú)的字符串,當(dāng)且僅當(dāng)他們的長度相等且每個索引的字符都相等時,javascript的才認(rèn)為相等。

代碼如下:

var o = {x:1} //定義一個對象

o.x = 2 //通過修改對象的屬性來改變對象

o.y = 3 //再次更改這個對象,給它增加一個新屬性

var a =[1,2,3] //數(shù)組也是可以修改的

a[0]=0; //更改數(shù)組中的一個元素

a[3]=4; 給數(shù)組增加一個新元素

對象的比較并非值的比較:即使兩個對象包含同樣的屬性及相同的值,他們也是不相等的,各個索引元素完全相等的兩個數(shù)組也不相等

代碼如下:

var o ={x:1}, p={x:1}//兩個具有相同屬性的兩個對象

o === p ;//=>false 兩個單獨(dú)的對象永不相等( o == p ; =>false)

var a =[],b=[]; //兩個單獨(dú)的空數(shù)組

a === b ; //=>false兩個單獨(dú)的數(shù)組永不相等

我們通常將對象稱為引用類型(reference type),以此來和javascript的基本類型區(qū)分開來。依照術(shù)語的叫法,對象都是引用(reference),對象的比較均是引用的比較;當(dāng)且當(dāng)它們應(yīng)用同一個基對象時,它們才相等。

代碼如下:

var a = []; //定義一個引用空數(shù)組的變量a

var b = a; //變量b引用同一個數(shù)組

b[0] = 1;

a[0] //=>1 變量a也會修改

a === b //=>true a和b引用同一個數(shù)組,因此他們相等。

就像你剛才看到的如上代碼,將對象(或數(shù)組)賦值給一個變量,僅僅是賦值的引用值:對象本身并沒有復(fù)制一次。

如果你想得到一個對象或數(shù)組的副本,則必須顯式復(fù)制對象的每個屬性或數(shù)組的每個元素。下面的這個例子則是通過循環(huán)來完成對數(shù)組的復(fù)制。

代碼如下:

var a = ['a', 'b', 'c']; //待復(fù)制的數(shù)組

var b = []; //復(fù)制到目標(biāo)的空數(shù)組

for (var i = 0; i < a.length; i++) { //遍歷a[]中的每個元素

b[i] = a[i]; //將元素復(fù)制到b中。

}

同樣的,如果我們想比較兩個單獨(dú)或者數(shù)組,則必須比較他們的屬性或元素。下面這段代碼定義了一個比較練個數(shù)組的函數(shù)。

代碼如下:

function equalArrays(a, b) {

if (a.length != b.length) return false; //兩個長度不相同的數(shù)組不相等

for (var i = 0; i < a.length; i++) //循環(huán)遍歷所有元素

if (a[i] !== b[i]) return false; //如果有任意元素不等,則數(shù)組不相等

return true; // 否則他們相等

}

8.類型轉(zhuǎn)化

javascript中的取值型非常靈活,我們已經(jīng)從布爾值看到了這一點(diǎn):當(dāng)javascript期望使用一個布爾值時候,你可以提供任意類型值。javascript將根據(jù)需要自行轉(zhuǎn)換類型。一些值(真值)為true,其它值(假值)轉(zhuǎn)化為false.這在其它類型中同樣適用。如果javascript期望使用一個字符串,它把給定的值轉(zhuǎn)換為字符串。如果javascript期望使用一個數(shù)組,它把給定的值轉(zhuǎn)換為數(shù)字(如果轉(zhuǎn)化結(jié)果無意義的話將返回NaN),一些例子如下:

代碼如下:

10 + "object" //=> "10object";

"7" * "4" // =>28 兩個字符串均轉(zhuǎn)化為數(shù)字

var n = 1 - "x" // =>NaN字符串x無法轉(zhuǎn)換為數(shù)字

n + " objects" // =>"NaN objects":NaN轉(zhuǎn)換為字符串"NaN"

下表說明了在javascript中如何進(jìn)行類型轉(zhuǎn)化。粗體突出了那些讓你倍感意外的類型轉(zhuǎn)化。空單元格表示不必要也沒有執(zhí)行的轉(zhuǎn)換。

值轉(zhuǎn)換為字符串?dāng)?shù)字布爾值對象

undefined

null"undefined"

"null"NaN

0false

falsethrows TypeError

throws TypeError

true

false"ture"

"false"1

0 new Boolean(true)

new Boolean(false)

""(空字符串)

"1.2"(非空,數(shù)字)

"one"(非空,非數(shù)字) 0

1.2

NaNfalse

true

truenew String("")

new String("1.2")

new String("one")

0

-0

NaN

Infinty

-Infinty

1(無窮大,非零)"0"

"0"

"NaN"

"Infinity"

"-Infinity" "1" false

false

false

true

true

truenew Number(0);

new Number(-0);

new Number(NaN)

new Number(Infinty)

new Number(-Infinty)

new Number(1)

{}(任意對象)

[](任意數(shù)組)

[9](1個數(shù)字元素)

['a'](其它數(shù)組)

function(){}(任意函數(shù))參考本小節(jié)第三節(jié)內(nèi)容

""

"9"

使用join()方法

參考本小節(jié)第三節(jié)內(nèi)容參考本小節(jié)第三節(jié)內(nèi)容

0

9

NaN

NaNtrue

true

true

true

true

上表提到的原始值到原始值的轉(zhuǎn)換行對簡單,我們已經(jīng)在第本文第三小節(jié)討論過轉(zhuǎn)換為布爾值的情況了。所有原始值轉(zhuǎn)換為字符串的情形也已經(jīng)明確定義。轉(zhuǎn)換為數(shù)字的情形比較微妙。那些以數(shù)字表示的字符串可以直接轉(zhuǎn)化為數(shù)字,也允許在開始和結(jié)尾處帶有空格。但在開始和結(jié)尾處的任意非空字符都不會被當(dāng)成數(shù)字量的一部分,進(jìn)而造成字符串為數(shù)字的結(jié)果為NaN。有一些數(shù)字轉(zhuǎn)換看起來讓人奇怪:true轉(zhuǎn)換為1,false、空字符串""轉(zhuǎn)換為0.

原始值到對象的轉(zhuǎn)換也非常簡單,原始值通過調(diào)用String(),Number()或Boolean()構(gòu)造函數(shù),轉(zhuǎn)化為它們各自的包裝對象。見本文第6節(jié)。

null和undefined屬于例外,當(dāng)將它們用在期望是一個對象的地方都會造成一個類型錯誤(TypeError)異常。而不會執(zhí)行正常的轉(zhuǎn)換。

對象到原始值的轉(zhuǎn)換多少有些復(fù)雜,本小節(jié)第三小節(jié)有專門描述。

i.轉(zhuǎn)換和相等性

由于javascript可以做靈活的類型轉(zhuǎn)換,因此其“==”相等運(yùn)算符也隨相等的含義靈活多變。例如:如下這些比較結(jié)果均是true;

null == undefined //這兩值被認(rèn)為相等

"0" == 0 //在比較之前,字符串轉(zhuǎn)換成數(shù)字。

0 = false //在這之前布爾值轉(zhuǎn)換成數(shù)字。

"0" ==false //在比較之前字符串和布爾值都轉(zhuǎn)換成數(shù)字

在第四章9節(jié)第一小節(jié)相信講解了“==”等于運(yùn)算符在判斷兩個值是否相等時做了那些類型轉(zhuǎn)換,并同樣介紹了“===”恒等運(yùn)算符在判斷相等時并未做任何的類型轉(zhuǎn)換。

需要特別注意的是:一個值轉(zhuǎn)換為另一個值并不意味著兩個值相等。比如在期望使用布爾值的地方使用了undefined,將會轉(zhuǎn)換為false,但這不表明undefined==false。javascript運(yùn)算符和語句期望使用多樣化的數(shù)據(jù)類型,并可以互相轉(zhuǎn)換。if語句將undefined轉(zhuǎn)化為false,但“==”運(yùn)算符從不試圖將其轉(zhuǎn)化為布爾值。

ii.顯式類型轉(zhuǎn)化

盡管javascript可以做做很多類型轉(zhuǎn)換,但有時仍需要做顯式轉(zhuǎn)換,或者為了使代碼變得清晰易讀而做顯式轉(zhuǎn)換。

做顯式轉(zhuǎn)換最重簡單的方法就是使用Boolean()、Number()、String()或Object函數(shù)。我們在本文第6節(jié)已經(jīng)介紹過了. 當(dāng)不通過new運(yùn)算符調(diào)運(yùn)這些函數(shù)時,他們會作為類型轉(zhuǎn)換函數(shù)并按照上邊表格所描述的規(guī)則做類型轉(zhuǎn)換。

代碼如下:

Number("3") //=>3

String(false) //=>"false"或使用false.toString()

Boolean([]) //=>true

Object(3) // =>new Number(3)

需要注意的是,除了null或undefined之外的任何值都具有toString()方法,在這個方法的執(zhí)行結(jié)果通常和String()方法返回的結(jié)果一致。同樣需要注意的話,如果試圖把null或undefined轉(zhuǎn)化為對象。則會拋出一個類型錯誤typeerro。Object()函數(shù)在這種情況下不會拋出異常:它僅簡單返回一個新創(chuàng)建的空對象。

javascript中的某些運(yùn)算符會做隱式的類型轉(zhuǎn)換,有時用于類型轉(zhuǎn)換。如果“+”運(yùn)算符的一個操作數(shù)是字符串,它將會把令一個操作數(shù)轉(zhuǎn)換為字符串。一元“+”運(yùn)算符將其操作數(shù)轉(zhuǎn)換為數(shù)字。同樣,一元“!”運(yùn)算符將其操作數(shù)轉(zhuǎn)換為布爾值取反,在代碼中常會看到這種類型轉(zhuǎn)換的慣用法。

代碼如下:

x + "" // 等于字符串String(x)

+x //等價于Number(x),也可以寫成x-0

!!x //等價于Boolean(x)

在計算機(jī)中數(shù)字的解析和格式化代碼是非常普通的工作。javascript中提供了專門的函數(shù)和方法用來更加精確的數(shù)字到字符串(number-to-string)和字符串到數(shù)字(string-to-number)的抓換。

Nmuber類定義的toString()方法可以接收表示基數(shù)(二進(jìn)制,八進(jìn)制,十六進(jìn)制等)的可選參數(shù),如果不指定該參數(shù),轉(zhuǎn)化規(guī)則將是十進(jìn)制。同樣也可以將數(shù)字轉(zhuǎn)換為其它進(jìn)制數(shù)。(范圍在2-36之間)

代碼如下:

var n = 17;

b_string = n.toString(2); //轉(zhuǎn)化為10001

o_string = "0" + n.toString(8); //轉(zhuǎn)化為八進(jìn)制 021

hex_string = "0x" + n.toString(16); //轉(zhuǎn)化為16進(jìn)制 0x11

javascript為控制輸出中小數(shù)點(diǎn)位置和有效數(shù)字位數(shù),或者決定是否需要指定指數(shù)計數(shù)法。Number類為這種數(shù)字到字符串定義了三個方法。

toFixed()根據(jù)小數(shù)點(diǎn)后指定位數(shù),將數(shù)字轉(zhuǎn)換為字符串,它從不使用指數(shù)計數(shù)法。toExponential()使用指數(shù)計數(shù)法,將數(shù)字轉(zhuǎn)換為指數(shù)形式的字符串,其中小數(shù)點(diǎn)前只有一位,小數(shù)點(diǎn)后的位置則由參數(shù)指定(也就是說有效數(shù)字位數(shù)要比指定的位數(shù)多一位)。toPrecision()根據(jù)指定的有效數(shù)字位數(shù),將數(shù)字轉(zhuǎn)換為字符串。如果有效數(shù)字的位數(shù)小于數(shù)字整數(shù)部分的位數(shù),則轉(zhuǎn)換成指數(shù)形式。我們注意到,三個方法都會適當(dāng)?shù)倪M(jìn)行四舍五入或填充0,

代碼如下:

var n = 123456.789;

n.toFixed(0); //"123457"

n.toFixed(2); //"123456.79"

n.toFixed(5); //"123456.78900"

n.toExponential(1); //"1.2e+5"

n.toExponential(3); //"1.235e+5"

n.toPrecision(4); // "1.235e+5"

n.toPrecision(7); //"123456.8"

n.toPrecision(10); //"123456.7890"

如果通過Number()轉(zhuǎn)換函數(shù)傳入一個字符串,它會試圖將其轉(zhuǎn)化為一個整數(shù)或浮點(diǎn)數(shù)直接量,這個方法只能基于十進(jìn)制進(jìn)行轉(zhuǎn)換,并且不能出現(xiàn)非法的尾隨字符。parseInt()和parseFloat()函數(shù)(它們是全局函數(shù),不屬于人和類的方法),更加靈活。parseInt()只解析整數(shù)。而parseFloat()則可以解析整數(shù)和浮點(diǎn)數(shù)。如果字符串前邊是0x或0X,parseInt()將其解析為16進(jìn)制數(shù)。兩個方法都會跳過任意量的前導(dǎo)空格,盡可能解析更多數(shù)值字符。并忽略后邊的內(nèi)容。如果第一個是非法的數(shù)字直接量,則返回NaN

代碼如下:

parseInt("3many nice") //=>3;

parseFloat("3.14meters") //=>3.14

parseInt("-12.34") //=>-12

parseInt("0xff") //=>255

parseInt("-0XFF") //=>-255

parseFloat(".1") // =>0.1

parseInt("0.1") //=> 0

parseInt(".1") //=>NaN 不能以.開始

parseInt("$112") //=>NaN 不能以$開頭

parseInt()可以接收第二個可選參數(shù)。這個參數(shù)指定數(shù)字轉(zhuǎn)換的基數(shù)。合法的取值范圍是2-36

代碼如下:

parseInt("11", 2) //=>3(1*2+1)

parseInt("ff", 16) //=> 255(15*16 +15)

parseInt("zz", 36) //=>1295(35*36+35)

parseInt("077", 8) // 63(7*8 +7)

parseInt("077", 10) //77(7*10+7)

iii.對象轉(zhuǎn)化為原始值。

對象到布爾值的轉(zhuǎn)換非常簡單:所有的對象(包括數(shù)組和函數(shù))都轉(zhuǎn)換為true。對于包裝對象亦是如此,new Boolean(false)是一個對象而不是原始值,它將轉(zhuǎn)換為true。 對象到字符串(object-to-String)和對象到數(shù)字(object-to-number)的轉(zhuǎn)換是通過調(diào)用帶轉(zhuǎn)換對象的一個方法來完成的。一個麻煩的事實是,javascript對象有兩個不同的方法來執(zhí)行轉(zhuǎn)換,并且接下來要討論并且接下來要討論的場景更加復(fù)雜。值得注意的是,這里提到的字符串和數(shù)字的轉(zhuǎn)換規(guī)則只適用于本地對象(native fangf object).宿主對象(例如:由web瀏覽器定義的對象),根據(jù)各自的算法可以轉(zhuǎn)換成字符串和數(shù)字。

所有的對象繼承了兩個轉(zhuǎn)換方法。第一個是toString(), 它的作用是返回一個反映這個對象的字符串。默認(rèn)的toString()方法并不會返回一個有趣的值。

({x:1,y:2}).toString() //=>"[object object]"

很多類定義了更多特定版本的toString()方法.

例如:數(shù)組類(Array class)的toString()方法將每個數(shù)組元素轉(zhuǎn)換為一個字符串,并在元素之間添加逗號后并合成結(jié)果字符串。

函數(shù)類(Function class)的toString()方法返回這個函數(shù)的實現(xiàn)定義的表示方式。實際上,這里的實現(xiàn)方式是通常是將用戶定義函數(shù)轉(zhuǎn)換為javascript源代碼字符串。

日期類(Date class)定義toString()方法返回一個可讀的(可被javascript-parsable解析的)日期和事件字符串

RegExp class定義的toString()方法將RegExp對象轉(zhuǎn)換為正則表達(dá)式直接量字符串。

代碼如下:

[1, 2, 3].toString(); //=> "1,2,3"

(function(x) {f(x);}).toString(); // =>"function(x){\n f(x); \n}"

/\d+/g.toString(); //=> /\\d+/g

new Date(2015, 0, 1).toString() //=>Thu Jan 01 2015 00:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)

另外一個函數(shù)是valueOf(),這個方法的任務(wù)并未詳細(xì)定義:如果存在任意原始值,它就默認(rèn)將對象轉(zhuǎn)換為表示它的原始值。對象是復(fù)合值,而且大多數(shù)對象無法真正表示一個原始值,數(shù)組、函數(shù)和正則表達(dá)式簡單地繼承了這個默認(rèn)方法,調(diào)用這些類型的實例的的valueOf()方法簡單地返回對象本身。日期類定義的valueOf()方法返回它的一個內(nèi)部表示:1970年1月1日以來的毫秒數(shù)。

代碼如下:

var d = new Date(2015, 0, 1); //=>Thu Jan 01 2015 00:00:00 GMT+0800 (中國標(biāo)準(zhǔn)時間)

d.valueOf() //=>1420041600000

通過是用我們剛才講解過的toString()和valueOf()方法,就可以做到對象到字符串和對象到數(shù)字的轉(zhuǎn)換了。但在某些場景中,javascript執(zhí)行了完全不同的對象到原始值的轉(zhuǎn)換。這些特殊的場景在本節(jié)的最后會講到。

javascript對象到字符串的轉(zhuǎn)換經(jīng)過了如下這些步奏

如果對象具有toString()方法,則調(diào)用這個方法。如果它返回一個原始值,javascript將這個值轉(zhuǎn)換為字符串(如果本身不是字符串的話),并返回這個字符串結(jié)果。

如果對象沒toString()方法,或者這個方法并不返回一個原始值,那么javascript會調(diào)用valueOf()方法。如果存在這個方法,則javascript調(diào)用它。如果返回值是原始值,javascript將責(zé)怪值轉(zhuǎn)換為字符串。

9.變量聲明。

在javascript程序中,使用一個變量之前應(yīng)該先聲明,變量是通過var來聲明的,如下所示:

var i;

var sum;

也可以通過一個var關(guān)鍵字聲明多個變量

var i,sun;

而且還可以將變量的初始值和變量聲明和寫在一起;

var message = "hello";

var i=0 ,j=0,k=0;

如果在var聲明語句中給變量指定初始值,那么雖然聲明了這個變量,但在給它存入一個值前,它的初始值是undefined. 我們注意到,在for和fo/in循環(huán)中同樣可以使用var語句,這樣可以更加簡潔地聲明在循環(huán)體語法中內(nèi)使用的循環(huán)變量。例如:

代碼如下:

for (var i = 0; i < 10; i++) log(i);

for (var i = 0, j = 10; i < 10, j = 100; i++, j--) console.log(i * j)

for (var p in o) console.log(p);

如果在var聲明語句中給變量指定初始值,那么雖然聲明了這個變量,但在給它存入一個值前,它的初始值是undefined. 我們注意到,在for和fo/in循環(huán)中同樣可以使用var語句,這樣可以更加簡潔地聲明在循環(huán)體語法中內(nèi)使用的循環(huán)變量。例如:

代碼如下:

var i=10;

i="ten";

10.變量作用域

一個變量的左右域(scope)是程序源代碼中定義這個變量的區(qū)域,全局變量擁有全局作用域,在javascript代碼中的任何地方都是定義。然而在函數(shù)內(nèi)部聲明變量只在函數(shù)體內(nèi)有定義。他們是局部變量,作用是局部性的。函數(shù)參數(shù)也是局部變量,它們只在函數(shù)體內(nèi)有定義。

在函數(shù)體內(nèi),局部變量的優(yōu)先級高于同名的全局變量。如果在函數(shù)內(nèi)聲明一個局部變量或者函數(shù)參數(shù)中帶有的變量和全局變量重名,那么全局變量就被局部變量所遮蓋。

代碼如下:

var scope = "global"; //聲明一個全局變量

function checkscope() {

var scope = "local"; //聲明一個同名的局部變量

return scope;

}

checkscope(); //=>"local"

盡管在全局作用域編寫代碼時可以不寫var語句,但聲明局部變量時則必須使用var語句。

代碼如下:

scope = "global"; //聲明一個全局變量,甚至不使用var來聲明

function checkscope2() {

scope = "local"; //修改了全局變量

myscope = "local"; //這里顯示式得聲明了一個新的全局變量

return [scope, myscope]; //

}

checkscope2(); //=> ["local","local"]:產(chǎn)生了副作用

scope // =>"local"全局變量修改了

myscope //=> "local"全局命名空間搞亂了。

函數(shù)定義是可以嵌套的。由于每個函數(shù)都有它直接的作用域,因此會出現(xiàn)幾個局部作用域嵌套的情況。

代碼如下:

var scope = "global scope"; //全局變量

function checkscope() {

var scope = "local scope"; //局部變量

function nested() {

var scope = "sested scope"; //嵌套作用域內(nèi)的局部變量

return scope;

}

return nested();

}

checkscope() //=>"嵌套作用域" sested scope

i.函數(shù)作用域和聲明提前

在一些類似c語言的編程語言中,花括號內(nèi)的每一段代碼都具有各自的左右域,而且變量在聲明他們的代碼之外是不可見的我們稱之為塊級作用域(block scope),而javascript中沒有塊級作用域,javascript取而代之的使用了函數(shù)作用域(function scope);變量在聲明它們的函數(shù)體以及這個函數(shù)體嵌套的任意函數(shù)體內(nèi)都是有意義的。

如下代碼,在不同的位置定義了i j k,他們都在同一個作用域內(nèi),這三個變量在函數(shù)體內(nèi)均有定義的。

代碼如下:

function test(o) {

var i = 0; //i在整個函數(shù)體內(nèi)均是定義的

if (typeif o == "object") {

var j = 0; //j在函數(shù)體內(nèi)是有定義的,不僅僅是在這個代碼段內(nèi)

for (var k = 0; k < 10; k++) { //k在函數(shù)體內(nèi)是有定義的,不僅僅是在循環(huán)內(nèi)

console.log(k); //輸出數(shù)字0-9

}

console.log(k); //k已經(jīng)定義,輸出10

}

console.log(j); //j已經(jīng)定義了,但可能沒有初始化。

}

javascript的函數(shù)作用域是指在函數(shù)內(nèi)聲明的所有變量在函數(shù)體內(nèi)始終是可見的。有意思的是,這意味這變量在聲明之前甚至已經(jīng)可用。javascript的這個特性被非正式的稱為聲明提前(hoisting),即javascript函數(shù)里聲明的所有變量(但不涉及賦值)都被提前至函數(shù)整體的頂部。如下代碼:

代碼如下:

var scope = "global";

function f() {

console.log(scope); //輸出"undefined",而不是"global"

var scope = "local"; //變量在這里賦初始值,但變量本身在函數(shù)體內(nèi)任何地方都是有定義的

console.log(scope); //輸出"local"

你可能誤以為函數(shù)的第一行會輸出"global",因為代碼還沒有執(zhí)行到var語句聲明局部變量的地方。其實不然,由于函數(shù)作用域的特性模具部變量在整個函數(shù)體內(nèi)始終有定義的,也就是說,在函數(shù)體內(nèi)局部變量覆蓋了同名全局變量。盡管如此,只有在程序執(zhí)行到var語句的時候,局部變量才能正真的被賦值。

因此,上述的過程等價于:將函數(shù)內(nèi)的變量聲明"提前"至函數(shù)頂部,同時變量初始化留在原來的位置:

代碼如下:

function f() {

var scope; //在函數(shù)的頂部聲明了局部變量

console.log(scope); //變量存在,但其值是"undefined"

scope = "local"; //在這里將其初始化,并賦值

console.log(scope); //這里它具有了我們所期望的值

}

在具有塊級作用域的編程語言中,在狹小的作用域里讓變量聲明和使用變量的代碼盡可能靠近彼此,通常來說,這是一個非常不錯的編程習(xí)慣。由于在javascript中沒有塊級作用域,因此一些程序員特意將變量聲明放在函數(shù)體頂部,而不是將聲明放在靠近使用變量之處。這種做法使得他們的源代碼非常清晰地反映了真實的變量作用域。

ii作為屬性的變量

當(dāng)聲明一個javascript全局變量時面試及上是定義了全局對象的一個屬性。見本文第三節(jié)。

當(dāng)使用var聲明一個變量時,創(chuàng)建的這個屬性是不可配置的。見第六章第7節(jié)。也就是說這個變量無法通過delete運(yùn)算符刪除。可能你已經(jīng)注意到了,如果你沒有使用嚴(yán)格模式并給一個未聲明的變量賦值的話。javascript會自動創(chuàng)建一個全局變量。以這種方式創(chuàng)建變量是全局對象正常的可配置屬性??梢詣h除它們。

代碼如下:

var truevar = 1; //聲明一耳光不可刪除的全局變量

fakevar = 2; //創(chuàng)建全局對象的一個可刪除的屬性

this.fakevar2 = 3; //同上

delete truevar // =>false 變量并沒有刪除

delete fakevar //=>true 變量被刪除

delete this.fakevar2 //=>true 變量被刪除

javascript全局變量是全局對象的屬性,這是在ECMAScript規(guī)范中強(qiáng)制規(guī)定的。對于局部變量則沒有此規(guī)定,但我們可以想象得到,局部變量當(dāng)做跟函數(shù)調(diào)用相關(guān)的某個對象的屬性。ECMAScript3規(guī)范稱對象為“調(diào)用對象”(call object),ECMAScript5規(guī)定范稱為“聲明上下文對象”(declarative environment record)。javascript可以允許使用this關(guān)鍵字引用全局對象,卻沒有方法可以引用局部變量中存放的對象。這種存放局部變量的對象的特有性質(zhì),是一種對我們不可見的內(nèi)部實現(xiàn)。然而,這些局部變量對象存在的觀念是非常重要的。

iii作用域鏈

javascript是基于詞法作用域的語言:通過閱讀包含變量定義在內(nèi)的舒航源碼就能知道變量的作用域。

全局變量在程序中始終是都是有定義的。局部變量在聲明它的函數(shù)體內(nèi)以及其所嵌套的函數(shù)內(nèi)始終是有定義的。

更多信息請查看IT技術(shù)專欄

更多信息請查看腳本欄目
易賢網(wǎng)手機(jī)網(wǎng)站地址:Javascript核心讀書有感之類型、值和變量
由于各方面情況的不斷調(diào)整與變化,易賢網(wǎng)提供的所有考試信息和咨詢回復(fù)僅供參考,敬請考生以權(quán)威部門公布的正式信息和咨詢?yōu)闇?zhǔn)!

2025國考·省考課程試聽報名

  • 報班類型
  • 姓名
  • 手機(jī)號
  • 驗證碼
關(guān)于我們 | 聯(lián)系我們 | 人才招聘 | 網(wǎng)站聲明 | 網(wǎng)站幫助 | 非正式的簡要咨詢 | 簡要咨詢須知 | 加入群交流 | 手機(jī)站點(diǎn) | 投訴建議
工業(yè)和信息化部備案號:滇ICP備2023014141號-1 云南省教育廳備案號:云教ICP備0901021 滇公網(wǎng)安備53010202001879號 人力資源服務(wù)許可證:(云)人服證字(2023)第0102001523號
云南網(wǎng)警備案專用圖標(biāo)
聯(lián)系電話:0871-65099533/13759567129 獲取招聘考試信息及咨詢關(guān)注公眾號:hfpxwx
咨詢QQ:526150442(9:00—18:00)版權(quán)所有:易賢網(wǎng)
云南網(wǎng)警報警專用圖標(biāo)