摘要:布爾值在編程中,和是經常出現的兩個值。對布爾值可以執行與或及非或叫取反操作。假如和是布爾值只有在和都為真的情況下為真。如果想用十六進制表示整數,在數值前面加上采用十六進制記號不能表示分數,也不能使用科學計數法。
3.1 數據類型
JavaScript實際上有6種數據類型;
布爾值,只有true和false兩個值
數值,比如 81 和 4.21
文本,JavaScript里稱之為字符串
特殊值undefined
特殊值null
對象
要了解一種數據類型,不僅要看它包含什么值,還要知道能對這種數據類型執行什么操作。比如,對數值可以執行四則運算,取模求冪等,對字符串可以執行去空格、切分、反序和大寫首字符操作。本章將介紹JavaScript的所有數據類型,以及與這些類型相關的各種操作。3.2 布爾值
在編程中,true和false是經常出現的兩個值。
var open = true var ready = false var gameOver = false var friendy = true var enabled = true
這兩個值有時候也會以比較結果的形式出現。所謂比較,就是計算一個值是等于===、不等于!==、小于<、小于等于<=、大于>,還是大于等于>=另一個值。
alert(137===5); // false alert(8!==3.0); // true alert(2<=2); // true var x = 16 > 8; alert(x); // true
這些值叫做布爾值。對布爾值可以執行&&(與)、||(或)及!(非或叫取反)操作。假如x和y是布爾值:
x && y 只有在x和y都為真的情況下為真。即真真為真,短路:因比較運算為左結合運算,若x為假,&&后面表達式不執行
x || y y或x有一個為真的情況下即為真。即一真為真,短路:若x為真,則短路跳出,||后面表達式不執行
!x 只有在x非真情況下為真
代碼補充:
console.log(4 < 5 && 15 === 6); // false console.log(1 === 2 || 15 > -5); // true console.log(!(3 <= 10)); // false console.log(true && 3+2) // result:5 第一個表達式為真,則對第二表達式計算 console.log(false && 3+2) // result:false 第一個表達式為假,則短路跳出,不計算第二表達式 console.log(false || 5+5) // result:10 第一個表達式為假,繼續檢查,執行第二表達式 console.log(true || 5+5) // result:true 第一個表達式為真,短路跳出,不計算第二表達式小練習
!(true && !false && true) || false // false false || true && false // false
證實或證否:如果x和y保存的都是布爾值,那么!(x && y) 一定等于 (!x == !y)
第三題,可畫圖,排列組合出所有可能便可證為實,總之&&:一旦有假則為假,||:一旦有真則為真
接下來介紹數值類型。在JavaScript中,數值就跟你想象一樣,該怎么寫就怎么寫:1729、3.141592或者299792458。如果兩個數值之間有一個E(或e),那么整個數就等于前面那個數乘以10后面那個數次冪(就是科學計數法- -)
3.3.1 數值運算適用于數值的操作符包括+、-、*、/和%(求余也叫取模)。
針對數值可以執行的其他運算還有
Math.floor(x) 取得小于等于x的最大正整數
Math.ceil(x) 取得大于等于x的最小整數
Math.sqrt(x) 對x開方
Math.random(x) 得到一個大于等于0,小于1的數
Math.pow(x,y) 得到的是x的y次方
Math.floor(2.99); // 2 Math.floor(-2.99); // -3 Math.ceil(3.99); // 4 Math.ceil(-3.99); // -3 Math.sqrt(100); // 10 Math.pow(2,4); // 16 Math.random(); // x大于等于0,小于103.3.2 大小和精度限制
JavaScript的數值與大多數編程語言的數值一樣,不同于我們日常所見的理想化數值。首先,它們收到計算設備固定大小的物理元件的限制。因此,存在一個最大的數值(在JavaScript里這個值約為1.79e308)和一個最小的數值(-1.79e108)。任何計算得到超過最大數值或者小于最小數值,都會轉化為特殊值Infinity或者-Infinity。數值除了存在大小的限制,還存在精度限制,計算得到無法精確表達的數值時,會轉換成最接近的可表示的數值。
console.log(12157692622039623539); // 12157692622039624000 console.log(12157692622039623539+1); // 12157692622039623539 console.log(1e200 === 1e200+1); // true console.log(4.18e-1000); // 0 console.log(0.1+0.2); // 0.30000000000000004 console.log(0.3 == 0.1+0.2) // false
很多腳本不會涉及這類似近似性問題,有的即便涉及也可以容忍。但在某些情況下,精度達不到要求真的會導致問題(比如金融方面的數值)。因此,我們應該對什么情況下可能出現精度不夠的問題有個心里預期。如以下幾點,
可表示的數值密集度集中在0左右,事實上有一多半都介于1和-1之間;離0越遠,就越稀疏。
所有介于正負9e15之間的數都可以精確表示,在這個范圍之外,只有部分整數可以表示。
涉及非常大的數值、非常小的數值或者非整數的計算,經常會導致不準確的結果。
如果需要用到最大可表示的值,可以調用表達式Number.MAX_VALUE。最小:-Number.MIX_VALUE保存著大于0的最小可表示值,即-2e1074 3.3.3 NaNNaN這個特殊值代表的是“Not a Number”,他會在數學計算得到了非數學意義上的結果時出現:
console.log(0/0); console.log(Infinity*Infinity); console.log(Infinity-Infinity); console.log(NaN+16); console.log(NaN === NaN); // false
NaN不等于任何值,也不等于NaN
檢測一個值是否為數值,可用 isNaN() 方法。
console.log(0/0 === NaN); // false console.log(isNaN(0/0)); // NaN console.log(isNaN(2.398472398)); // false console.log(isNaN(NaN)); // true console.log(isNaN(Infinity)); // false3.3.4 十六進制數值
JavaScript中的非負數也可以用十六進制記號表示。十六進制數值的計數規則是:0、1、2、3、4、5、6、7、8、9、A、B、C、D、F、10、11、12、......、19、1A、1B、......、1F...。如果想用十六進制表示整數,在數值前面加上0x:
alert(0x9) // 9 alert(0x9FA) // 2554 alert(-0xCafe) // -51966 alert(0xbad) // 2989
采用十六進制記號不能表示分數,也不能使用科學計數法。
某些版本的JavaScript實現把以0開頭的整數當做八進制數值:0、1、2、3、...、7、10、11、...、17、20、21、...。
如下:
alert(07) // 7 alert(011) // 9 alert(-02773) // -15313.4 文本 3.4.1 字符、符號與字符集
字符就是有名字的符號,比如:
加號
斯拉夫文字小型字母TSE
黑色的象棋騎士
梵文字母OM
MUSICAL SYMBOL DERMATA BELOW
不要混淆字符和符號,符號是字符的表現形式。比如,符號:K
拉丁字母大寫:K
希臘大寫字母:K(KAPPA)
梵文大寫字母:K(KA)
類似的,符號:Σ
希臘大寫字母:Σ(SIGMA)
求和號
符號:φ
帶斜線的拉丁大寫字母:O
直徑
空集
字符集由一組特定的字符組成,其中每個字符都有唯一的編號,叫碼點(codepoint)。與大多數語言一樣,JavaScript使用unicode字符集。unicode字符集一般用十六進制為每個字符編碼。
要了解全部碼點,可訪問Unicode碼點
為什么要知道碼點,因為在JavaScript中可以通過他們輸出鍵盤上沒有的字符。比如,下面的碼點可以輸出字符串"Привет"
"u041fu0440u0438u0432u0435u0442"
每個字符以u開頭,后跟代表該字符碼點的四位十六進制數字。此外,也可以用x開頭跟兩位十六進制數字表示字符。比如,字符串"o1é"可以有以下兩種表示法:
"o1xc9"
"o1u00c9"
有些字符不會顯式出來,所以必須用使用碼點表示法。比如"從左到右標記"(u200e)、"從右到左標記"(u200f)和"零寬度非中斷空白"(ufeff)"。其中,前兩個字符會出現在混合了從左到右閱讀的文字(英語,西班牙語)與從右到左(希伯來和阿拉伯語)閱讀的文字的文檔中。
轉義序列:
如:
" 單引號
" 雙引號
xhh hh是兩位十六進制值,相應字符的碼點
uhhhh hhhh是四位十六進制值,也是相應字符碼點
、 、、f、 、v 換行符、制表符、退格符、進紙符、回車符、制表符
反斜杠本身
反斜杠不僅用于通過碼點來表示字符,而且也用于與后續字符組織成所謂的轉義序列。
換行符n導致后面的字符出現在下一行,t制表符表示按列對齊文本。如:
alert("1. f3 e5 2. g4 u265bh4++")
u加碼點的方式只在JavaScript代碼中有效。如果想在HTML文檔顯示字符,則需要在碼點兩側分別加上和分號;
字符 JavaScript表示法 HTML表示法 黑旗皇后 u265b ♛ 骰子1 u2680 ⚀ 骰子2 u2681 ⚁ 藏文 u0f5c ཛྷ
一個擲骰子的程序,隨機生成0~6中一個數。因為骰子六面的字符在Unicode中的碼點為2680~2685。 由于程序非常短,所以才把程序嵌入到了HTML文檔中。如果代碼比較長,請把它們轉移到多帶帶的文件中。樣式規則也一樣,因為這里只有一條規則,我們才把它放到了文檔頭部。大型頁面中,所有樣式規則也應該保存在一個多帶帶的文件匯總。這樣,文檔的結構、樣式、行為才能各安其位,相互分離。在軟件工程中,關注點分離是一個非常重要的思想。 3.4.2 字符串操作
JavaScript支持很多種字符串操作,比如查詢字符串長度(即字符數)、字母的大小寫轉換以及替換字符串中某一部分,等等。
console.log("Hello, there".length); // 12 console.log("Hello,there".toLowerCase()); // hello,there console.log("Hello,there".toUpperCase()); // HELLO,THERE console.log("Hello,there".replace("ello","i")); // Hi,there
Sometimes,你可能想知道某個字符在字符串的哪個位置,或者某個位置上是哪個字符。JavaScript字符串的第一索引為0,第二個字符的索引為1,第三個為2,以此類推。要知道字符串s中位置為p的字符,可以使用表達s.charAt(p)。要定位字符串中文本的位置,可以使用indexOf和lastIndexOf。表達式s.substring(x,y)會得到字符串s中,從位置x開始直到(但不包含)位置y的所有字符。
"Some text".charAt(2) // "m" var str = "Some text"; str[str.length-1]; // "t" 可獲取任意字符串最后一個字符(包含空格) "Some text".indexOf("me") // 2 返回某個指定的字符串值在字符串中首次出現的位置 "Some text".lastIndexOf("e") // 6 返回一個指定的字符串值最后出現的位置,從后向前搜索 alert("Some text".substring(3,0)) // "e te" 返回上標(包括)至下標(不包括)之間的字符
操作符+用于拼接兩個字符串....略
String 對象的方法 slice()、substring() 和 substr() (不建議使用)都可返回字符串的指定部分。slice() 比 substring() 要靈活一些,因為它允許使用負數作為參數。slice() 與 substr() 有所不同,因為它用兩個字符的位置來指定子串,而 substr() 則用字符位置和長度來指定子串。 substr(start,length)必需。一個非負的整數,規定要提取的子串的第一個字符在 stringObject 中的位置
可選。子串中的字符數。必須是數值。如果省略了該參數,那么返回從 stringObject 的開始位置到結尾的字串
var str = "Hello World"; console.log(str.substr(-3,5)) // "rld" 倒數第3個字符開始的5個字符 console.log(str.substr(1,-1)) // "" length參數必須為正整數 console.log(str.substr(1,4)) // "ello" 正數第2個字符開始的4個字符 console.log(str.substr(2)) // "llo World" 正數第2個字符開始到結尾所有字符
Test中,參數start可為負整數,與W3C描述不同,待驗證
slice(start,end)要抽取的片斷的起始下標。如果是負數,則該參數規定的是從字符串的尾部開始算起的位置。也就是說,-1 指字符串的最后一個字符,-2 指倒數第二個字符,以此類推
緊接著要抽取的片段的結尾的下標。若未指定此參數,則要提取的子串包括 start 到原字符串結尾的字符串。如果該參數是負數,那么它規定的是從字符串的尾部開始算起的位置
var str = "Hello World"; console.log(str.slice(1,4)) // "ell" 第2個字符,到第5個字符的前一個字符,參數end本身并不包含 console.log(str.slice(-5,-2)) // "Wor" 倒數第5個字符,到倒數第二個字符前一個字符,和正數同理 console.log(str.slice(3)) // "lo World" 不指定參數end,提取到結尾字符串 console.log(str.slice(-(str.length-1))) // "ello World" 倒數也同上substring(start,stop)
必需。一個非負的整數,規定要提取的子串的第一個字符在 stringObject 中的位置
可選。一個非負的整數,比要提取的子串的最后一個字符在 stringObject 中的位置多 1。如果省略該參數,那么返回的子串會一直到字符串的結尾
var str = "Hello World"; console.log(str.substring(2,7)); // "llo W" 從索引為2到索引為7之間的字符(不包括索引7的字母) console.log(str.substring(-3,2)); // "He" start參數不識別負數,從頭部開始選擇 console.log(str.substring(3)) // "lo World" 索引為3的字符后所有字符,因為未指定stop參數 console.log(str.substring(4,-2)) // "Hell" 選擇從頭部首字符至索引為4的字符前一個字符,stop參數不能識別負數3.5 undefined與null
一般來說,我們都希望通過編程得到一些實際效果,比如某個東西的成本多少(數值),游戲中某個玩家是否處于活動狀態(布爾值)或者你輔導員的名字(字符串)。不過,在某些情況下,我們也需要知道某個數據不存在,或者某個數據不可靠。就以輔導員為例,有幾個問題來表示:
我有個輔導員,她名叫Alice
我壓根就沒有輔導員
我可能有也可能沒有輔導員,我真的不知道
我不知道自己有沒有輔導員,不過我不介意讓別人知道這件事
JavaScript為表示第二種情況提供了null,為第三種情況提供了undefined。
var supervisor = "Alice"; // 輔導員是Alice var chief = null; // 肯定沒有輔導員 var assistant = undefined; // 可能有助理3.6 對象 3.6.1 對象基礎
在JavaScript中,所有不是布爾值、數值、字符串、null和undefined的值,都是對象。對象有屬性,屬性有值。屬性名可以是字符串(位于引號內),也可是非負整數(0、1、2...)。屬性值也可以是對象,可以定義復雜的數據結構。對象字面量是一種定義的表達式,如:
var dress = { size:4, color:"green", brand:"DKNY", price:834.95 }; var Location = { latitude:31.131013, longitude:29.976977 }; var part = { "serial number":"367DRT2219873X-785-11P", description:"air intake manifold", "unitr cost":29.95 }; var p = { name:{first:"Sean",last:"O" Brien"}, country:"Ireland", birth:{year:1981,month:2,day:17}, kidNames:{1:"Ciara",2:"Bearach",3:"Mairead",4:"Aisling"} };
定義對象之后,可以使用點或方括號讀取屬性的值。
p.country; // "Ireland" p["country"]; // 方括號內屬性名必須加引號 p:birth.year; // 1981 p.birth["year"]; // 1981 p["birth"].year; // 1981 p["birth"]["year"]; // 1981 p.kidNames[4]; // "Aisling" p["kidNames"][3] // "Aisling"
用點號訪問屬性的方式雖然簡潔,卻不能用于讀取以整數命名的屬性(比如不能用"a.1"),在ES3中也不能讀取以JavaScript保留字命名的屬性。這時候,就要使用方括號表示法(a[10]、a["var"])。方括號表示法還適用于包含空格及其他非字母的屬性(part["serial number"]),對象屬性并非一成不變,可以隨時給對象添加或刪除屬性,如:
var dog = {}; // 將一個對象引用賦值給變量 dog.name = "Karl"; // 添加屬性1 dog.breed = "Rottweiler"; // 添加屬性2 console.log(delete dog.name); // 刪除屬性2,返回true console.log(dog.name); // undefined
在使用JavaScript開發Web應用,構成網頁的元素就是帶有屬性的對象。下面這個小程序演示這一點,它通過每2秒隨機變換一次笑臉的位置在實現笑臉在瀏覽器中的跳躍。
JavaScript Temperature Converter ☺
這里的笑臉就是字符U+263a,嵌在了ID為face的div的元素中。作為對象,這個元素有一個style屬性,而這個屬性本身也是一個對象,又有
position、left和top等屬性。這段腳本通過setinterval每2000毫秒執行一次move函數。樣式屬性left和top的值都是字符串,有幾種格式,其中一種就是288px這樣的屬性值,表示相對于窗口的偏移量。這個腳本每次運行move函數都會重新設定樣式的值。JavaScript檢測到樣式變化就會刷新瀏覽器窗口。除非你關閉瀏覽器窗口或者打開了其他網頁,否則這個程序會一直運行。
什么情況下必須使用方括號表訪問對象的屬性?
使用了不能作為標識符的屬性名的情況
將變量的值作為屬性名使用的情況
將表達式的求值結果作為屬性名使用的情況
如下代碼會輸出什么,為什么?
var pet = { name:"Oreo", type:"Rat" }; alert(pet[name]);
Answer:方括號內的值是屬性名的字符串,缺少引號,將搜索name變量,但是并不存在此變量及相應的值,所以將彈出undefined
3.6.2 理解對象引用對象與其他五種值(數值、字符串、布爾值、null、undefined)是不同的,其他五種值統稱基本類型值,對象與他們的區別主要表現在兩方面。雖然說起來有點嚴肅,但明白這兩點區別對于正確高效地使用對象至關重要,必須牢記。第一點:
對象表達式的值并非對象本身,而是一個指向對象的引用。如圖示,基本類型值直接存儲在變量中,而對象不是。對象的值中存儲的是指向對象的引用(變量b)。
由于對象的值其實是引用,所以把一個對象賦值給一個變量,實際上會產生該對象引用的一個副本,而不會賦值對象本身。換句話說,對象賦值不會產生新對象。想想看,對象的賦值與基本類型值賦值過程并沒有不同。變量間的賦值就是把保存一個盒子里的東西賦值一份再保存到另一個盒子中,而該盒子中存儲的可能是數值,也可能是一個引用。下圖表示基本類型賦值和對象賦值,可以想一想。
對象與其他類型值的第二個重要的區別是:
對同一個對象字面量的每次求值,都會產生一個新對象。
如上:腳本聲明了三個變量,創建了兩個對象。雖然兩個對象擁有相同的屬性,每個屬性的值也相同,但它們卻是兩個不同的對象,因此這個腳本會創建兩個對象。
關于變量只保存對象的引用而非對象這一點,不僅在賦值的時候有所體現,在等同性測試的時候也會有所體現。這兩種情況下,我們都必須搞明
白。對于測試表達式x===y,我們想知道x和y中等值是否相同。
var a = {x:1,y:2}; // 聲明對象字面量1 var b = a; // 將變量a引用對象的引用賦值給變量b var c = {x:1,y:2}; // 聲明對象字面量2 alert(a===b); // true alert(a===c); // false // 1. 即使兩個對象的內部結構相同,但是比較結果:false // 2. 相等運算,比較的是引用的對象是否來自同一個對象,a、b變量引用同一個對象,全等運算為:true // 3. 值得一提的是,a,b變量操作過程中,并沒有產生新對象 // 再次強調!對象相等運算比較的是,引用對象來源是否是同一個對象
如下,一個對象可以同時被多個變量引用,因此通過其中任何一個變量都可以修改對象的屬性,也都可以查看修改后的結果。
小練習:對表達式{x:1,y:2}=== {x:1,y:2}求值,解釋結果。
false:使用{}大括號就已經聲明了對象字面量,本質上和上面的變量a,c引用的對象是相同的,所過結果為假。
3.6.3 對象原型每個JavaScript對象都有一個暗藏的鏈接指向自己的原型對象(prototype),如果你讀取的的屬性不在對象本身上,那么JavaScript就會進一步查詢這個對象的原型對象。如果在這個原型對象上也沒找到,還會進一步查詢原型對象的原型對象,以此類推。這個原型鏈最后一個對象的暗藏鏈接,應該指向null值。如果整個原型鏈都沒有你想讀取的屬性,那么你會看到一個錯誤。
實際上,這里基于原型創建c1對象使用的是Object.create()。這是ES5定義的操作,在老版本JavaScript引擎中,還有一種基于原型創建對象愛的技術,后面會繼續討論。
在需要定義大量相似對象時,原型是非常有用的。下圖又基于一個原型創建了兩個新對象。其中一個完全沒有自己的屬性,因而它的屬性完全繼承原型對象。
小練習:
說說什么是自有屬性,什么是繼承屬性。
字面意思先簡單理解,自有屬性在自身,直接訪問,不需通過原型鏈。繼承屬性繼承自原型,通過_proto_向上查詢如果運行protoCircle.radius = 5,那么訪問c1.radius和c2.radius結果發生什么?
c1.radius = 5,c2.radius = 15,原型的屬性改變,則凡是繼承它屬性的都會受到影響。c1,c2對象均繼承自原型,但是c2存在自有屬性,并未查詢原型,所以讀取的是自有屬性。 3.6.4 自引用對象對象的屬性可以引用自身,兩個對象也可以通過屬性相互作用。但這種情況下,光靠對象字面量無法描述了。
于是先使用對象字面量創建對象的部分屬性,然后在通過賦值方式定義其他屬性。當然也可以為彼此賦值。
3.7 數組數組是一種特殊的對象,它的屬性是從0開始的連續非負整數,而且有一個名為length的對應屬性。之所以說數組特殊,主要是因為不能使用常規的對象字面量來創建它,必須使用另一種專用語法:
var a = []; var b =[8,false,[[null,9]]]; var numbers = [ "zero", "one", "two", "three", "four", "five", "six" ];
這種專用語法實際上是用來創建屬性0,1,2...,還有length的。當然,length屬性也很特殊:為它賦值可以擴大或縮小數組,那么新增屬性會被設定為undefined。另外,在超過數組長度的某個位置上賦值也可以擴大數組。
var a = [9,3,2,1,3]; // a[0]值為9,a.length等于5 a[20] = 6; // a[5]到a[19]的值都是undefined,a[20]說明有20 + a[0]個值,length:21 alert(a.length); // 21 a.length = 50; // a[21]到a[49]的值都是undefined a.length = 3; // a現在是[9,3,2]
基于某個分隔符拆分(split)字符串、切割(slice)現有數組都可以創建新數組,另外把兩個數組拼接(concat)起來也可以創建新數組。反之,把數組元素連接(join)起來可以創建一個由同一個分隔符分隔的字符串:
var s = "A red boat"; var a = s.split(" "); // a是["A","red","boat"] var b = [9,3,2,1,3,7]; var c = b.slice(2,5); // c是[2,1,3] var d = c.concat(a); // d是[2,1,3,"A","red","boat"] console.log(d.join("|")) // "2|1|3|A|red|blat"
注意,使用slice切割數組b中從位置2到位置5的元素,返回數組是[ b[2],b[3],b[4] ]。換句話說,切割得到的數組包含位于切割起點的元素,不包含位于切割終點的元素;和substring截取字符串的操作相同。a.slice(x,y),則返回a[x]和a[y-1]構成的數組。還有另外兩種slice操作:
var a = [9,4,1,7,8]; var b = a.slice(2); // a[2]開始到最后 var c = a.slice(); // 所有索引,得到a的副本
拆分字符串的split操作不會修改原字符串、切割(slice)、拼接(concat)和連接(join)數組元素也不會修改原數組。不過。確實有一些操作會修改數組對象本身。比如,可以使用push在數組末尾、使用unshift在數組開頭添加元素;反之,可以使用pop在數組末尾、使用shift在數組開頭刪除元素。另外,還可使用reverse反轉數組元素的順序,使用sort對數組元素進行排序。這些會修改數組本身的操作為可變操作(mutator)。
var a = []; // a是長度(length)為0的數組 var b = [3,5]; // length:2 b.push(2); // [3,5,2] b.unshift(7); // [7,3,5,2] a.push(3,10,5); // [3,10,5] a.reverse(); // [5,10,3] a.pop(); // [5,10] a.shift(); // [10] b.push(a[0],1); // [7,3,5,2,10,1] b.sort(); // [1,10,2,3,5,7] b.reverse(); // [7,5,3,2,10,1]
JavaScript默認是將所有的數組元素都當成字符串來排序的,就算數組中包含數值、布爾值、對象或別的數據也一樣。既然是按字符串排序,那排序標準就是字母表,因此字符串"1"小于"10",后者有小于"2"(就如同"foot"小于"football",后者又小于"goal")。實際上也可以按照數值進行排序,具體后面章節會介紹。
把數組放到對象字面量中,或者反之,可以創造出任何復雜的數組結構:
var song = { title:"In My Head", track_number:10, album:"Rock Steady", artist:"No Doubt", authors:["Gwen Stefani","Tony Kannal","Tom Dumont"], duration:205 }; var triangle = [{x:0,y:0},{x:3,y:-6},{x:-4,y:-1.5}];
實踐中,我們會使用對象(多帶帶)描述一種具體的事物,如裙子、人、歌曲和坐標點等等,會用數組描述一組事物,如一張專輯中的歌曲或一個多邊形的頂點。數組也不是構造數據集合的唯一方式。
小練習:把變量song和triangle用圖表示出來,包括引用的對象。(PS大法...這書實在啊,教JS順便復習PS基礎操作:)
請把變量a引用的數組在執行下列操作之后的結果用圖示形式畫出來:
var a = [1,2,3,4];a.unshift(a.pop());
答:圖就免了,pop();會刪除數組末尾元素并返回,之后被unshift()接收,添加至數組頭部,需要注意的是,由于數組長度不變,刪除末尾元素后,只是a[3]的值變為undefined,所以最后a數組內元素是:[4,1,2,3,undefined]
3.8 類型轉換 3.8.1 弱類型目前,接觸到的從操作符,如:
布爾值 && 布爾值 布爾值 || 布爾值 !布爾值 -數值 數值+,-,*,/,%數值 Math.sqrt(ceil,floor,PI,pow,random...)(數值) 字符串+字符串 字符串.toUpperCase() 字符串.indexOf(數值) 對象[字符串] ...
如果讓操作符搭配一個或多個"錯誤的"的類型會怎么樣?
這里是數值:
7 * false // 0 7 * true // 7 7 * "5" // 35 7 * " " // 0 7 * "dog" // NaN 7 * null // 0 7 * undefined // NaN 7 * {x:1} // NaN
這里是布爾值:
!5 // false !0 // true !"dog" // false !"" // true !" " // false !null // true !undefined // true !{x:1} // false
這里是字符串:
"xyz"+false // "xyzfalse" "xyz"+true // "xyztrue" "xyz"+7 // "xyz7" "xyz"+null // "xyznull" "xyz"+undefined // "xyzundefined" "xyz"+{x:1} // xyz[object Object] "xyz"+[1,2,3] // xyz1,2,3
通過以上實驗,可以看出操作符搭配錯誤的類型,不僅不會報錯,還會正常顯示。通過類型轉換以有意義的方式處理了錯誤類型的值。
轉換為數值:false被轉換為0,true被轉換為1,字符串為轉換成可能的值,null被轉換成0;如果無法把字符轉換成數值,則轉換成NaN。對象x會調用x.valueOf();
轉換為布爾值:0、空字符串("")、null、undefined、NaN。其他值都被轉換成true。false一般稱為假值,true則為真值;
轉換為字符串:JavaScript會按常理處理,如例子所示。只是對象x會調用x.toString(),具體后面會討論。
關于valueOf和toString的詳細解釋,&&與||其實他們并不是真的需要比較布爾值,后續繼續討論。
由于存在隱式數據類型轉換,JavaScript被稱為弱類型編程語言。在強類型編程語言中,由錯誤類型值構成的表達式會導致錯誤。如果腳本里含有這種"病句",要么不會被允許執行,要么干脆直接停止工作,要么會在問題表達式被求值時拋出異常。
有時候,這種自動類型轉換會造成一些意外。比如isNaN有時會產生一些難以理解的行為,我們知道它的作用是判斷某個值是不是非數值(Not a Number)。一般來說,我們會覺得布爾值、字符串、null會被判定為非數值,但實驗表明并非如此。
isNaN(true); // false,因為true轉換成了1 isNaN(null); // false,因為null轉換成了0 isNaN("water"); // true,很明顯 isNaN("100"); // false,因為"100"轉換成了100
看來,應該把isNaN的作用解讀為"不能轉換成數值"。再比如數值與字符串間的轉換,也是不可避免會碰到的:
var x = prompt("Enter a number"); var y = prompt("Enter another number"); alert(x+y); // 結果是拼接后的字符串,而非數學意義上的加法
每次提示都輸入2,結果是22,因為對prompt求值的結果總是字符串,而+操作符又同時適用于數值和字符串。如果提示框顯示x-y,執行的那就是數值減法。因為-在JavaScript只能用于數值,所以得到的字符串都會先被轉換成數值。當然,乘法和除法也是"安全的"。但不管怎樣,在數值和字符串相遇的時候,你總得自己多加小心才是。
3.8.2 顯式轉換鑒于字符串與數值間的轉換容易出問題,很多JavaScript程序員傾向于在代碼中顯式地實現字符串到數值的轉換。
如:
"3.14"-0; // 3.14 "3.14"*1; // 3.14 ("3.14"/1); // 3.14 +"3.14"; // 3.14 [速度最快] Number("3.14"); // 3.14 [清除,速度最慢] parseFloat("3.14"); // 3.14
前三個表達式使用了-、*、/,作為數值操作符,它們會在執行計算(在這里都是無效計算)之前把字符串轉換成數值。第四個表達式也使用了一個數值操作符,叫做一元加。把它放到數值前面,不會產生任何操作,而與之對應的一元減操作符就不一樣了。
+4 // 4 [一元加] -4 // -4 [一元減]
由于一元加需要一個數值參與計算,因此如果它后面是一個字符串,JavaScript就會把這個字符串轉換成數值。使用+把字符串轉換成數值的做法顯得有點神秘,但這種技術很方便,而且也并不少見。類似這種的編程方法被稱為:習語,對外人并不顯見,必須習而得之。
var x = +prompt("Enter a nunber"); var y = +prompt("Enter another nunber"); alert(x+y); // 算術加法
那么Number(s)和parseFloat(s)中s如果是字符串,結果又會怎么樣?
var x = Number(prompt("Enter....number")); var y = Number(prompt("Enter another...ber")); alert(x+y); // 算術加法
不過,很多程序員并不使用這種方式,因為效率低:JavaScript引擎在運行以上代碼時會額外多做一些工作,導致腳本執行速度降低,內存占用增多。究其原因,就是Number生成的并非基本類型值,而是一個包裝著數值的對象,這個對象在被當成數值使用時會把數值拿出來。對象比基本類型值更讓JavaScript引擎費勁,一方面創建對象需要分配空間,而在不需要對象時,還要銷毀對象。然而,有時候可讀性確實比效率更重要,也可以使用Number。
parseFloat(string);還可以使用parseFloat及parseInt顯式把字符串轉換成數值。轉換從字符串開頭開始,但不一定轉換整個字符串,而且首尾的空格會被忽略。
console.log(parseFloat("23.9")); // 23.9 console.log(parseFloat("5.663E2")); // 566.3 console.log(parseFloat(" 8.11 ")); // 8.11 console.log(parseFloat("52.3xyz")); // 52.3 console.log(parseFloat("xyz52.3")); // NaN console.log(parseFloat("3 .5 .6")); // 3 console.log(parseFloat("123456 454")); // 123456 // 首尾空格忽略 // 除了+、-、數字、小數點、科學計數法(E或e)這些符號,其他的字符本身以及后面的所有字符都會被忽略 // 如果參數字符串第一個字符串不能被解析為數字,會直接返回NaN
parseFloat 是全局函數,不屬于任何對象。 parseFloat 將它的字符串參數解析成為浮點數并返回。如果在解析過程中遇到了正負號(+ 或 -)、數字 (0-9)、小數點,或者科學記數法中的指數(e 或 E)以外的字符,則它會忽略該字符以及之后的所有字符,返回當前已經解析到的浮點數。同時參數字符串首位的空白符會被忽略。 如果參數字符串的第一個字符不能被解析成為數字,則 parseFloat 返回 NaN。提示:您可以通過調用 isNaN 函數來判斷 parseFloat 的返回結果是否是 NaN。如果讓 NaN 作為了任意數學運算的操作數,則運算結果必定也是 NaN。parseInt(string, radix);
parseInt得到的數值沒有小數部分,其實parseInt中的Int就是integer,整數的意思。數值中含有小數的叫浮點數(Why?)
console.log(parseInt("23.9")); // 23 console.log(parseInt("5.663E2")); // 5 console.log(parseInt(" 8.11 ")); // 5 console.log(parseInt("52.3xyz")); // 52 console.log(parseInt("xyz52.3")); // NaN
使用parseInt可以轉換基數為2到36的任何數值,進制轉換。
console.log(parseInt("75EF2",16)); // 483058 console.log(parseInt("50",8)); // 40 console.log(parseInt("110101",2)); // 53 console.log(parseInt("hello",30)); // 14167554 console.log(parseInt("36",2)); // NaN
當參數 radix 的值為 0,或沒有設置該參數時,parseInt() 會根據 string 來判斷數字的基數(前提)。 舉例,如果 string 以 "0x" 開頭,parseInt() 會把 string 的其余部分解析為十六進制的整數。如果 string 以 0 開頭,那么 ECMAScript v3 允許 > parseInt() 的一個實現把其后的字符解析為八進制或十六進制的數字。如果 string 以 1 ~ 9 的數字開頭,parseInt() 將把它解析為十進制的整數。3.8.3 松散相等操作符
因為JavaScript是弱類型的,所以在執行+-*/<等計算時,要確保數據的類型匹配,就算是相等操作符,也會發生同樣的類型轉換。
console.log(false === 0) // false 嚴格相等比較(類型不轉換) console.log(false == 0) // true 相等比較(類型轉換)
JavaScript提供兩種相等測試機制,一種會執行隱式類型轉換,一種不會。
相等操作符===當且僅當兩個表達式的值相同,類型相同時才會返回true(除了null)。而!==的結果自然與===截然相反。這兩種相等操作符叫做嚴格相等操作符。
另一種測試機制==和!=被人喻為嚴格操作符的"邪惡表親"。==在測試之前會不顧一切地轉換表達式類型,因此盡量不要使用它。
不過,==的轉換是有意義的,只是要記住比難。JavaScript官方規范對此有詳細描述,但我們這里可以簡短歸納。
要確定x == y的結果,JavaScript會嘗試對它們進行類型轉換,以便比較。
如果x和y中有一個字符串,有一個數值,JavaScript會把字符串轉換成數值。
如果一個是布爾值,另一個不同,JavaScript會把布爾值轉換成數值。
如果是一個對象,另一個是字符串是或數值,JavaScript會把對象轉換成字符串或者數值。
最后,undefined == null、null == undefined。待尋找原因。
由于上述情況復雜,一般更傾向于使用嚴格相等操作符===和!==。雖然松散相等操作符==和!==可以像前面討論的那樣在代碼提供一些快捷操作,即自動幫我們實現字符串到數值的轉換,但轉換結果很多情況下無法預見,規則很難牢記。
使用===和!==,盡量不使用==和!=。3.9 typeof操作符
有時候,你可能必須某個值的類型。JavaScript有一個古怪的typeof操作符,能夠返回關于表達式類型的字符串描述。說它古怪,是因為它的返回值有時候可信,有時候又不可信。
typeof 101.3; // number typeof false; // boolean typeof "dog"; // string typeof {x:1,y:2}; // object typeof undefined; // undefined typeof null; // object typeof [1,2,3]; // object typeof alert; // function typeof (typeof 1); // string
null的類型沒有里有是object。數組的類型返回object倒可以理解,畢竟數組是對象。可為什么函數的類型又不是了呢?函數也是一種對象啊。
小練習:
測試typeof Infinity和typeof NaN
console.log(typeof Infinity); // number console.log(typeof NaN); // number
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82608.html
摘要:如在上列中結果實際上是給定數字的字符串形式無效語法有效語法在上列中結果是因為第一個被視為的一部分,第二個是屬性訪問運算符。用于檢查傳入的對象是否是傳入對象的原型第章將討論原型。返回對象的字符串表示。 只挑本人重要的寫(有夾雜其他補充) 3.1 語法 注釋 單行注釋以兩個斜杠開頭,如下所示: // 單行注釋 塊級注釋以一個斜杠和一個星號( /* )開頭, 以一個星號和...
摘要:設計模式是以面向對象編程為基礎的,的面向對象編程和傳統的的面向對象編程有些差別,這讓我一開始接觸的時候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續了解設計模式必須要先搞懂面向對象編程,否則只會讓你自己更痛苦。 JavaScript 中的構造函數 學習總結。知識只有分享才有存在的意義。 是時候替換你的 for 循環大法了~ 《小分享》JavaScript中數組的那些迭代方法~ ...
摘要:如果參數不在與之間,該方法將返回一個空字符串這個不解釋了方法用于在字符串中用一些字符替換另一些字符,或替換一個與正則表達式匹配的子串。 主要總結 JavaScript的六種數據類型:Boolean、Number、String、Null、Undefined、Object 布爾類型 布爾真假判定:短路原則 x && y 只有在x和y都為真的情況下為真。即真真為真,短路:因比較運算為左...
摘要:操作符,會將數值改變正數變成負數負數變成正數。同時,也說明了,使用兩個邏輯非操作符和的操作結果相同。操作符得到的是余數。不相等操作符有兩種。 這篇筆記的內容對應的是《JavaScript高級程序設計(第三版)》中的第三章。 1.操作符 1-1 一元操作符 遞增和遞減操作符 遞增和遞減操作符有兩個 ++ 和 --。一元操作符使用的時候,可以前置也可以后置。由于兩個操作方式類似,先只說明 ...
摘要:在本例中,使用屬性指定鏈接的目標,其中表示超文本鏈接。您應該認為和元數據隱式出現在示例中,即使它們沒有實際顯示在文本中。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:JavaScript and the Browser 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2 版)》 ...
閱讀 1041·2019-08-30 12:57
閱讀 2114·2019-08-30 11:11
閱讀 2177·2019-08-29 15:20
閱讀 1870·2019-08-29 14:12
閱讀 3274·2019-08-28 17:51
閱讀 2378·2019-08-26 13:23
閱讀 789·2019-08-26 10:34
閱讀 3844·2019-08-23 12:37